窗口关闭过程
——OnOK(),OnCancel(),OnClose(),EndDialog(),DestroyWindow(),OnDestroy(),OnNcDestroy()
发现我误导人了,说的不准确,修改一下。
一、对于非模态窗口,必须重载OnCancel函数,在函数中调用DestroyWindows()方法,且不能调用基类的函数。因为基类函数中调用的是EndDialog()方法。而OnClose()也会调用OnCancel()方法。另外想通过OnOK关闭对话框,也必须同样处理,不能直接用默认方法。
1 、只有点击标题栏的叉号图标、在桌面任务栏右键-关闭、Alt+F4、标题栏最左边图标上单击-关闭,发送WM_CLOSE消息,触发OnClose()。
所以对于非模态窗口,其关闭过程
OnClose()->OnCancel()->DestroyWindow()->OnDestroy()->OnNcDestroy() , ->仅表示时间先后而已
而OnNcDestroy()最后又调用了PostNcDestroy()
2、回车、ESC、点击“确定”或“取消”,都不会调用OnClose()
一般来说,OnOK是对ID_OK的响应, OnCancel是对IDCANCEL的响应. 前者对应键盘的Enter, 后者对应Esc。
OnCancel()->DestroyWindow()->OnDestroy()->OnNcDestroy()
OnOK()->DestroyWindow()->OnDestroy()->OnNcDestroy()
OnNcDestroy()最后又调用了PostNcDestroy()
OnOK()与OnCancel()
如前面所述,OnOK是对ID_OK的响应, OnCancel是对IDCANCEL的响应. 前者对应键盘的Enter, 后者对应Esc。
OnOK()和OnCancel()都调用了EndDialog().OnOK调用了UpdateData(TRUE)而OnCacel()没有调用。
在OnOK()结束刚进入DestroyWindow时,其实窗口并未关闭,依然可以用ShowWindow显示出来
模态的对话框可以用EndDialog来销毁, 非模态的对话框要用DestroyWindow来销毁
见《OnOK与OnCancel》http://ponymaggie.blog.sohu.com/135823530.html
EndDialog()
该函数清除一个模态对话框,并使系统中止对对话框的任何处理
对于DoModal出来的窗口,可以使用默认的OnOk()和OnCancel()来处理。其基类方法中会调用EndDialog()方法。
它只能在对话框的消息处理函数里使用,并且这个函数调用之后,没有立即就删除对话框的,而是设置了操作系统里的结束标志。当操作系统查检到有这个标志时,就去删除对话框的消息循环,同时也去释放对话框占用的资源。其实对话框的生命周期是这样的,先由函数DialogBox创建对话框,这样函数DialogBox完成创建对话框但还没有显示前会发出消息WM_INITDIALOG,让对话框有机会初始化上面所有窗口或控件的显示,比如设置文本框的字符串等。最后当用户点出确定或者取消的按钮,就收到两个命令IDOK或IDCANCEL,这时就可以调用函数EndDialog来结束对话框的生命。
见《Windows API一日一练(18)EndDialog函数》http://blog.csdn.net/caimouse/archive/2007/07/30/1716140.aspx
DestroyWindows()
CWnd::DestroyWindow销毁m_hWnd(必须非空),同时销毁其菜单、定时器,以及完成其他清理工作。
::DestroyWindow使将被销毁的窗口失去激活、失去输入焦点,并发送WM_DESTROY、WM_NCDESTROY消息到该窗口及其各级子窗口。如果被销毁的窗口是子窗口且没有设置WM_NOPARENTNOTFIY风格,则给其父窗口发送WM_PARENTNOFITY消息。
CWnd::OnDestroy() 和 CWnd::OnNcDestroy() 以及 CWnd::PostNcDestroy()
CWnd::OnDestroy() 调用缺省处理函数Default()。
CWnd::OnNcDestroy() 首先判断当前线程的主窗口是否是该窗口,如果是且模块非DLL,则发送WM_QUIT消息,使得程序结束;
然后,判断当前线程的活动窗口是否是该窗口,如果是则设置活动窗口为NULL;
接着,清理Tooltip窗口,调用Default由Windows缺省处理WM_NCDESTROY消息,UNSUBCLASS,把窗口句柄和MFC
窗口对象分离(Detach);
最后,调用虚函数PostNcDestoy()。
见《MFC教程_应用程序的退出》http://www.vczx.com/tutorial/mfc/mfc6.php
总结一下的话,DestroyWindows可以理解成是主动的,OnDestroy是被动的.
用户主动调用DestroyWindows来关闭窗口,而当窗口被关闭时OnDestroy函数被调用!
你调用DestroyWindow(),那么系统就会发一个WM_DESTROY的消息,这个消息会调用OnDestroy()函数.
DestroyWindow() ------> WM_DESTROY + WM_NCDESTROY ------>OnDestroy()
发消息 响应消息映射
另外,如果要在退出时提示用户,应在OnClose()或OnOK()、OnCancel()中作出处理,而不能在响应WM_DESTROY时处理
,因为那是窗口已经销毁了(但应用程序并没有退出)。在处理WM_DESTROY消息时,系统会调用
PostQuitMessage()向消息队里投递WM_QUIT消息,结束消息循环。(见《VC++深入详解》P18)
最后注意一个问题,通常我们创建一个非模态窗口时,可能会这样写
{
CDialog * pWnd = new CMyDialog();
pWnd->Create(……);
pWnd->ShowWindow(SW_SHOW);
}
很肯能是在一个模块或者一个函数中创建窗口,但是却无法知道什么时候关闭窗口。而pWnd也只是作为一个局部变量。那么如何对它进行析构呢?
通常这样是重载虚函数PostNcDestroy()来实现
void CMyDialog::PostNcDestroy()
{
CDialog::PostNcDestroy();
delete this;
}
为什么把对话框类的delete this放在PostNcDestroy中而不是OnNcDestroy?
这是因为OnNcDestroy只被已建立的窗口调用。如果建立窗口失败(如PreCreateWindow), 则没有窗口处来发送
WM_NCDESTROY消息。PostNcDestroy是在对象窗口被完全删除, 在OnNcDestroy后,甚至在窗口建立失败之后
调用的。
以上是学习MFC窗口关闭销毁等相关知识时的一些总结。