VC 模式對話框和非模式對話框的創建,銷燬和區別

在WIN32中,模式對話框的創建一般是使用DialogBox來進行創建的。而非模式對話框則是利用CreateWindow來創建的。在MFC或是WTL中,模式對話框一般是使用DoModal,而非模式對話框的創建則是使用Create。模式對話框創建後,程序的其他窗口便不能進行操作,必須將該窗口關閉後,其他窗口才能進行操作。而非模式對話框則無需這樣,它不強制要求用戶立即反應,而是與其他窗口同時接受用戶操作。
Create的Dialog一般是modalless,如果你的程序本身就是隻有一個Dialog,就無所謂了,看不出modalless的效果。modalless本來就是讓有機會切換到本程序的其他窗口。
非模態對話框的特點: 
與模態對話框不同,非模態對話框不壟斷用戶的輸入,用戶打開非模態對話框後,仍然可以與其它界面進行交互。 
非模態對話框的設計與模態對話框基本類似,也包括設計對話框模板和設計CDialog類的派生類兩部分。但是,在對話框的創建和刪除過程中,非模態對話框與模態對話框相比有下列不同之處: 
非模態對話框的模板必須具有Visible風格,否則對話框將不可見,而模態對話框則無需設置該項風格。更保險的辦法是調用CWnd::ShowWindow(SW_SHOW)來顯示對話框,而不管對話框是否具有Visible風格。 
非模態對話框對象是用new操作符在堆中動態創建的,而不是以成員變量的形式嵌入到別的對象中或以局部變量的形式構建在堆棧上。通常應在對話框的擁有者窗口類內聲明一個指向對話框類的指針成員變量,通過該指針可訪問對話框對象。 
通過調用CDialog::Create函數來啓動對話框,而不是CDialog::DoModal,這是模態對話框的關鍵所在。由於Create函數不會啓動新的消息循環,對話框與應用程序共用同一個消息循環,這樣對話框就不會壟斷用戶的輸入。Create在顯示了對話框後就立即返回,而DoModal是在對話框被關閉後才返回的。衆所周知,在MFC程序中,窗口對象的生存期應長於對應的窗口,也就是說,不能在未關閉屏幕上窗口的情況下先把對應的窗口對象刪除掉。由於在Create返回後,不能確定對話框是否已關閉,這樣也就無法確定對話框對象的生存期,因此只好在堆中構建對話框對象,而不能以局部變量的形式來構建之。 
必須調用CWnd::DestroyWindow而不是CDialog::EndDialog來關閉非模態對話框。調用CWnd::DestroyWindow是直接刪除窗口的一般方法。由於缺省的CDialog::OnOK和CDialog::OnCancel函數均調用EndDialog,故程序員必須編寫自己的OnOK和OnCancel函數並且在函數中調用DestroyWindow來關閉對話框。 
因爲是用new操作符構建非模態對話框對象,因此必須在對話框關閉後,用delete操作符刪除對話框對象。在屏幕上一個窗口被刪除後,框架會調用CWnd::PostNcDestroy,這是一個虛擬函數,程序可以在該函數中完成刪除窗口對象的工作,具體代碼如下
void CModelessDialog::PostNcDestroy
{
delete this; //刪除對象本身
}
這樣,在刪除屏幕上的對話框後,對話框對象將被自動刪除。擁有者對象就不必顯式的調用delete來刪除對話框對象了。 
必須有一個標誌表明非模態對話框是否是打開的。這樣做的原因是用戶有可能在打開一個模態對話框的情況下,又一次選擇打開命令。程序根據標誌來決定是打開一個新的對話框,還是僅僅把原來打開的對話框激活。通常可以用擁有者窗口中的指向對話框對象的指針作爲這種標誌,當對話框關閉時,給該指針賦NULL值,以表明對話框對象已不存在了。 
提示:在C++編程中,判斷一個位於堆中的對象是否存在的常用方法是判斷指向該對象的指針是否爲空。這種機制要求程序員將指向該對象的指針初始化爲NULL值,在創建對象時將返回的地址賦給該指針,而在刪除對象時將該指針置成NULL值。  
根據上面的分析,我們很容易把Register程序中的登錄數據對話框改成非模態對話框。這樣做的好處在於如果用戶在輸入數據時發現編輯視圖中有錯誤的數據,那麼不必關閉對話框,就可以在編輯視圖中進行修改。 
窗口對象的自動清除: 
一個MFC窗口對象包括兩方面的內容:一是窗口對象封裝的窗口,即存放在m_hWnd成員中的HWND(窗口句柄),二是窗口對象本身是一個C++對象。要刪除一個MFC窗口對象,應
該先刪除窗口對象封裝的窗口,然後刪除窗口對象本身。 
刪除窗口最直接方法是調用CWnd::DestroyWindow或::DestroyWindow,前者封裝了後者的功能。前者不僅會調用後者,而且會使成員m_hWnd保存的HWND無效(NULL)。如果DestroyWindow刪除的是一個父窗口或擁有者窗口,則該函數會先自動刪除所有的子窗口或被擁有者,然後再刪除父窗口或擁有者。在一般情況下,在程序中不必直接調用DestroyWindow來刪除窗口,因爲MFC會自動調用DestroyWindow來刪除窗口。例如,當用戶退出應用程序時,會產生WM_CLOSE消息,該消息會導致MFC自動調用CWnd::DestroyWindow來刪除主框架窗口,當用戶在對話框內按了OK或Cancel按鈕時,MFC會自動調用CWnd::DestroyWindow來刪除對話框及其控件。 
窗口對象本身的刪除則根據對象創建方式的不同,分爲兩種情況。在MFC編程中,會使用大量的窗口對象,有些窗口對象以變量的形式嵌入在別的對象內或以局部變量的形式創建在堆棧上,有些則用new操作符創建在堆中。對於一個以變量形式創建的窗口對象,程序員不必關心它的刪除問題,因爲該對象的生命期總是有限的,若該對象是某個對象的成員變量,它會隨着父對象的消失而消失,若該對象是一個局部變量,那麼它會在函數返回時被清除。 
對於一個在堆中動態創建的窗口對象,其生命期卻是任意長的。初學者在學習C++編程時,對new操作符的使用往往不太踏實,因爲用new在堆中創建對象,就不能忘記用delete刪除對象。讀者在學習MFC的例程時,可能會產生這樣的疑問,爲什麼有些程序用new創建了一個窗口對象,卻未顯式的用delete來刪除它呢?問題的答案就是有些MFC窗口對象具有自動清除的功能。 
如前面講述非模態對話框時所提到的,當調用CWnd::DestroyWindow或::DestroyWindow刪除一個窗口時,被刪除窗口的PostNcDestroy成員函數會被調用。缺省的PostNcDestroy什麼也不幹,但有些MFC窗口類會覆蓋該函數並在新版本的PostNcDestroy中調用delete this來刪除對象,從而具有了自動清除的功能。此類窗口對象通常是用new操作符創建在堆中的,但程序員不必操心用delete操作符去刪除它們,因爲一旦調用DestroyWindow刪除窗口,對應的窗口對象也會緊接着被刪除。 
不具有自動清除功能的窗口類如下所示。這些窗口對象通常是以變量的形式創建的,無需自動清除功能。 
所有標準的Windows控件類。 
從CWnd類直接派生出來的子窗口對象(如用戶定製的控件)。 
切分窗口類CSplitterWnd。 
缺省的控制條類(包括工具條、狀態條和對話條)。 
模態對話框類。 
具有自動清除功能的窗口類如下所示,這些窗口對象通常是在堆中創建的。 
主框架窗口類(直接或間接從CFrameWnd類派生)。 
視圖類(直接或間接從CView類派生)。 
 
讀者在設計自己的派生窗口類時,可根據窗口對象的創建方法來決定是否將窗口類設計成可以自動清除的。例如,對於一個非模態對話框來說,其對象是創建在堆中的,因此應該具有自動清除功能。 
綜上所述,對於MFC窗口類及其派生類來說,在程序中一般不必顯式刪除窗口對象。也就是說,既不必調用DestroyWindow來刪除窗口對象封裝的窗口,也不必顯式地用delete操作符來刪除窗口對象本身。只要保證非自動清除的窗口對象是以變量的形式創建的,自動清除的窗口對象是在堆中創建的,MFC的運行機制就可以保證窗口對象的徹底刪除。 
如果需要手工刪除窗口對象,則應該先調用相應的函數(CWnd::DestroyWindow)刪除窗口,然後再刪除窗口對象.對於以變量形式創建的窗口對象,窗口對象的刪除是框架自動完成的.對於在堆中動態創建了的非自動清除的窗口對象,必須在窗口被刪除後,顯式地調用delete來刪除對象(一般在擁有者或父窗口的析構函數中進行).對於具有自動清除功能的窗口對象,只需調用CWnd::DestroyWindow即可刪除窗口和窗口對象。注意,對於在堆中創建的窗口對象,不要在窗口還未關閉的情況下就用delete操作符來刪除窗口對象. 
提示:在非模態對話框的OnCancel函數中可以不調用CWnd::DestroyWindow,取而代之的是調用CWnd::ShowWindow(SW_HIDE)來隱藏對話框.在下次打開對話框時就不必調用Create了,只需調用CWnd::ShowWindow(SW_SHOW)來顯示對話框.這樣做的好處在於對話框中的數據可以保存下來,供以後使用.由於擁有者窗口在被關閉時會調用DestroyWindow刪除每一個所屬窗口,故只要非模態對話框是自動清除的,程序員就不必擔心對話框對象的刪除問題.  
以下是一點資料供參考,非模態對話框的銷燬順序:
MFC應用程序中處理消息的順序
1.AfxWndProc() 該函數負責接收消息,找到消息所屬的CWnd對象,然後調用AfxCallWndProc
2.AfxCallWndProc() 該函數負責保存消息(保存的內容主要是消息標識符和消息參數)供應用程序以後使用,
然後調用WindowProc()函數
3.WindowProc() 該函數負責發送消息到OnWndMsg()函數,如果未被處理,則調用DefWindowProc()函數
4.OnWndMsg() 該函數的功能首先按字節對消息進行排序,對於WM_COMMAND消息,調用OnCommand()消息
響應函數,對於WM_NOTIFY消息
調用OnNotify()消息響應函數。任何被遺漏的消息將是一個窗口消息。OnWndMsg()函數搜
索類的消息映像,以找到一個
能處理任何窗口消息的處理函數。如果OnWndMsg()函數不能找到這樣的處理函數的話,則
把消息返回到WindowProc()函數,由它將消息發送給DefWindowProc()函數
5.OnCommand() 該函數查看這是不是一個控件通知(lParam參數不爲NULL,如果lParam參數爲空的話,說明
該消息不是控件通知),如果它是,OnCommand()函數會試圖將消息映射到製造通知的控件;
如果他不是一個控件通知(或者如果控件拒絕映射的消息)OnCommand()就會調用OnCmdMsg()函數
6.OnCmdMsg() 根據接收消息的類,OnCmdMsg()函數將在一個稱爲命令傳遞(Command Routing)的過程中潛在的
傳遞命令消息和控件通知。
例如:如果擁有該窗口的類是一個框架類,則命令和通知消息也被傳遞到視圖和文檔類,併爲該
類尋找一個消息處理函數
MFC應用程序創建窗口的過程
1.PreCreateWindow() 該函數是一個重載函數,在窗口被創建前,可以在該重載函數中改變創建參數
(可以設置窗口風格等等)
2.PreSubclassWindow() 這也是一個重載函數,允許首先子分類一個窗口
3.OnGetMinMaxInfo() 該函數爲消息響應函數,響應的是WM_GETMINMAXINFO消息,允許設置窗口的最大或者
最小尺寸
4.OnNcCreate() 該函數也是一個消息響應函數,響應WM_NCCreate消息,發送消息以告訴窗口的客戶區
即將被創建
5.OnNcCalcSize() 該函數也是消息響應函數,響應WM_NCCALCSIZE消息,作用是允許改變窗口客戶區大小
6.OnCreate() 該函數也是一個消息響應函數,響應WM_Create消息,發送消息告訴一個窗口已經被創建
7.OnSize() 該函數也是一個消息響應函數,響應WM_SIZE消息,發送該消息以告訴該窗口大小已經
發生變化
8.OnMove() 消息響應函數,響應WM_MOVE消息,發送此消息說明窗口在移動
9.OnChildNotify() 該函數爲重載函數,作爲部分消息映射被調用,告訴父窗口即將被告知一個窗口剛剛被
創建
MFC應用程序關閉窗口的順序(非模態窗口)
1.OnClose() 消息響應函數,響應窗口的WM_CLOSE消息,當關閉按鈕被單擊的時候發送此消息
2.OnDestroy() 消息響應函數,響應窗口的WM_DESTROY消息,當一個窗口將被銷燬時,發送此消息
3.OnNcDestroy() 消息響應函數,響應窗口的WM_NCDESTROY消息,當一個窗口被銷燬後發送此消息
4.PostNcDestroy() 重載函數,作爲處理OnNcDestroy()函數的最後動作,被CWnd調用
MFC應用程序中打開模式對話框的函數調用順序
1.DoModal() 重載函數,重載DoModal()成員函數
2.PreSubclassWindow() 重載函數,允許首先子分類一個窗口
3.OnCreate() 消息響應函數,響應WM_Create消息,發送此消息以告訴一個窗口已經被創建
4.OnSize() 消息響應函數,響應WM_SIZE消息,發送此消息以告訴窗口大小發生變化
5.OnMove() 消息響應函數,響應WM_MOVE消息,發送此消息,以告訴窗口正在移動
6.OnSetFont() 消息響應函數,響應WM_SETFONT消息,發送此消息,以允許改變對話框中控件的字體
7.OnInitDialog() 消息響應函數,響應WM_INITDIALOG消息,發送此消息以允許初始化對話框中的控件,
或者是創建新控件
8.OnShowWindow() 消息響應函數,響應WM_SHOWWINDOW消息,該函數被ShowWindow()函數調用
9.OnCtlColor() 消息響應函數,響應WM_CTLCOLOR消息,被父窗口發送已改變對話框或對話框上面控件
的顏色
10. OnChildNotify() 重載函數,作爲WM_CTLCOLOR消息的結果發送

MFC應用程序中關閉模式對話框的順序
1.OnClose() 消息響應函數,響應WM_CLOSE消息,當"關閉"按鈕被單擊的時候,該函數被調用
2.OnKillFocus() 消息響應函數,響應WM_KILLFOCUS消息,當一個窗口即將失去鍵盤輸入焦點以前被髮送
3.OnDestroy() 消息響應函數,響應WM_DESTROY消息,當一個窗口即將被銷燬時,被髮送
4.OnNcDestroy() 消息響應函數,響應WM_NCDESTROY消息,當一個窗口被銷燬以後被髮送
5.PostNcDestroy() 重載函數,作爲處理OnNcDestroy()函數的最後動作被CWnd調用
打開無模式對話框的順序
1.PreSubclassWindow() 重載函數,允許用戶首先子分類一個窗口
2.OnCreate() 消息響應函數,響應WM_Create消息,發送此消息以告訴一個窗口已經被創建
3.OnSize() 消息響應函數,響應WM_SIZE消息,發送此消息以告訴窗口大小發生變化
4.OnMove() 消息響應函數,響應WM_MOVE消息,發送此消息以告訴窗口正在移動
5.OnSetFont() 消息響應函數,響應WM_SETFONT消息,發送此消息以允許改變對話框中控件的字體
MSDN.原文說明:
CWnd::DestroyWindow See Also
CWnd Overview | Class Members | Hierarchy Chart | CWnd::OnDestroy | CWnd::Detach | DestroyWindowDestroys the Windows window attached to the CWnd object.
virtual BOOL DestroyWindow( );
Return Value
Nonzero if the window is destroyed; otherwise 0.
Remarks
The DestroyWindow member function sends appropriate messages to the window to deactivate it and remove the input focus. It also destroys the window's menu, flushes the
application queue, destroys outstanding timers, removes Clipboard ownership, and breaks the Clipboard-viewer chain if CWnd is at the top of the viewer chain. It sends
WM_DESTROY and WM_NCDESTROY messages to the window. It does not destroy the CWnd object.
DestroyWindow is a place holder for performing cleanup. Because DestroyWindow is a virtual function, it is shown in any CWnd-derived class in Class View. But even if you override
this function in your CWnd-derived class, DestroyWindow is not necessarily called. If DestroyWindow is not called in the MFC code, then you have to explicitly call it in your own code if
you want it to be called.
Assume, for example, you have overridden DestroyWindow in a CView-derived class. Since MFC source code does not call DestroyWindow in any of its CFrameWnd-derived classes,
your overridden DestroyWindow will not be called unless you call it explicitly.
If the window is the parent of any windows, these child windows are automatically destroyed when the parent window is destroyed. The DestroyWindow member function destroys
child windows first and then the window itself.
The DestroyWindow member function also destroys modeless dialog boxes created by CDialog::Create.
If the CWnd being destroyed is a child window and does not have the WS_EX_NOPARENTNOTIFY style set, then the WM_PARENTNOTIFY message is sent to the parent.
Example
// CModeless is CDialog class representing a modeless dialog
// Destruction of the modeless dialog involves calling DestroyWindow in
// OnOK() & OnCancel() handlers
void CModeless::OnOK()
{
if (!UpdateData(TRUE))
{
TRACE0("UpdateData failed during dialog termination/n");
// The UpdateData routine will set focus to correct item
return;
}
DestroyWindow();
}
void CModeless::OnCancel()
{
DestroyWindow();
}
非模態對話框相對於模態對話框,他的創建和銷燬過程和模態對話框有一定的區別 
先看一下MSDN的原文:
When you implement a modeless dialog box, always override the OnCancel member function and call DestroyWindow from within it. Don’t call the base class
CDialog::OnCancel, because it calls EndDialog, which will make the dialog box invisible but will not destroy it. You should also override PostNcDestroy for
modeless dialog boxes in order to delete this, since modeless dialog boxes are usually allocated with new. Modal dialog boxes are usually constructed on
the frame and do not need PostNcDestroy cleanup.
MS的指示:非模態對話框需要重載函數OnCanel,並且在這個函數中調用DestroyWindow。並且不能調用基類的OnCancel,因爲基類的OnCancel調用了EndDialog這個函數,這個函數是
針對模態對話框的。
還有一個必須重載的函數就是PostNcDestroy,這也是一個虛函數,通常的非模態對話框是用類的指針,通過new創建的,這就需要在PostNcDestroy函數中delete掉這個指針。
模式對話框會和非模式對話框在運行原理上有一定的差別。
下面是創建模式對話框和非模式對話框的幾段代碼,可以比較其中的不同之處:
void CMainWindow::OnModel() // 用戶點擊“Model Dialog”按鈕
{
CMyDialog dlg(this);
// 顯示模式對話框
dlg.DoModal();
}
void CMainWindow::OnModeless() // 用戶點擊“Modeless Dialo”按鈕
{
CMyDialog* pDlg = new CMyDialog(this);
pDlg->m_bModeless = TRUE;
// 創建無模式對話框
pDlg->Create(IDD_MYDIALOG);
// 移動窗口到主窗口的中央
pDlg->CenterWindow();
// 顯示更新窗口
pDlg->ShowWindow(SW_NORMAL);
pDlg->UpdateWindow();
}
void CMyDialog::OnCancel() // 用戶關閉對話框
{
if(m_bModeless)
DestroyWindow();
else
CDialog::OnCancel();
}
void CMyDialog::PostNcDestroy()
{
if(m_bModeless) //這麼做可以使模式對話框不調用PostNcDestroy,因爲它的實例會自動刪除
delete this;
}
其中OnModel是對彈出模式對話框的按鈕的函數響應,OnModeless是對彈出非模式對話框的按鈕的函數響應,從代碼可以看到兩者創建的方法不一樣。由於創建模式對話框的方法比較
簡潔,可想而知,CMyDialog類默認是創建模式對話框的。
再來看下面兩個CMyDialog重載的函數OnCancel和PostNcDestroy,爲什麼要重載這兩個函數呢?這得從兩種對話框的運行原理來分析。
模式對話框在關閉之前不允許用戶切換到主窗口。模式對話框使得消息循環限制在對話框內,而不會流向主窗口,所以對主窗口的任何操作都是無效的。這樣就類似於在主窗口消息循
環裏內嵌了一個屬於對話框的消息循環(不知道這樣的描述是否恰當),有點函數機制的味道。事實上,模式對話框實例(對象)就是在函數堆棧中申請的,這樣在對話框窗口銷燬時就用
不着刪除自己了。因爲函數機制的作用本身就是這樣的。
下面來澄清一下對話框窗口銷燬和對話框實例銷燬的區別。一個對話框如果要銷燬,要做兩個步驟,先是要銷燬對話框窗口,這是由OnCancel函數來完成的;然後是銷燬對話框實例,
這是由PostNcDestroy函數來完成的。所以,如果是單單創建模式對話框,就不需要在CMyDialog中重載OnCancel和PostNcDestroy了,用CDialog中的就行了(況且模式對話框根本就不需
要PostNcDestroy函數)。但是,如果是創建非模式對話框就不同了,CDialog::Create會立即返回,進入普通的循環,即主窗口循環,不像模式對話框的DoModel函數要到對話框窗口關
閉之後才返回,其內部有消息循環。所以,非模式對話框實例要像主窗口實例一樣在進程堆中申請,實例銷燬時也要調用PostNcDestroy函數。
void CMyDialog::OnCancel() // 用戶關閉對話框
{
if(m_bModeless) //如果是非模式對話框,就不能在內置循環中調用OnCancel函數,因爲
DestroyWindow(); //那麼做了,程序可能會把消息發送給主窗口,那麼關閉的就是主窗口
else //了,就不能關閉對話框了
CDialog::OnCancel();
}
消息響應的區別
在消息響應方面,模式對話框和非模式對話框之間又有着很大的區別。模式對話框工作的時候,它有內部的消息泵機制,控件之間的交互不用我們人爲的去控制,系統會幫助我們去處理。
非模式對話框則像普通窗口一樣,則由WinMain中書寫的消息循環驅動。但由於是對話框,它對一些消息有特殊的處理。因此,在消息循環中,需要先對對話框提供截獲消息的機會。
While (GetMessage(&msg, NULL, 0, 0))
{
if (hDlgModeless == 0 || !IsDialogMessage(hDlgModeless, &msg))
{
TranslateMessage(&msg);
DispatchMessage( &msg);
}
}
如果當前取得的消息是對話框的消息,IsDialogMessage 將它交由對話消息處理函數處理,並返回TRUE。不需要再派發了。
注意:這個方法並不是很好用,因爲當對話框過多的時候,處理起來就比較麻煩了。另一種處理的方法是利用子類化控件的方法,來處理控件間的交互。
銷燬的區別
模式對話框的銷燬是使用EndDialog,而非模式對話框的銷燬是使用DestroyWindow.。所以我們在銷燬對話框的時候,也要對其進行區別。
非模式對話框,用戶關閉對話框時,對話框消息處理函數將收到WM_CLOSE消息,接到後調用DestroyWindow以銷燬非模式對話框。
模式對話框,則一般響應IDOK和IDCANCEL。在PPC上,我們對於OK鍵和X鍵的處理要注意這點。
其他
非模態對話框的模板必須具有Visible風格,否則對話框將不可見,而模態對話框則無需設置該項風格。更保險的辦法是調用ShowWindow(hDialog, SW_SHOW)來顯示對話框,而不管對話
框是否具有Visible風格。 
非模態對話框對象是用new操作符在堆中動態創建的,而不是以成員變量的形式嵌入到別的對象中或以局部變量的形式構建在堆棧上。通常應在對話框的擁有者窗口類內聲明一個指向對話框
類的指針成員變量,通過該指針可訪問對話框對象。
通過調用Create函數來啓動對話框,而不是DoModal,這是模態對話框的關鍵所在。由於Create函數不會啓動新的消息循環,對話框與應用程序共用同一個消息循環,這樣對話框就不會壟
斷用戶的輸入。Create在顯示了對話框後就立即返回,而DoModal是在對話框被關閉後才返回的。衆所周知,在MFC程序中,窗口對象的生存期應長於對應的窗口,也就是說,不能在未關
閉屏幕上窗口的情況下先把對應的窗口對象刪除掉。由於在Create返回後,不能確定對話框是否已關閉,這樣也就無法確定對話框對象的生存期,因此只好在堆中構建對話框對象,而不能
以局部變量的形式來構建之。
因爲是用new操作符構建非模態對話框對象,因此必須在對話框關閉後,用delete操作符刪除對話框對象。
必須有一個標誌表明非模態對話框是否是打開的。這樣做的原因是用戶有可能在打開一個模態對話框的情況下,又一次選擇打開命令。程序根據 標誌來決定是打開一個新的對話框,還是僅
僅把原來打開的對話框激活。通常可以用擁有者窗口中的指向對話框對象的指針作爲這種標誌,當對話框關閉時,給該指 針賦NULL值,以表明對話框對象已不存在了。
注意:在C++編程中,判斷一個位於堆中的對象是否存在的常用方法是判斷指向該對象的指針是否爲空。這種機制要求程序員將指向該對象的指針初始化爲NULL值,在創建對象時將返回的
地址賦給該指針,而在刪除對象時將該指針置成NULL值。
使用總結:非模式對話框在調用退出函數時,可以先發消息給主窗口,通知它我退出了,可以清空改窗口的指針。再調用DestroyWindow。具體如下:
void CChart::OnOK() //非模式對話框退出按鈕處理函數
{
 // TODO: Add extra validation here
 
 ::SendMessage(GetParent()->m_hWnd,WM_MY_CHART,0,0);//通知主窗口該窗口退出,進行相關清理工作
 DestroyWindow();//注意發送消息必須在銷燬窗口之前,因爲發送消息必須要依賴窗口。
 // CDialog::OnOK();//這個是關閉模式對話框的方法,它調用::EndDialog 
//關閉非模式對話框必須採用通用方法就是DestroyWindow()(發送的是WM_DESTROY 消息)
}
void CChart::PostNcDestroy() //非模式對話框退出通知函數
{
 // TODO: Add your specialized code here and/or call the base class
 delete this;//窗口關閉,銷燬相關資源。
 CDialog::PostNcDestroy();
}
//主窗口收到消息後,可以處理它的指針。
// TODO: 處理用戶自定義消息
 if(lParam==0)//圖表m_chart窗口關閉
 {
 // delete m_chart;//注意在此處不能銷它的毀資源,因爲窗口還沒有關閉。
  m_chart = NULL;//只是通知父窗口,把指針清空。
  return 0L;
 }
一定要理解和注意順序關係。
http://blog.csdn.net/mycaibo
發佈了41 篇原創文章 · 獲贊 13 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章