今天項目中遇到的問題,記錄下來,做個總結。
一個簡單的目的是創(chuàng)建一個非模態(tài)對話框并在對話框關閉后將其銷毀。
這里的銷毀包括:銷毀對話框對象資源和對話框對象指針;
首先說創(chuàng)建對話框:
一、模態(tài)對話框(model dialog box)
在程序運行的過程中,若出現(xiàn)了模態(tài)對話框,那么主窗口將無法發(fā)送消息,直到模態(tài)對話框退出才可以發(fā)送。
點擊模態(tài)對話框中的OK按鈕,模態(tài)對話框會被銷毀。創(chuàng)建一個模態(tài)對話框的代碼:
因為DoModal()函數(shù)的一個功能是,當前只能運行此模態(tài)對話框,且停止主窗口的運行,直到模態(tài)對話框退出,才允許主窗口運行。
DoModal()函數(shù)也有顯示對話框的功能,所以也無需調(diào)用其他函數(shù)來顯示對話框。(這里就關系到DoModal中的函數(shù)調(diào)用順序,后面會有順序的說明)
二、非模態(tài)對話框(modaless dialog box)
創(chuàng)建非模態(tài)對話框,必須聲明一個指向CTestDialog類的指針變量,且需要顯示的調(diào)用ShowWindow()才能將對話框顯示出來。有兩種創(chuàng)建方法:
(1)采用局部變量創(chuàng)建一個非模態(tài)對話框
可以有兩種解決辦法:
1) 在創(chuàng)建對話框的類中,將對話框對象指針存儲起來,然后釋放對應指針,一般可以定義一個全局的或者成員變量來存儲(用map)
2)將對話框對象指針的釋放交給對話框自身去維護,在上層類中之創(chuàng)建出來即可。具體方法是:在對話框類中重寫PostNcDestory方法,該方法中delete this即可。具體順序后面介紹。
(2)采用成員變量創(chuàng)建一個非模態(tài)對話框
首先在你所要編寫的類的頭文件中聲明一個指針變量:
然后再在相應的CPP文件,在你要創(chuàng)建對話框的位置添加如下代碼:
最后在所在類的析構函數(shù)中收回pTD所指向的內(nèi)存:
但這樣的方法只能創(chuàng)建一個對話框,若是再打開一個對話框,則之前的指針丟失(會造成內(nèi)存不好釋放)。
若要用這種方式創(chuàng)建多個對話框可以用一個map管理存儲指針,釋放時對應釋放,關閉了哪個對話框就把那個對應指針釋放掉,但這樣做很麻煩。
我的做法是第一種方法,在對話框類中維護釋放和關閉對話框。下面會將方法寫出來。
一個非模態(tài)的MFC 窗口的銷毀過程:
假設自己通過new創(chuàng)建了一個窗口對象pWnd,然后pWnd->Create。則銷毀窗口的調(diào)用次序:
1. 手工調(diào)用pWnd->DestroyWindow(); // 一般在對話框類中的OnCancle函數(shù)中postMessage(WM_DESTORY)或者直接調(diào)用
2. DestroyWindow會發(fā)送WM_DESTROY;
3. WM_DESTROY對應的消息處理函數(shù)是OnDestroy();
4. DestroyWindow會發(fā)送WM_NCDESTROY;
5. WM_NCDESTROY對應的消息處理函數(shù)是OnNcDestroy;
6. OnNcDestroy最后會調(diào)用PostNcDestroy;
7. PostNcDestroy經(jīng)常被用戶重載以提供釋放內(nèi)存操作。例如可以使用delete this;
通過這種方式,窗口對象對應的窗口和窗口對象本身都被釋放了。
注: 銷毀窗口對象對應的窗口和釋放窗口對象指針 ,可以通過DestroyWindow,這是比較好的方法,因為最后MFC會自動相應WM_CLOSE導致CframWnd::DestroyWindow被調(diào)用,然后會一次釋放所有子窗口的句柄。用戶需要做的是在PostNcDestroy中釋放堆窗口對象指針。但因為某些對象是在棧中申請的,所以delete this可能出錯。這就要保證寫程序時自己創(chuàng)建的窗口盡量使用堆申請。一個MFC窗口對象包括兩方面的內(nèi)容:一是窗口對象封裝的窗口,即存放在m_hWnd成員中的HWND(窗口句柄),二是窗口對象本身是一個C++對象。要刪除一個MFC窗口對象,應該先刪除窗口對象封裝的窗口,然后刪除窗口對象本身。
刪除窗口最直接方法是調(diào)用CWnd::DestroyWindow或::DestroyWindow,前者封裝了后者的功能。前者不僅會調(diào)用后者,而且會使成員m_hWnd保存的HWND無效(NULL)。如果DestroyWindow刪除的是一個父窗口或擁有者窗口,則該函數(shù)會先自動刪除所有的子窗口或被擁有者,然后再刪除父窗口或擁有者。在一般情況下,在程序中不必直接調(diào)用DestroyWindow來刪除窗口,因為MFC會自動調(diào)用DestroyWindow來刪除窗口。例如,當用戶退出應用程序時,會產(chǎn)生WM_CLOSE消息,該消息會導致MFC自動調(diào)用CWnd::DestroyWindow來刪除主框架窗口,當用戶在對話框內(nèi)按了OK或Cancel按鈕時,MFC會自動調(diào)用CWnd::DestroyWindow來刪除對話框及其控件。
對于一個在堆中動態(tài)創(chuàng)建的窗口對象,其生命期卻是任意長的。所以可能會產(chǎn)生這樣的疑問,為什么有些程序用new創(chuàng)建了一個窗口對象,卻未顯式的用delete來刪除它呢?問題的答案就是有些MFC窗口對象具有自動清除的功能。
如前面講述非模態(tài)對話框時所提到的,當調(diào)用CWnd::DestroyWindow或::DestroyWindow刪除一個窗口時,被刪除窗口的PostNcDestroy成員函數(shù)會被調(diào)用。缺省的PostNcDestroy什么也不干,但有些MFC窗口類會覆蓋該函數(shù)并在新版本的PostNcDestroy中調(diào)用delete this來刪除對象,從而具有了自動清除的功能。此類窗口對象通常是用new操作符創(chuàng)建在堆中的,但程序員不必操心用delete操作符去刪除它們,因為一旦調(diào)用DestroyWindow刪除窗口,對應的窗口對象也會緊接著被刪除。
對于在堆中動態(tài)創(chuàng)建了的非自動清除的窗口對象,必須在窗口被刪除后,顯式地調(diào)用delete來刪除對象(一般在擁有者或父窗口的析構函數(shù)中進行).對于具有自動清除功能的窗口對象,只需調(diào)用CWnd::DestroyWindow即可刪除窗口和窗口對象。注意,對于在堆中創(chuàng)建的窗口對象,不要在窗口還未關閉的情況下就用delete操作符來刪除窗口對象。
下面總結一下MFC對話框創(chuàng)建和銷毀的函數(shù)調(diào)用順序:
非模態(tài)對話框
MFC應用程序創(chuàng)建窗口的過程
1.PreCreateWindow() 該函數(shù)是一個重載函數(shù),在窗口被創(chuàng)建前,可以在該重載函數(shù)中改變創(chuàng)建參數(shù) (可以設置窗口風格等等)
2.PreSubclassWindow() 這也是一個重載函數(shù),允許首先子分類一個窗口
3.On
4.On
5.On
6.On
7.On
8.On
9.On
MFC應用程序關閉窗口的順序(非模態(tài)窗口)
1.On
2.On
3.On
4.PostNcDestroy() 重載函數(shù),作為處理On
對于非模態(tài)窗口,必須重載OnCancel函數(shù),在函數(shù)中調(diào)用DestroyWindows()方法,且不能調(diào)用基類的函數(shù)。因為基類函數(shù)中調(diào)用的是 EndDialog()方法。(因為EndDialog是關閉模態(tài)對話框時調(diào)用的)而OnClose()也會調(diào)用OnCancel()方法。另外想通過OnOK關閉對話框,也必須同樣處理,不能直接用默認方法。
所以對于非模態(tài)窗口,其關閉過程為:
OnClose()->OnCancel()->DestroyWindow()->OnDestroy()->OnNcDestroy() ,->僅表示時間先后而已
而OnNcDestroy()最后又調(diào)用了PostNcDestroy()
說明:OnOK是對ID_OK的響應, OnCancel是對IDCANCEL的響應. 前者對應鍵盤的Enter, 后者對應Esc。OnOK()和OnCancel()都調(diào)用了EndDialog().OnOK調(diào)用了UpdateData(TRUE)而OnCacel()沒有調(diào)用。
模態(tài)的對話框可以用EndDialog來銷毀, 非模態(tài)的對話框要用DestroyWindow來銷毀
MFC應用程序中創(chuàng)建模態(tài)對話框的函數(shù)調(diào)用順序:
1.DoModal() 重載函數(shù),重載DoModal()成員函數(shù)
2.PreSubclassWindow() 重載函數(shù),允許首先子分類一個窗口
3.On
4.On
5.On
6.On
7.On
8.On
9.On
10. On
MFC應用程序中關閉模式對話框的順序
1.On
2.On
3.On
4.On
5.PostNcDestroy() 重載函數(shù),作為處理On
{
}
通常這樣是重載虛函數(shù)PostNcDestroy()來實現(xiàn)
void CMyDialog::PostNcDestroy()
{
}