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