MFC模态对话框和非模态对话框
下面是一個我的手寫的模態對話框和非模態對話框圖:
模態對話框是指當其顯示時,程序會暫停執行,直到關閉這個模態對話框后,才能繼續執行程序中其他任務。非模態對話框是指當其顯示時,允許轉而執行程序中其他任務,而不用關閉這個對話框。?
????模態對話框的創建:創建模態對話框需要調用CDialog類的成員函數:DoModal,該函數的功能是創建并顯示一個模態對話框,其返回值將作為CDialog類的另一個成員函數:EndDialog的參數,后者的功能是關閉模態對話框。一般顯示模態對話框的實現代碼如下:
void CASCEView::OnDialog()
{
???????? CASCEDlg dlg;
???????? dlg.DoModal();
}?
非模態對話框的創建:要創建非模態對話框就需要利用CDialog類的Create成員函數,該函數有以下兩種形式的聲明:
virtual BOOL Create(
?? LPCTSTR lpszTemplateName,
?? CWnd* pParentWnd = NULL
);
virtual BOOL Create(
?? UINT nIDTemplate,
?? CWnd* pParentWnd = NULL
);?
??? 由上可知,CDialog::Create函數的第一個參數可以是對話框資源的ID(nIDTemplate),或者也可以是對話框模板的名稱(lpszTemplateName);而第二個參數指定了對話框的父窗口,如果其值是NULL,則對話框的父窗口就是主應用程序窗口。
????當利用Create函數創建非模態對話框時,我們還需要接著調用ShowWindow函數來將這個對話框顯示出來;而利用DoModal創建的模態對話框之所以不用,是因為DoModal函數本身就有顯示模態對話框的作用。同時我們不能像模態對話框那樣將對話框定義成對象,如下代碼是顯示不出非模態對話框的:
void CASCEView::OnDialog()
{
???????? CASCEDlg dlg;
???????? dlg.Create(IDD_DIALOG1, this);
???????? dlg.ShowWindow(SW_SHOW);
}?
????因為這里創建的非模態對話框對象dlg是一個局部對象,當程序執行時,會依次執行各條代碼,當OnDialog函數執行結束時,dlg這個對象的生命周期也就玩玩了,它就會銷毀與之相關聯的對話框資源,對話框自然就顯示不出來啦!而模態對話框之所以能夠顯示,是因為當執行到調用DoModal函數以顯示模態對話框時,程序就會暫停執行,直到模態對話框關閉之后,程序才繼續向下執行。而這之前,dlg還沒銷毀。
??? 因此,在創建非模態對話框時,不能將對話框對象定義成局部變量,解決方法有二:一是把對話框對象定義成CASCEView類的成員變量;二是把它定義成指針,在堆上分配內存,如下:
void CASCEView::OnDialog()
{
???????? CASCEDlg *pDlg = new CASCEDlg;
???????? pDlg->Create(IDD_DIALOG1, this);
???????? pDlg->ShowWindow(SW_SHOW);
}?
??? 但是這又引入了新的問題:我們必須釋放pDlg占用的資源,否則會造成內存泄漏!況且這里pDlg還是一個局部指針變量,當它的生命周期結束時,在程序中就無法再引用它所指向的那塊內存了。解決方法同樣有兩個:一是將pDlg定義成CASCEView類的成員變量,然后在CASCEView類的析構函數中調用delete函數釋放它指向的內存;二是在CASCEDlg類中重載PostNcDestroy虛函數,釋放this指針指向的內存:
void CASCEDlg::PostNcDestroy()
{
???????? delete this;
???????? CDialog::PostNcDestroy();
}?
????還有一點需要注意的是:當單擊對話框上的默認OK按鈕時,兩種對話框都會消失。但對于模態對話框而言,此時對話框窗口對象被銷毀了;而對非模態對話框來說,對話框窗口對象并未被銷毀,只是隱藏起來而已。?
??? 在非模態對話框中單擊OK按鈕后,程序會調用基類CDialog的OnOK函數,這是一個虛函數,后者又會調用EndDialog函數,這個函數用于終止模態對話框,但對于非模態對話框,這個函數只是使對話框窗口不可見,并不銷毀它。因此,對非模態對話框來說,如果有一個ID值為IDOK的按鈕,就必須重寫基類的OnOK虛函數,并在重寫的函數中調用DestroyWindow函數,以完成銷毀對話框的工作,同時注意不要再調用基類的OnOK函數。同理,如果非模態對話框中有一個ID值為IDCANCEL的按鈕,也必須重寫基類的OnCancel虛函數,并在重寫的函數中調用DestroyWindow函數,銷毀對話框,同時注意不要再調用基類的OnCancel函數了。?
???? 非模態對話框相對于模態對話框,他的創建和銷毀過程和模態對話框有一定的區別
先看一下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掉這個指針。?
了解了理論過后,下面我們就可以用代碼實現一下非模態對話框的創建和銷毀過程:
//建立
//主框架中:
CTestDlg *pDlg=new CTestDlg;
pDlg->Create(IDD_TESTDLG,this);
pDlg->ShowWindow(SW_SHOW);?
//對話框中:
void CTestDlg::OnCancel()
{
???? DestroyWindow();
}
void CTestDlg::PostNcDestroy()
{
???? CDialog::PostNcDestroy();
???? delete this;
}?
如果要在點擊按鈕的情況下,銷毀非模態對話框,只需要把按鈕的事件映射到OnCancel函數即可。
以下是一點資料供參考:?
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消息,發送此消息以允許改變對話框中控件的字體?
以上這些的執行都是按給定的順序執行!
總結
以上是生活随笔為你收集整理的MFC模态对话框和非模态对话框的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搭建校园网(组网工程课设)
- 下一篇: 中国人为什么精于计算而输于思维?