MFC模态对话框和非模态对话框
下面是一個(gè)我的手寫的模態(tài)對(duì)話框和非模態(tài)對(duì)話框圖:
模態(tài)對(duì)話框是指當(dāng)其顯示時(shí),程序會(huì)暫停執(zhí)行,直到關(guān)閉這個(gè)模態(tài)對(duì)話框后,才能繼續(xù)執(zhí)行程序中其他任務(wù)。非模態(tài)對(duì)話框是指當(dāng)其顯示時(shí),允許轉(zhuǎn)而執(zhí)行程序中其他任務(wù),而不用關(guān)閉這個(gè)對(duì)話框。?
????模態(tài)對(duì)話框的創(chuàng)建:創(chuàng)建模態(tài)對(duì)話框需要調(diào)用CDialog類的成員函數(shù):DoModal,該函數(shù)的功能是創(chuàng)建并顯示一個(gè)模態(tài)對(duì)話框,其返回值將作為CDialog類的另一個(gè)成員函數(shù):EndDialog的參數(shù),后者的功能是關(guān)閉模態(tài)對(duì)話框。一般顯示模態(tài)對(duì)話框的實(shí)現(xiàn)代碼如下:
void CASCEView::OnDialog()
{
???????? CASCEDlg dlg;
???????? dlg.DoModal();
}?
非模態(tài)對(duì)話框的創(chuàng)建:要?jiǎng)?chuàng)建非模態(tài)對(duì)話框就需要利用CDialog類的Create成員函數(shù),該函數(shù)有以下兩種形式的聲明:
virtual BOOL Create(
?? LPCTSTR lpszTemplateName,
?? CWnd* pParentWnd = NULL
);
virtual BOOL Create(
?? UINT nIDTemplate,
?? CWnd* pParentWnd = NULL
);?
??? 由上可知,CDialog::Create函數(shù)的第一個(gè)參數(shù)可以是對(duì)話框資源的ID(nIDTemplate),或者也可以是對(duì)話框模板的名稱(lpszTemplateName);而第二個(gè)參數(shù)指定了對(duì)話框的父窗口,如果其值是NULL,則對(duì)話框的父窗口就是主應(yīng)用程序窗口。
????當(dāng)利用Create函數(shù)創(chuàng)建非模態(tài)對(duì)話框時(shí),我們還需要接著調(diào)用ShowWindow函數(shù)來將這個(gè)對(duì)話框顯示出來;而利用DoModal創(chuàng)建的模態(tài)對(duì)話框之所以不用,是因?yàn)镈oModal函數(shù)本身就有顯示模態(tài)對(duì)話框的作用。同時(shí)我們不能像模態(tài)對(duì)話框那樣將對(duì)話框定義成對(duì)象,如下代碼是顯示不出非模態(tài)對(duì)話框的:
void CASCEView::OnDialog()
{
???????? CASCEDlg dlg;
???????? dlg.Create(IDD_DIALOG1, this);
???????? dlg.ShowWindow(SW_SHOW);
}?
????因?yàn)檫@里創(chuàng)建的非模態(tài)對(duì)話框?qū)ο骴lg是一個(gè)局部對(duì)象,當(dāng)程序執(zhí)行時(shí),會(huì)依次執(zhí)行各條代碼,當(dāng)OnDialog函數(shù)執(zhí)行結(jié)束時(shí),dlg這個(gè)對(duì)象的生命周期也就玩玩了,它就會(huì)銷毀與之相關(guān)聯(lián)的對(duì)話框資源,對(duì)話框自然就顯示不出來啦!而模態(tài)對(duì)話框之所以能夠顯示,是因?yàn)楫?dāng)執(zhí)行到調(diào)用DoModal函數(shù)以顯示模態(tài)對(duì)話框時(shí),程序就會(huì)暫停執(zhí)行,直到模態(tài)對(duì)話框關(guān)閉之后,程序才繼續(xù)向下執(zhí)行。而這之前,dlg還沒銷毀。
??? 因此,在創(chuàng)建非模態(tài)對(duì)話框時(shí),不能將對(duì)話框?qū)ο蠖x成局部變量,解決方法有二:一是把對(duì)話框?qū)ο蠖x成CASCEView類的成員變量;二是把它定義成指針,在堆上分配內(nèi)存,如下:
void CASCEView::OnDialog()
{
???????? CASCEDlg *pDlg = new CASCEDlg;
???????? pDlg->Create(IDD_DIALOG1, this);
???????? pDlg->ShowWindow(SW_SHOW);
}?
??? 但是這又引入了新的問題:我們必須釋放pDlg占用的資源,否則會(huì)造成內(nèi)存泄漏!況且這里pDlg還是一個(gè)局部指針變量,當(dāng)它的生命周期結(jié)束時(shí),在程序中就無法再引用它所指向的那塊內(nèi)存了。解決方法同樣有兩個(gè):一是將pDlg定義成CASCEView類的成員變量,然后在CASCEView類的析構(gòu)函數(shù)中調(diào)用delete函數(shù)釋放它指向的內(nèi)存;二是在CASCEDlg類中重載PostNcDestroy虛函數(shù),釋放this指針指向的內(nèi)存:
void CASCEDlg::PostNcDestroy()
{
???????? delete this;
???????? CDialog::PostNcDestroy();
}?
????還有一點(diǎn)需要注意的是:當(dāng)單擊對(duì)話框上的默認(rèn)OK按鈕時(shí),兩種對(duì)話框都會(huì)消失。但對(duì)于模態(tài)對(duì)話框而言,此時(shí)對(duì)話框窗口對(duì)象被銷毀了;而對(duì)非模態(tài)對(duì)話框來說,對(duì)話框窗口對(duì)象并未被銷毀,只是隱藏起來而已。?
??? 在非模態(tài)對(duì)話框中單擊OK按鈕后,程序會(huì)調(diào)用基類CDialog的OnOK函數(shù),這是一個(gè)虛函數(shù),后者又會(huì)調(diào)用EndDialog函數(shù),這個(gè)函數(shù)用于終止模態(tài)對(duì)話框,但對(duì)于非模態(tài)對(duì)話框,這個(gè)函數(shù)只是使對(duì)話框窗口不可見,并不銷毀它。因此,對(duì)非模態(tài)對(duì)話框來說,如果有一個(gè)ID值為IDOK的按鈕,就必須重寫基類的OnOK虛函數(shù),并在重寫的函數(shù)中調(diào)用DestroyWindow函數(shù),以完成銷毀對(duì)話框的工作,同時(shí)注意不要再調(diào)用基類的OnOK函數(shù)。同理,如果非模態(tài)對(duì)話框中有一個(gè)ID值為IDCANCEL的按鈕,也必須重寫基類的OnCancel虛函數(shù),并在重寫的函數(shù)中調(diào)用DestroyWindow函數(shù),銷毀對(duì)話框,同時(shí)注意不要再調(diào)用基類的OnCancel函數(shù)了。?
???? 非模態(tài)對(duì)話框相對(duì)于模態(tài)對(duì)話框,他的創(chuàng)建和銷毀過程和模態(tài)對(duì)話框有一定的區(qū)別
先看一下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的指示:非模態(tài)對(duì)話框需要重載函數(shù)OnCanel,并且在這個(gè)函數(shù)中調(diào)用DestroyWindow。并且不能調(diào)用基類的OnCancel,因?yàn)榛惖腛nCancel調(diào)用了EndDialog這個(gè)函數(shù),這個(gè)函數(shù)是針對(duì)模態(tài)對(duì)話框的。
還有一個(gè)必須重載的函數(shù)就是PostNcDestroy,這也是一個(gè)虛函數(shù),通常的非模態(tài)對(duì)話框是用類的指針,通過new創(chuàng)建的,這就需要在PostNcDestroy函數(shù)中delete掉這個(gè)指針。?
了解了理論過后,下面我們就可以用代碼實(shí)現(xiàn)一下非模態(tài)對(duì)話框的創(chuàng)建和銷毀過程:
//建立
//主框架中:
CTestDlg *pDlg=new CTestDlg;
pDlg->Create(IDD_TESTDLG,this);
pDlg->ShowWindow(SW_SHOW);?
//對(duì)話框中:
void CTestDlg::OnCancel()
{
???? DestroyWindow();
}
void CTestDlg::PostNcDestroy()
{
???? CDialog::PostNcDestroy();
???? delete this;
}?
如果要在點(diǎn)擊按鈕的情況下,銷毀非模態(tài)對(duì)話框,只需要把按鈕的事件映射到OnCancel函數(shù)即可。
以下是一點(diǎn)資料供參考:?
MFC應(yīng)用程序中處理消息的順序
1.AfxWndProc()?????? 該函數(shù)負(fù)責(zé)接收消息,找到消息所屬的CWnd對(duì)象,然后調(diào)用AfxCallWndProc?
2.AfxCallWndProc()?? 該函數(shù)負(fù)責(zé)保存消息(保存的內(nèi)容主要是消息標(biāo)識(shí)符和消息參數(shù))供應(yīng)用程序以后使用,然后調(diào)用WindowProc()函數(shù)?
3.WindowProc()?????? 該函數(shù)負(fù)責(zé)發(fā)送消息到OnWndMsg()函數(shù),如果未被處理,則調(diào)用DefWindowProc()函數(shù)?
4.OnWndMsg()???????? 該函數(shù)的功能首先按字節(jié)對(duì)消息進(jìn)行排序,對(duì)于WM_COMMAND消息,調(diào)用OnCommand()消息響應(yīng)函數(shù),對(duì)于WM_NOTIFY消息調(diào)用OnNotify()消息響應(yīng)函數(shù)。任何被遺漏的消息將是一個(gè)窗口消息。OnWndMsg()函數(shù)搜索類的消息映像,以找到一個(gè)能處理任何窗口消息的處理函數(shù)。如果OnWndMsg()函數(shù)不能找到這樣的處理函數(shù)的話,則把消息返回到WindowProc()函數(shù),由它將消息發(fā)送給DefWindowProc()函數(shù)?
5.OnCommand()?????? 該函數(shù)查看這是不是一個(gè)控件通知(lParam參數(shù)不為NULL,如果lParam參數(shù)為空的話,說明該消息不是控件通知),如果它是,OnCommand()函數(shù)會(huì)試圖將消息映射到制造通知的控件;如果他不是一個(gè)控件通知(或者如果控件拒絕映射的消息)OnCommand()就會(huì)調(diào)用OnCmdMsg()函數(shù)?
6.OnCmdMsg()???????? 根據(jù)接收消息的類,OnCmdMsg()函數(shù)將在一個(gè)稱為命令傳遞(Command Routing)的過程中潛在的傳遞命令消息和控件通知。例如:如果擁有該窗口的類是一個(gè)框架類,則命令和通知消息也被傳遞到視圖和文檔類,并為該類尋找一個(gè)消息處理函數(shù)?
MFC應(yīng)用程序創(chuàng)建窗口的過程
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ā)送此消息說明窗口在移動(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)用?
MFC應(yīng)用程序中打開模式對(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ū)υ捒蛏厦婵丶念伾?
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ì)話框的順序?
1.PreSubclassWindow()???? 重載函數(shù),允許用戶首先子分類一個(gè)窗口?
2.OnCreate()???????????? 消息響應(yīng)函數(shù),響應(yīng)WM_CREATE消息,發(fā)送此消息以告訴一個(gè)窗口已經(jīng)被創(chuàng)建?
3.OnSize()?????????????? 消息響應(yīng)函數(shù),響應(yīng)WM_SIZE消息,發(fā)送此消息以告訴窗口大小發(fā)生變化?
4.OnMove()?????????????? 消息響應(yīng)函數(shù),響應(yīng)WM_MOVE消息,發(fā)送此消息以告訴窗口正在移動(dòng)?
5.OnSetFont()???????????? 消息響應(yīng)函數(shù),響應(yīng)WM_SETFONT消息,發(fā)送此消息以允許改變對(duì)話框中控件的字體?
以上這些的執(zhí)行都是按給定的順序執(zhí)行!
總結(jié)
以上是生活随笔為你收集整理的MFC模态对话框和非模态对话框的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搭建校园网(组网工程课设)
- 下一篇: 中国人为什么精于计算而输于思维?