MFC 编辑控件 EN_KILLFOCUS 问题

Posted

技术标签:

【中文标题】MFC 编辑控件 EN_KILLFOCUS 问题【英文标题】:MFC Edit Control EN_KILLFOCUS issue 【发布时间】:2019-04-05 12:28:16 【问题描述】:

我正在使用 Visual Studio 2013 并制作基于 MFC 对话框的应用程序。我遇到了编辑控件的 Kill Focus 的奇怪问题。

请看下面:

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

在我的应用程序中,对话框上有两个编辑控件。

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;
        
    

现在,问题发生在更改第一个编辑控件(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_QUALITY1IDC_EDIT_QUALITY2 有两个不同的值

 #define IDC_EDIT_QUALITY1               1018
 #define IDC_EDIT_QUALITY2               1020

请帮助解决这个问题。

【问题讨论】:

为什么不直接使用 MFC 提供的标准验证属性?当您将变量添加到控件时,您可以告诉它有效范围,然后系统使用它? 【参考方案1】:

我相信您收到的IDC_EDIT_QUALITY2 控件的EN_KILLFOCUS 通知不是由m_ctrlQuality1.SetFocus() 调用引起的,而是由AfxMessageBox() 调用引起的。

当您按下 [Tab] 键时,IDC_EDIT_QUALITY1 失去焦点,IDC_EDIT_QUALITY2 获得焦点。然后您会收到IDC_EDIT_QUALITY1EN_KILLFOCUS 通知。您显示错误消息,这会导致应用程序“屈服”(再次开始处理消息),同时显示消息框。 m_ctrlQuality1.SetFocus() 调用不会在AfxMessageBox() 返回之前发生,即在您关闭消息框之前,因此IDC_EDIT_QUALITY2EN_KILLFOCUS 通知不能是该调用的结果。我猜这是显示消息框的结果(IDC_EDIT_QUALITY2 获得了焦点,但消息框使其失去焦点)。

您可以按照 Staytuned123 的建议通过添加成员变量来解决此问题,但设置不同:将其命名为 m_bKillFocusProcessing,并在处理任何 EN_KILLFOCUS 通知时将其设置为 TRUE (AfxMessageBox () 加上 SetFocus()),并在完成处理后发送到 FALSE;如果它已经是TRUE 退出而不做任何事情。也就是说,一次只能处理一个EN_KILLFOCUS 通知。

但是,这样的用户界面(在退出字段时显示消息框)相当奇怪。为什么要重新发明***,而不是使用 MFC 已经提供的 DDX/DDV 功能?您可以定义与控件关联的成员变量,并执行各种检查,包括范围检查。调用UpdateData(TRUE) 执行检查(针对对话框上的所有控件)并将数据传输到成员变量。或者您可以放置​​一些显示错误的控件(通常为红色),当发现错误时激活,例如在 .net 或 web 中。

【讨论】:

您好,Constantine Georgiou,非常感谢您提供如此详细的解释。我已经设法使用 m_bKillFocusProcessing 逻辑获得了有效的解决方案。我会考虑尝试 DDX/DDV 和 UpdateData(TRUE),看看它是否会减少条件检查开销。再次感谢,确实!问候。【参考方案2】:

当您按下 TAB 键时,IDC_EDIT_QUALITY2 获得焦点。但是因为输入的值越界,程序调用m_ctrlQuality1.SetFocus(),这反过来又导致OnQuality2EditKillFocus()被调用。 添加一个成员变量 m_bQuality1OutOfBound 并在调用 m_ctrlQuality1.SetFocus() 之前将其设置为 true。在OnQuality2EditKillFocus()中,当m_bQuality1OutOfBound为true时,设置为false,不要调用ValidateQualityParams(IDC_EDIT_QUALITY2)

【讨论】:

嗨,Staytuned123,我已经尝试合并 m_bQuality1OutOfBound 并进行了相关更改。但是,它仍然不起作用。我是 *** 的新手,正在学习共享代码和帖子的正确方法。同时,我已将源代码上传到:drive.google.com/open?id=17E1B6ZGeXttRKK-Fyf708cS37cfchx1I 请您看一下包含源代码的 Test.zip 并提出可行的解决方案。问候,哈迪克·沙阿 我试用了你的程序员。不要在 OnQuality2EditKillFocus() 中将 m_bQuality1OutOfBound 设置为 false。其他一切都保持不变。这将解决你的问题。请记住对 IDC_EDIT_QUALITY1 和 IDC_EDIT_QUALITY2 应用相同的更改。 嗨,Staytuned123,尝试使用 m_bQuality1OutOfBound 方法,仍然遗漏了一些情况,即验证仅被触发一次并且没有再次触发,即使它应该被触发。我尝试了 m_bKillFocusProcessing (正如上面的康斯坦丁乔治欧所建议的那样),它正在解决我的问题。感谢您检查我的代码并提供建议的所有努力。问候。

以上是关于MFC 编辑控件 EN_KILLFOCUS 问题的主要内容,如果未能解决你的问题,请参考以下文章

MFC中TAB控件的编辑

MFC 旋转/编辑控件

编辑控件 MFC 中光标位置更改时是不是有通知代码?

借助复选框控件 (MFC) 启用/禁用编辑框

从 MFC 中的编辑控件写入文本 [重复]

MFC 搜索编辑框