[英]How to prevent MFC dialog closing on Enter and Escape keys?
I know one method of preventing an MFC dialog from closing when the Enter or Esc keys are pressed, but I'd like to know more details of the process and all the common alternative methods for doing so.我知道一种防止 MFC 对话框在按下Enter或Esc键时关闭的方法,但我想了解该过程的更多详细信息以及执行此操作的所有常用替代方法。
Thanks in advance for any help.在此先感谢您的帮助。
When the user presses Enter key in a dialog two things can happen:当用户在对话框中按下 Enter 键时,会发生两种情况:
CDialog::SetDefID()
).该对话框有一个默认控件(请参阅CDialog::SetDefID()
)。 Then a WM_COMMAND with the ID of this control is sent to the dialog.然后将带有此控件 ID 的 WM_COMMAND 发送到对话框。With the first option, it may happen that the default control has a ID equal to IDOK.对于第一个选项,可能会发生默认控件的 ID 等于 IDOK。 Then the results will be the same that in the second option.那么结果将与第二个选项中的结果相同。
By default, class CDialog
has a handler for the WM_COMMAND(IDOK)
that is to call to CDialog::OnOk()
, that is a virtual function, and by default it calls EndDialog(IDOK)
that closes the dialog.默认情况下,类CDialog
有一个用于调用CDialog::OnOk()
的WM_COMMAND(IDOK)
处理程序,这是一个虚函数,默认情况下它调用EndDialog(IDOK)
来关闭对话框。
So, if you want to avoid the dialog being closed, do one of the following.因此,如果您想避免关闭对话框,请执行以下操作之一。
IDOK
.将默认控件设置为IDOK
以外的其他控件。WM_COMMAND(IDOK)
that does not call EndDialog()
.将处理程序设置为不调用EndDialog()
的WM_COMMAND(IDOK)
EndDialog()
。CDialog::OnOk()
and do not call the base implementation.覆盖CDialog::OnOk()
并且不调用基本实现。 About IDCANCEL, it is similar but there is not equivalent SetDefID()
and the ESC key is hardcoded.关于 IDCANCEL,它是类似的,但没有等效的SetDefID()
并且 ESC 键是硬编码的。 So to avoid the dialog being closed:所以为了避免对话框被关闭:
WM_COMMAND(IDCANCEL)
that does not call EndDialog()
.将处理程序设置为不调用EndDialog()
的WM_COMMAND(IDCANCEL)
EndDialog()
。CDialog::OnCancel()
and do not call the base implementation.覆盖CDialog::OnCancel()
并且不调用基本实现。There is an alternative to the previous answer, which is useful if you wish to still have an OK / Close button.上一个答案有一个替代方案,如果您希望仍然有一个确定/关闭按钮,这将很有用。 If you override the PreTranslateMessage function, you can catch the use of VK_ESCAPE / VK_RETURN like so:如果您覆盖 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 answer of @the-forest-and-the-trees is quite good. @the-forest-and-the-trees 的回答很好。 Except one situation which was addressed by @oneworld.除了@oneworld 解决的一种情况。 You need to filter messages which are not for dialog window:您需要过滤不是对话窗口的消息:
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);
}
Remember to add virtual
in the header file.记得在头文件中添加virtual
。
When dealing with Dialog style MFC applications, the framework automatically hard codes a few items that must be overridden to prevent the application from quitting when the ESC or Enter keys are pressed.在处理 Dialog 样式的 MFC 应用程序时,框架会自动硬编码一些必须覆盖的项目,以防止应用程序在按下 ESC 或 Enter 键时退出。 But there is a very simple way that doesn't require anything special such as implementing PreTranslateMessage() which is very much not recommend.但是有一种非常简单的方法不需要任何特殊的东西,例如实现非常不推荐的 PreTranslateMessage()。
There are three functions that need to be in place:有三个功能需要到位:
In the header, add the three function prototypes.在标题中,添加三个函数原型。 You can use the Class Wizard if you like to add the WM_CLOSE event handler but it's super simple to just type it in.如果您想添加 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
};
In the .cpp file, add the ON_WM_CLOSE() entry to the message map and the definitions for the three functions.在 .cpp 文件中,将 ON_WM_CLOSE() 条目添加到消息映射和三个函数的定义中。 Since OnCancel() and OnOK() are generally going to be empty, you could just inline them in the header if you want (see what I did in Step 1?).由于 OnCancel() 和 OnOK() 通常为空,如果需要,您可以将它们内联到标头中(看看我在第 1 步中做了什么?)。
The .cpp file will have something like this: .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
}
I simply override the OnOk event and instead of passing the message to the parent dialog, do nothing.我只是覆盖 OnOk 事件,而不是将消息传递给父对话框,什么都不做。
So it's basically simple as doing so:所以这样做基本上很简单:
void OnOk() override { /*CDialog::OnOK();*/ }
This should prevent the dialog from closing when pressing the return/enter key.这应该可以防止对话框在按下回车/回车键时关闭。
Make sure you don't #define CUSTOM_ID 2
because 2
is already defined for escape and I think 1
is defined for enter?确保你没有#define CUSTOM_ID 2
因为2
已经定义为转义而我认为1
是为输入定义的? Correct me if i'm wrong.如果我错了,请纠正我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.