我知道一种防止 MFC 对话框在按下Enter或Esc键时关闭的方法,但我想了解该过程的更多细节以及所有常见的替代方法。
提前感谢您的帮助。
当用户在对话框中按下 Enter 键时,可能会发生两种情况:
CDialog::SetDefID()
)。然后将带有此控件 ID 的 WM_COMMAND 发送到对话框。对于第一个选项,默认控件的 ID 可能等于 IDOK。然后结果将与第二个选项中的结果相同。
默认情况下,类CDialog
有一个WM_COMMAND(IDOK)
要调用的处理程序CDialog::OnOk()
,它是一个虚函数,默认情况下它调用EndDialog(IDOK)
关闭对话框。
因此,如果您想避免关闭对话框,请执行以下操作之一。
IDOK
.WM_COMMAND(IDOK)
不调用EndDialog()
.CDialog::OnOk()
并且不调用基本实现。关于 IDCANCEL,它是类似的,但没有等效SetDefID()
项,并且 ESC 键是硬编码的。所以为了避免对话框被关闭:
WM_COMMAND(IDCANCEL)
不调用EndDialog()
.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() ,这是非常不推荐的。
需要具备三个功能:
在标题中,添加三个函数原型。如果您想添加 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
};
在 .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
是为输入定义的?如我错了请纠正我。