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

    xiaoxiao2023-12-18  170

    本文参考了如下文章:

    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

    //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,代码如下:

     

    [cpp] view plaincopy

    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();

    }

     

     

     

     

     

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

     

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

    最新回复(0)