視窗關閉過程
——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視窗關閉銷毀等相關知識時的一些總結。