繁体   English   中英

如何防止 MFC 对话框在 Enter 和 Escape 键上关闭?

[英]How to prevent MFC dialog closing on Enter and Escape keys?

我知道一种防止 MFC 对话框在按下EnterEsc键时关闭的方法,但我想了解该过程的更多详细信息以及执行此操作的所有常用替代方法。

在此先感谢您的帮助。

当用户在对话框中按下 Enter 键时,会发生两种情况:

  1. 该对话框有一个默认控件(请参阅CDialog::SetDefID() )。 然后将带有此控件 ID 的 WM_COMMAND 发送到对话框。
  2. 该对话框没有默认控件。 然后将 ID = IDOK 的 WM_COMMAND 发送到对话框。

对于第一个选项,可能会发生默认控件的 ID 等于 IDOK。 那么结果将与第二个选项中的结果相同。

默认情况下,类CDialog有一个用于调用CDialog::OnOk()WM_COMMAND(IDOK)处理程序,这是一个虚函数,默认情况下它调用EndDialog(IDOK)来关闭对话框。

因此,如果您想避免关闭对话框,请执行以下操作之一。

  1. 将默认控件设置为IDOK以外的其他控件。
  2. 将处理程序设置为不调用EndDialog()WM_COMMAND(IDOK) EndDialog()
  3. 覆盖CDialog::OnOk()并且不调用基本实现。

关于 IDCANCEL,它是类似的,但没有等效的SetDefID()并且 ESC 键是硬编码的。 所以为了避免对话框被关闭:

  1. 将处理程序设置为不调用EndDialog()WM_COMMAND(IDCANCEL) EndDialog()
  2. 覆盖CDialog::OnCancel()并且不调用基本实现。

上一个答案有一个替代方案,如果您希望仍然有一个确定/关闭按钮,这将很有用。 如果您覆盖 PreTranslateMessage 函数,您可以像这样捕获 VK_ESCAPE / VK_RETURN 的使用:

BOOL MyCtrl::PreTranslateMessage(MSG* pMsg)
{
    if( pMsg->message == WM_KEYDOWN )
    {
        if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
        {
            return TRUE;                // Do not process further
        }
    }

    return CWnd::PreTranslateMessage(pMsg);
}

@the-forest-and-the-trees 的回答很好。 除了@oneworld 解决的一种情况。 您需要过滤不是对话窗口的消息:

BOOL CDialogDemoDlg::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->hwnd == this->m_hWnd && pMsg->message == WM_KEYDOWN)
    {
        if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
        {
            return TRUE;                // Do not process further
        }
    }
    return CWnd::PreTranslateMessage(pMsg);
}

记得在头文件中添加virtual

在处理 Dialog 样式的 MFC 应用程序时,框架会自动硬编码一些必须覆盖的项目,以防止应用程序在按下 ESC 或 Enter 键时退出。 但是有一种非常简单的方法不需要任何特殊的东西,例如实现非常不推荐的 PreTranslateMessage()。

有三个功能需要到位:

  1. OnCancel() 函数覆盖基类版本而不是调用它。 这可以防止 ESC 键关闭应用程序。
  2. OnOK() 函数覆盖基类版本而不是调用基类。 这可以防止 Enter 键关闭应用程序。
  3. 由于您现在已阻止关闭对话框窗口,因此您现在必须实现 OnClose() 事件处理程序。 当 Windows 的“X”按钮或系统命令 Close Alt+F4 被单击时,此函数处理程序将进行处理。 现在为了关闭应用程序,如果需要,您可以调用其他函数 OnOK()、OnCancel() 之一的基类版本,以实际关闭应用程序。 此时,您现在可以完全控制应用程序的关闭方式。

第1步

在标题中,添加三个函数原型。 如果您想添加 WM_CLOSE 事件处理程序,您可以使用类向导,但只需输入它就非常简单。

// DefaultDialogAppDlg.h
//

class CDefaultDialogAppDlg : public CDialogEx
{
    // ... other code
  
protected:
    virtual void OnCancel(){}    // inline empty function
    virtual void OnOK(){}        // inline empty function
public:
    afx_msg void OnClose();      // message handler for WM_CLOSE

    // ...other code
};

第2步

在 .cpp 文件中,将 ON_WM_CLOSE() 条目添加到消息映射和三个函数的定义中。 由于 OnCancel() 和 OnOK() 通常为空,如果需要,您可以将它们内联到标头中(看看我在第 1 步中做了什么?)。

.cpp 文件将包含以下内容:

// DefaultDialogAppDlg.cpp

// ... other code

BEGIN_MESSAGE_MAP(CDefaultDialogAppDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_CLOSE()        // WM_CLOSE messages are handled here.
END_MESSAGE_MAP()

// ... other code

void CDefaultDialogAppDlg::OnClose()
{
    // TODO: Add exit handling code here
    // NOTE: to actually allow the program to end, call the base class
    // version of either the OnOK() or OnCancel() function.
    
    //CDialogEx::OnOK();      // returns 1 to theApp object
    CDialogEx::OnCancel();    // returns 2 to theApp object
}

我只是覆盖 OnOk 事件,而不是将消息传递给父对话框,什么都不做。
所以这样做基本上很简单:

void OnOk() override { /*CDialog::OnOK();*/ }

这应该可以防止对话框在按下回车/回车键时关闭。

确保你没有#define CUSTOM_ID 2因为2已经定义为转义而我认为1是为输入定义的? 如果我错了,请纠正我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM