本文参考了如下文章:
http://msdn.microsoft.com/en-us/library/66b3y2ab(VS.71).aspx
http://topic.csdn.net/u/20100918/16/5a8bb22b-80bc-4e9f-8392-a3f876e91e05.html
http://blog.csdn.net/zdl1016/article/details/2799823(推荐)
其实大家都明白,想要解决这个问题,其实有两种思路:
1、处理PreTranslateMessage函数,将消息为ESC和ENTER的都过滤掉,如直接返回或替换为WM_RETURN等。但是这个不太推荐。
2、重载OnOk(),OnCancel()函数,(这是根本的重点的解决办法)
对于很熟悉VC的同学来说不难,但是初入门的在网上看到的都是如何如何的办法,没有将新手最迫切的问题解决了:如何重载?
首先,MFC创建的Dialog在按下默认的确定(OK)和取消(CANCEL)按钮时都点用了父窗口的OnOk()和OnCancel()函数,他们的区别:
第一,OnOK()和OnCancel()是CDialog基类的成员函数,而OnClose()和OnDestroy()是CWnd基类的成员函数,即WM消息响应函数。从应用程序结构的角度,拿对话框来说,红色的X对应的是CWnd,而处于对话框中的“确定”、“取消”按钮则对应了CDialog。
第二,OnClose()和OnDestroy()
在单视图程序中,根据<<深入浅出MFC>>所讲,程序退出时执行的操作顺序为(从点X按钮开始)
(1)用户点击X退出按钮,发送了WM_CLOSE消息----->响应OnClose()
(2)在WM_CLOSE消息的处理函数中,调用DestroyWindow()----->销毁与指定CWnd窗口对象关联的窗口,但未销毁CWnd对象
(3)在DestroyWindow()中发送了WM_DESTROY消息----->窗口销毁后响应OnDestroy()
(4)在WM_DESTROY消息中调用PostQuitMessage(),发送WM_QUIT消息,结束消息循环
可以看到,程序的退出过程,是先响应OnClose(),然后响应OnDestroy(),在响应OnDestroy()之前,窗口对象已经被销毁。OnDestroy()到底干了什么呢?它就像一个teller,先通知CWnd对象告诉它即将被销毁,尔后OnDestroy的真正运行是在CWnd对象已经从屏幕上清除以后被调用的。
第三,OnOK()、OnCancel()()、OnClose()、OnDestroy()
CDialog::OnOK首先调用UpdateData(TRUE)将数据传给对话框成员变量,然后调用CDialog::EndDialog关闭对话框;
CDialog::OnCancel只调用CDialog::EndDialog关闭对话框;
OnClose()是响应 WM_CLOSE 的.一定程度上可以说CDialog::EndDialog()和OnClose()完成类似的工作,但处理的机制不一样,前者是CDialog的对象机制,后者是WM的消息映射机制。
CDialog::EndDialog()-------->OnDestroy()
OnClose()-------->OnDestroy()
EndDialog()和OnClose()属于“同级别”的,所以我们在按下OK按钮的时候,程序是不会执行OnClose()的,但两种机制都必须经过OnDestroy()
对于按键:
按esc只会调用OnCancel()按alt+f4会先调用OnClose()后调用OnCancel()
按X或关闭按扭时会先调用OnClose()后调用OnCancel()
**********************************************************************************
重载OnOK,OnCancel函数,下面的这种方式不是很正确:
protected:
virtual void OnCancel();
virtual void OnOK();
void CDialog::OnOK()
{
// TODO: 在此添加专用代码和/或调用基类
//CDialog::OnOK();
}
.....
**********************************************************
其实也没啥太大的错误,最大的错误是重载了CDialog的OnOk,OnCancel方法,这样的话是对于父窗口的正常使用有潜在的危险,并且经实践有时候并不能够达到原有的目的。最正确的方法是重载CXXXDlg(即我们需要处理的窗口)的对应方法,这样就很完美了。
一般来说,我们需要不但需要重载OnOk(),OnCancel(),而且需要重新相应WM_CLOSE消息,其中WM_CLOSE消息相应很重要,如果不这么做你就不能通过X以及各种正常的方式关闭对话框。
所以一般这么做:
- //CXXXDlg.h中
- protect://public也没错
- virtual void OnOk();
- virtual void OnCancel();
- //CXXXDlg.cpp中
- void CXXXDlg::OnOk()//啥也不做就OK了
- {
- }
- void CXXXDlg::OnCancel()//同上
- {
- }
//CXXXDlg.h中
protect://public也没错
virtual void OnOk();
virtual void OnCancel();
//CXXXDlg.cpp中
void CXXXDlg::OnOk()//啥也不做就OK了
{
}
void CXXXDlg::OnCancel()//同上
{
}
然后Add window message Handle,选则WM_CLOSE消息,添加并编辑,在消息响应中函数中添加
Enddialog(IDCANCEL); //参数可以自己根据需要填写
如,我的项目名叫CDlgDrawTool,代码如下:
- void CDlgDrawTool::OnCancel() //回车按钮处理
- {
- }
- void CDlgDrawTool::OnOK() //ESC按钮不处理
- {
- }
- void CDlgDrawTool::OnClose() //X按钮处理
- {
- // TODO: Add your message handler code here and/or call default
- EndDialog(IDCANCEL); //关闭窗口
- CDialog::OnClose();
- }
void CDlgDrawTool::OnCancel() //回车按钮处理
{
}
void CDlgDrawTool::OnOK() //ESC按钮不处理
{
}
void CDlgDrawTool::OnClose() //X按钮处理
{
// TODO: Add your message handler code here and/or call default
EndDialog(IDCANCEL); //关闭窗口
CDialog::OnClose();
}
这样,你的对话框就可以正常使用了!