Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Отключить привязку к событиям в рантайм


Автор: 17dufa 30.9.2009, 13:24
Добрый день.
Имеется у меня дочерняя форма, а на ней куча полей, которые заполняются пользователем. Формочка по KILLFOCUS проверяет корректность заполнения, если заполнено с ошибкой - мессаджбокс и возврат фокуса в окно. Проблема вылезает если ввести что-нить неправильное и попытаться закрыть формочку. Формочка закрывается и начинают сыпаться мессаджбоксы об ошибке ввода, после штук 3-5 сообщений приложение закрывается целиком. Соответственно есть мысля: по закрытию формочки отрубить обработку KILLFOCUS'ов. Как это сделать в рантайме?

Автор: SenkraD 30.9.2009, 13:44
17dufa,  ну можно поймать WM_CLOSE и выставить там какой-то флаг,
а в обработчике WM_KILLFOCUS проверять флаг и далее работать по результатам
проверки

Автор: 17dufa 30.9.2009, 13:55
SenkraD, этих самых обработчиков WM_KILLFOCUS до чертиков. в каждом из них плодить:
Код

if (m_Closing)
   return;

как-то некрасиво. проще в WM_CLOSE отрубить все эти обработчики.

Автор: Earnest 30.9.2009, 16:03
Если все-таки хочешь обрубить обработчики, то можно сделать так: перекрsть OnCmdMsg на диалоге; в ней если пришла команда и код уведомления KILLFocus и стоит флаг закрытия, не вызывать базовый обработчик а просто возвращать true.
Но есть подозрение, что фишка не пройдет: ты ведб закрываешь форму, нажимая какую-нибудь кнопку, а это скорее всего сначала вызовет killfocus, прежде чем ты флаг выставишь.

Вообще-то проверка на KillFocus - плохая идея - ты уже хлебнул. Нужно выбрать сначала концепуию: 
1) каждое поле в любой момент содержит валидные данные 
ИЛИ
2) валидные данные должны быть в конце, при нажатии OK или эквивалента.  
Очевидно, 1 вариант поддерживать сложнее, и нужно бороться с кил-фокусами. Кстати, тогда нечего возмущаться, что по Cancel форма не закрывается, а требует исправления (всегда так всегда)
2-й вариант более человечный: проверяй все поля только при выходе с подтверждением.


Автор: 17dufa 30.9.2009, 16:42
Earnest, к сожалению, второй вариант не катит. По поведению KillFocus я и не возмущаюсь, я его прекрасно понимаю и полностью с ним согласен в рамках существующего кода, но так как такое поведение пользователя не устроит, то код надо править. попробую завтра поиграться с OnCmdMsg, по результатам отпишусь.

Автор: Earnest 1.10.2009, 06:48
Ясно, но имей в виду, что более чем возможно, что KillFocus придет раньше, чем команда Cancel (и ты выставишь флаг). Тогда попробуй перехватить событие, которое должно привести к выходу с отменой, например LBUTTONDOWN на кнопке Cancel. Выставь флаг и вызови стандартный обработчик. Это должно помочь. Удобнее всего сделать это в PreTranslateMessage диалога, т.к. там можно обработать всевозможные варианты выхода. А что касается OnCmdMsg, так это железно получится, если флаг вовремя выставишь.

Автор: 17dufa 1.10.2009, 16:28
значит так. вот работающие решение по отрубанию обработчиков KILLFOCUS по закрытию формы кнопочкой "выход"(IDCANCEL) или крестиком:
Код

class CForm : CDialog
{
BOOL m_Exit;
....
};

CForm::CForm(...):m_Exit(FALSE)....

BOOL CMT103Form::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    const MSG &lastSentMsg = AfxGetThreadState()->m_lastSentMsg;

    if (m_bExit && nCode != CN_UPDATE_COMMAND_UI && !pHandlerInfo) 
    {
        int nMsg = HIWORD(nCode);
        nCode = LOWORD(nCode);
    if (!nMsg) nMsg = WM_COMMAND;
        if (nMsg == WM_COMMAND && ((nCode == EN_KILLFOCUS)
             || (nCode == CBN_KILLFOCUS)
             || (nCode == LBN_KILLFOCUS)
             || (nMsg == WM_NOTIFY && nCode == LOWORD(NM_KILLFOCUS)))) 
    {
            return TRUE;
    }
    return CDialogScr::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

void СForm::OnCancel() 
{
    m_Exit = TRUE;
    
    CDialogScr::OnCancel();
}

BOOL CMT103Form::PreTranslateMessage(MSG* pMsg) 
{
    if (pMsg->message == WM_LBUTTONDOWN)
    {
        if (GetDlgItem(IDCANCEL)->GetSafeHwnd() == pMsg->hwnd)
            m_Exit = TRUE;
    }
}


Благодарю Earnest за помощь.

Автор: Earnest 1.10.2009, 18:47
Проверять классы - это лишнее, уведомления уникальны, можно проверять только их. А вот чего у тебя нет - это отсечения апдейтов, которые тоже идут через OnCmdMsg. И, кстати, флажок лучше проверить в самом начале:
Код

   if (m_bExit && nCode != CN_UPDATE_COMMAND_UI && !pHandlerInfo)
   {
       nMsg = HIWORD(nCode);
       nCode = LOWORD(nCode);
       if (nMsg == 0) nMsg = WM_COMMAND;
       if ((nMsg == WM_COMMAND && (nCode == EN_KILLFOCUS || nCOde == ...)) || (nMsg == WM_NOTIFY && nCode ==   NM_KILLFOCUS) return TRUE;
   }


Автор: 17dufa 2.10.2009, 14:07
Earnest, ща поправлю

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)