Ошибка управления редактированием MFC EN_KILLFOCUS - PullRequest
1 голос
/ 05 апреля 2019

Я использую Visual Studio 2013 и создаю приложение на основе MFC Dialog.У меня странная проблема с Kill Focus of Edit Control.

Пожалуйста, смотрите ниже:

=========================================================================

В моем приложении у меня есть два диалоговых окна Edit Controls.

1st Edit Control -> IDC_EDIT_QUALITY1
2nd Edit Control -> IDC_EDIT_QUALITY2

Я обработал оба события EN_KILLFOCUS для проверки значения.

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    ON_EN_KILLFOCUS(IDC_EDIT_QUALITY1, &CTestDlg::OnQuality1EditKillFocus)
    ON_EN_KILLFOCUS(IDC_EDIT_QUALITY2, &CTestDlg::OnQuality2EditKillFocus)
END_MESSAGE_MAP()

void CTestDlg::OnQuality1EditKillFocus()
{
    ValidateQualityParams(IDC_EDIT_QUALITY1);
}

void CTestDlg::OnQuality2EditKillFocus()
{
    ValidateQualityParams(IDC_EDIT_QUALITY2);
}

#define MIN_QUALITY_VALUE     1     
#define MAX_QUALITY_VALUE   100

void CTestDlg::ValidateQualityParams(int qualityParamID)
{
    CString strQuality1;
    if (IDC_EDIT_QUALITY1 == qualityParamID)
    {
        m_ctrlQuality1.GetWindowText(strQuality1);
        if ((_ttoi(strQuality1) < MIN_QUALITY_VALUE) || (_ttoi(strQuality1) > MAX_QUALITY_VALUE))
        {
            CString strMessage;
            strMessage.Format(_T("Quality1 value must be between %d to %d."), MIN_QUALITY_VALUE, MAX_QUALITY_VALUE);
            **AfxMessageBox(strMessage);**
            m_ctrlQuality1.SetSel(0, -1);
            m_ctrlQuality1.SetFocus();
            return;
        }
    }

    CString strQuality2;
    if (IDC_EDIT_QUALITY2 == qualityParamID)
    {
        m_ctrlQuality2.GetWindowText(strQuality2);
        if ((_ttoi(strQuality2) < MIN_QUALITY_VALUE) || (_ttoi(strQuality2) > MAX_QUALITY_VALUE))
        {
            CString strMessage;
            strMessage.Format(_T("Quality2 value must be between %d to %d."), MIN_QUALITY_VALUE, MAX_QUALITY_VALUE);
            AfxMessageBox(strMessage);
            m_ctrlQuality2.SetSel(0, -1);
            m_ctrlQuality2.SetFocus();
            return;
        }
    }
}

Теперь проблема возникает, когда после изменения значения в 1-м элементе управления редактирования (IDC_EDIT_QUALITY1), скажем, введя в него 0 и нажав клавишу TAB, последовательность действий выглядит следующим образом:

  • void CTestDlg :: OnQuality1EditKillFocus() вызывается.
  • Вызывает ValidateQualityParams (IDC_EDIT_QUALITY1)
  • Внутри ValidateQualityParams он переходит к условию if (IDC_EDIT_QUALITY1 == qualityParamID).
  • Поскольку введенное мной значение меньше MIN_QUALITY_VALUE, оно отображает сообщение, вызывая AfxMessageBox.
    - Теперь, даже из стека вызовов AfxMessageBox, оно попадает в void CTestDlg :: OnQuality2EditKillFocus ()внутренне.

Хотя стек вызовов OnQuality1EditKillFocus еще не закончен, OnQuality2EditKillFocus вызывается из стека вызовов AfxMessageBox.

Я не понимаюпричина этой проблемы.Кто-нибудь сталкивался с такой проблемой раньше?

В моем resource.h у меня есть два различных значения для IDC_EDIT_QUALITY1 и IDC_EDIT_QUALITY2

 #define IDC_EDIT_QUALITY1               1018
 #define IDC_EDIT_QUALITY2               1020

Пожалуйста, помогите по этой проблеме.

Ответы [ 2 ]

0 голосов
/ 06 апреля 2019

Я полагаю, что уведомление EN_KILLFOCUS для элемента управления IDC_EDIT_QUALITY2, которое вы получаете, вызвано не вызовом m_ctrlQuality1.SetFocus(), а вызовом AfxMessageBox().

При нажатии клавиши [Tab] IDC_EDIT_QUALITY1 теряет фокус, а IDC_EDIT_QUALITY2 получает фокус. Затем вы получите уведомление EN_KILLFOCUS для IDC_EDIT_QUALITY1. Отображается сообщение об ошибке, которое приводит к тому, что приложение «уступает» (снова запускает обработку сообщений), пока отображается окно сообщения. Вызов m_ctrlQuality1.SetFocus() не будет выполнен до возврата AfxMessageBox(), т.е. до того, как вы закроете окно сообщения, и поэтому уведомление EN_KILLFOCUS для IDC_EDIT_QUALITY2 не может быть результатом этого вызова. Я предполагаю, что это результат отображения окна сообщения (IDC_EDIT_QUALITY2 получил фокус, но окно сообщения заставляет его потерять его).

Вы можете обойти это, добавив переменную memeber, как предложил Staytuned123, но в другой настройке: назовите ее, скажем m_bKillFocusProcessing, и установите ее на TRUE, пока вы обрабатываете ЛЮБОЕ EN_KILLFOCUS уведомление (AfxMessageBox () плюс SetFocus ()) и FALSE, когда вы закончите его обработку; если это уже TRUE выход, ничего не делая. То есть одновременно может обрабатываться только одно EN_KILLFOCUS уведомление.

Однако такой пользовательский интерфейс (отображающий окно сообщения при выходе из поля) довольно странный. И зачем изобретать велосипед, а не использовать функцию DDX / DDV, которую уже предлагает MFC? Вы можете определять переменные-члены, связанные с элементами управления, и выполнять различные проверки, включая проверку диапазона. Вызовите UpdateData(TRUE), чтобы выполнить проверки (для всех элементов управления в диалоговом окне) и передать данные в переменные-члены. Или вы можете поместить некоторые элементы управления отображением ошибок (обычно красного цвета), которые активируются при обнаружении ошибки, например, в .net или в Интернете.

0 голосов
/ 05 апреля 2019

Когда вы нажали клавишу TAB, IDC_EDIT_QUALITY2 получил фокус.Но поскольку введенное значение вышло за пределы, программа вызвала m_ctrlQuality1.SetFocus(), что, в свою очередь, привело к вызову OnQuality2EditKillFocus().Добавить переменную-член говорит m_bQuality1OutOfBound и установить его в true прямо перед вызовом m_ctrlQuality1.SetFocus()OnQuality2EditKillFocus(), когда m_bQuality1OutOfBound имеет значение true, установите для него значение false и не вызывайте ValidateQualityParams(IDC_EDIT_QUALITY2).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...