zl程序教程

您现在的位置是:首页 >  其它

当前栏目

MFC中解决回车和ESC关闭的问题,重载OnOk(),OnCancel()函数的正确做法

解决 函数 关闭 正确 mfc 重载 回车 做法
2023-09-11 14:16:46 时间

本文参考了如下文章:

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以及各种正常的方式关闭对话框。

      所以一般这么做:

 

[cpp] view plaincopy

  1. //CXXXDlg.h中  
  2. protect://public也没错  
  3. virtual void OnOk();  
  4. virtual void OnCancel();  
  5.   
  6. //CXXXDlg.cpp中  
  7.   
  8. void CXXXDlg::OnOk()//啥也不做就OK了  
  9. {  
  10.   
  11. }  
  12. void CXXXDlg::OnCancel()//同上  
  13.   
  14. {  
  15.   
  16. }  
 
  1. //CXXXDlg.h中

  2. protect://public也没错

  3. virtual void OnOk();

  4. virtual void OnCancel();

  5.  
  6. //CXXXDlg.cpp中

  7.  
  8. void CXXXDlg::OnOk()//啥也不做就OK了

  9. {

  10.  
  11. }

  12. void CXXXDlg::OnCancel()//同上

  13.  
  14. {

  15.  
  16. }


然后Add window message Handle,选则WM_CLOSE消息,添加并编辑,在消息响应中函数中添加

 

 

 

 

Enddialog(IDCANCEL); //参数可以自己根据需要填写

如,我的项目名叫CDlgDrawTool,代码如下:

 

[cpp] view plaincopy

  1. void CDlgDrawTool::OnCancel()   //回车按钮处理  
  2. {  
  3. }  
  4. void CDlgDrawTool::OnOK()   //ESC按钮不处理  
  5. {  
  6. }  
  7. void CDlgDrawTool::OnClose()    //X按钮处理  
  8. {  
  9.     // TODO: Add your message handler code here and/or call default  
  10.     EndDialog(IDCANCEL);    //关闭窗口  
  11.     CDialog::OnClose();  
  12. }  
 
  1. void CDlgDrawTool::OnCancel() //回车按钮处理

  2. {

  3. }

  4. void CDlgDrawTool::OnOK() //ESC按钮不处理

  5. {

  6. }

  7. void CDlgDrawTool::OnClose() //X按钮处理

  8. {

  9. // TODO: Add your message handler code here and/or call default

  10. EndDialog(IDCANCEL); //关闭窗口

  11. CDialog::OnClose();

  12. }


 

 

 

 

 

这样,你的对话框就可以正常使用了!

 

http://blog.csdn.net/bbdxf/article/details/7395201