小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

MFC 創(chuàng)建非模態(tài)對(duì)話框和銷毀過(guò)程

 行走在理想邊緣 2016-12-28

今天項(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ì)話框的代碼:

  1. //創(chuàng)建一個(gè)模態(tài)對(duì)話框  
  2. CTestDialog td;  
  3. td.DoModal();   
其中CTestDialog為所要?jiǎng)?chuàng)建的對(duì)話框類。而這個(gè)對(duì)話框是在另個(gè)類中創(chuàng)建。

因?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)建一個(gè)非模態(tài)對(duì)話框  
  2. CTestDialog *pTD = new CTestDialog();  
  3. pTD->Create(IDD_DIALOG1); //創(chuàng)建一個(gè)非模態(tài)對(duì)話框  
  4. pTD->ShowWindow(SW_SHOWNORMAL); //顯示非模態(tài)對(duì)話框 其中參數(shù)用swp_SHOWNOMAL,  SW_SHOW, SW_VISION 好像效果是一樣的 
這種方式創(chuàng)建的對(duì)話框,如果對(duì)話框?qū)ο笾羔樖蔷植康模敲措x開(kāi)作用域,指針就消失掉,所以當(dāng)釋放對(duì)話框?qū)ο笾羔標(biāo)傅膬?nèi)存時(shí)就無(wú)法在創(chuàng)建對(duì)話框的類中進(jìn)行釋放,若不做處理,則會(huì)造成內(nèi)存泄露。打開(kāi)很多個(gè)對(duì)話框則會(huì)導(dǎo)致內(nèi)存耗盡程序奔潰。

可以有兩種解決辦法:

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è)指針變量:

  1. private:  
  2.     CTestDialog *pTD;  

 然后再在相應(yīng)的CPP文件,在你要?jiǎng)?chuàng)建對(duì)話框的位置添加如下代碼:

  1. //采用成員變量創(chuàng)建一個(gè)非模態(tài)對(duì)話框  
  2. pTD = new CTestDialog(); //給指針?lè)峙鋬?nèi)存  
  3. pTD->Create(IDD_DIALOG1); //創(chuàng)建一個(gè)非模態(tài)對(duì)話框  
  4. pTD->ShowWindow(SW_SHOWNORMAL); //顯示非模態(tài)對(duì)話框  

        最后在所在類的析構(gòu)函數(shù)中收回pTD所指向的內(nèi)存:

  1. delete pTD;  

但這樣的方法只能創(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)按了OKCancel按鈕時(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.OnGetMinMaxInfo()   該函數(shù)為消息響應(yīng)函數(shù),響應(yīng)的是WM_GETMINMAXINFO消息,允許設(shè)置窗口的最大或者最小尺寸

4.OnNcCreate()        該函數(shù)也是一個(gè)消息響應(yīng)函數(shù),響應(yīng)WM_NCCREATE消息,發(fā)送消息以告訴窗口的客戶區(qū) 即將被創(chuàng)建

5.OnNcCalcSize()      該函數(shù)也是消息響應(yīng)函數(shù),響應(yīng)WM_NCCALCSIZE消息,作用是允許改變窗口客戶區(qū)大小

6.OnCreate()          該函數(shù)也是一個(gè)消息響應(yīng)函數(shù),響應(yīng)WM_CREATE消息,發(fā)送消息告訴一個(gè)窗口已經(jīng)被創(chuàng)建

7.OnSize()            該函數(shù)也是一個(gè)消息響應(yīng)函數(shù),響應(yīng)WM_SIZE消息,發(fā)送該消息以告訴該窗口大小已經(jīng) 發(fā)生變化

8.OnMove()            消息響應(yīng)函數(shù),響應(yīng)WM_MOVE消息,發(fā)送此消息說(shuō)明窗口在移動(dòng)

9.OnChildNotify()     該函數(shù)為重載函數(shù),作為部分消息映射被調(diào)用,告訴父窗口即將被告知一個(gè)窗口剛剛被創(chuàng)建

MFC應(yīng)用程序關(guān)閉窗口的順序(非模態(tài)窗口)

1.OnClose()       消息響應(yīng)函數(shù),響應(yīng)窗口的WM_CLOSE消息,當(dāng)關(guān)閉按鈕被單擊的時(shí)候發(fā)送此消息

2.OnDestroy()     消息響應(yīng)函數(shù),響應(yīng)窗口的WM_DESTROY消息,當(dāng)一個(gè)窗口將被銷毀時(shí),發(fā)送此消息

3.OnNcDestroy()   消息響應(yīng)函數(shù),響應(yīng)窗口的WM_NCDESTROY消息,當(dāng)一個(gè)窗口銷毀后發(fā)送此消息

4.PostNcDestroy() 重載函數(shù),作為處理OnNcDestroy()函數(shù)的最后動(dòng)作,被CWnd調(diào)用

對(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)用。
  在OnOK()結(jié)束剛進(jìn)入DestroyWindow時(shí),其實(shí)窗口并未關(guān)閉,依然可以用ShowWindow顯示出來(lái)

模態(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.OnCreate()            消息響應(yīng)函數(shù),響應(yīng)WM_CREATE消息,發(fā)送此消息以告訴一個(gè)窗口已經(jīng)被創(chuàng)建

4.OnSize()              消息響應(yīng)函數(shù),響應(yīng)WM_SIZE消息,發(fā)送此消息以告訴窗口大小發(fā)生變化

5.OnMove()              消息響應(yīng)函數(shù),響應(yīng)WM_MOVE消息,發(fā)送此消息,以告訴窗口正在移動(dòng)

6.OnSetFont()           消息響應(yīng)函數(shù),響應(yīng)WM_SETFONT消息,發(fā)送此消息,以允許改變對(duì)話框中控件的字體

7.OnInitDialog()        消息響應(yīng)函數(shù),響應(yīng)WM_INITDIALOG消息,發(fā)送此消息以允許初始化對(duì)話框中的控件, 或者是創(chuàng)建新控件

8.OnShowWindow()        消息響應(yīng)函數(shù),響應(yīng)WM_SHOWWINDOW消息,該函數(shù)被ShowWindow()函數(shù)調(diào)用

9.OnCtlColor()          消息響應(yīng)函數(shù),響應(yīng)WM_CTLCOLOR消息,被父窗口發(fā)送已改變對(duì)話框或?qū)υ捒蛏厦婵丶念伾?/p>

10. OnChildNotify()     重載函數(shù),作為WM_CTLCOLOR消息的結(jié)果發(fā)送

MFC應(yīng)用程序中關(guān)閉模式對(duì)話框的順序

1.OnClose()        消息響應(yīng)函數(shù),響應(yīng)WM_CLOSE消息,當(dāng)'關(guān)閉'按鈕被單擊的時(shí)候,該函數(shù)被調(diào)用

2.OnKillFocus()    消息響應(yīng)函數(shù),響應(yīng)WM_KILLFOCUS消息,當(dāng)一個(gè)窗口即將失去鍵盤輸入焦點(diǎn)以前被發(fā)送

3.OnDestroy()      消息響應(yīng)函數(shù),響應(yīng)WM_DESTROY消息,當(dāng)一個(gè)窗口即將被銷毀時(shí),被發(fā)送

4.OnNcDestroy()    消息響應(yīng)函數(shù),響應(yīng)WM_NCDESTROY消息,當(dāng)一個(gè)窗口銷毀以后被發(fā)送

5.PostNcDestroy()  重載函數(shù),作為處理OnNcDestroy()函數(shù)的最后動(dòng)作被CWnd調(diào)用

對(duì)于DoModal出來(lái)的窗口,可以使用默認(rèn)的OnOk()和OnCancel()來(lái)處理。其基類方法中會(huì)調(diào)用EndDialog()方法。


 最后注意一個(gè)問(wèn)題,通常我們創(chuàng)建一個(gè)非模態(tài)窗口時(shí),可能會(huì)這樣寫

{

   CDialog * pWnd = new CMyDialog();

   pWnd->Create(……);

   pWnd->ShowWindow(SW_SHOW);

}

   一般是在一個(gè)模塊或者一個(gè)函數(shù)中創(chuàng)建窗口,但是卻無(wú)法知道什么時(shí)候關(guān)閉窗口。而pWnd也只是作為一個(gè)局部變量。那么如何對(duì)它進(jìn)行析構(gòu)呢?

通常這樣是重載虛函數(shù)PostNcDestroy()來(lái)實(shí)現(xiàn)

void CMyDialog::PostNcDestroy()
{
       CDialog::PostNcDestroy();
       delete this;
}

 為什么把對(duì)話框類的delete this放在PostNcDestroy中而不是OnNcDestroy?

   這是因?yàn)镺nNcDestroy只被已建立的窗口調(diào)用。如果建立窗口失敗(如PreCreateWindow), 則沒(méi)有窗口處來(lái)發(fā)送







    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多