摘自技術(shù)流博客[
http://blog.sina.com.cn/zhangzhiyu1987]
在VC++中,打開對(duì)話框一般是用DoModal()函數(shù)調(diào)用模態(tài)對(duì)話框,但是模態(tài)對(duì)話框只能在對(duì)彈出的當(dāng)前子窗口進(jìn)行操作,而不能對(duì)父窗口進(jìn)行操作,也無(wú)法傳遞數(shù)據(jù)到父窗口中,根據(jù)筆者的研究發(fā)現(xiàn),采用非模態(tài)對(duì)話框的模式可以很好的解決這一問(wèn)題。
在VS2008中新建一個(gè)就有MFC應(yīng)用程序的Project項(xiàng)目,在彈出的MFC應(yīng)用程序向?qū)е羞x擇“基于對(duì)話框”,取消“使用Unicode庫(kù)”,單擊完成。在“資源視圖”里面添加一個(gè)對(duì)話框,默認(rèn)ID為IDD_DIALOG1。
雙擊IDD_DIALOG1對(duì)話框,在彈出的MFC類向?qū)е?,類名填寫CSonDialog,基類選擇CDialog,單擊完成。這樣我們就將新建的IDD_DIALOG1關(guān)聯(lián)上一個(gè)基于CDialog的類了。
在父窗口上添加一個(gè)按鈕,雙擊,便可進(jìn)入這個(gè)按鈕的消息響應(yīng)函數(shù)。在最上面包含CSonDialog的頭文件#include “SonDialog.h”。如果在消息響應(yīng)函數(shù)中寫入如下代碼:
CSonDialog SonWnd;
SonWnd.DoModal();
運(yùn)行之后按下父窗口上的按鈕,可以發(fā)現(xiàn)彈出了IDD_DIALOG1,但是只能在IDD_DIALOG1上操作,無(wú)法操作父窗口。如果想要在彈出子窗口后還可以操作父窗口的話,需要采用非模態(tài)對(duì)話框的模式彈出子窗口。
MFC在CDialog類中有一個(gè)Create(UINT nIDTemplate, CWnd *pParentWnd = 0),這個(gè)函數(shù)可以創(chuàng)建一個(gè)Dialog,其中參數(shù)nIDTemplate為需要?jiǎng)?chuàng)建的Dialog的ID。同時(shí)還有一個(gè)函數(shù)ShowWindow(int nCmdShow),用來(lái)顯示創(chuàng)建的這個(gè)Dialog。在消息響應(yīng)函數(shù)中寫入如下代碼:
CSonDialog SonWnd;
SonWnd.Create(IDD_DIALOG1);
SonWnd.ShowWindow(SW_SHOW);
運(yùn)行之后按下父窗口上的按鈕發(fā)現(xiàn)窗口閃了一下,然后就消失了。這是因?yàn)閷?duì)象SonWnd是一個(gè)局部對(duì)象,在運(yùn)行完SonWnd.ShowWindow(SW_SHOW)這條語(yǔ)句之后便退出了消息響應(yīng)函數(shù),因此SonWnd對(duì)象也就被銷毀了。如果想要退出消息響應(yīng)函數(shù)之后窗口依然存在,則需要將SonWnd定義為一個(gè)全局變量。因此在ProjectDlg.h中添加一個(gè)CSonDialog SonWnd的定義,同時(shí)由于VC++在編譯的時(shí)候預(yù)編譯頭文件,因此還需要在ProjectDlg.h中包含CSonDialog的頭文件#include “SonDialog.h”,這樣在ProjectDlg.cpp中,便可以把SonDialog.h刪掉了。然后在按鈕的消息響應(yīng)函數(shù)中添加如下代碼:
SonWnd.Create(IDD_DIALOG1);
SonWnd.ShowWindow(SW_SHOW);
我們發(fā)現(xiàn)IDD_DIALOG1被創(chuàng)建出來(lái),并且一直保留著。但是還是無(wú)法和父窗口進(jìn)行數(shù)據(jù)交流。根據(jù)查找資料我們發(fā)現(xiàn)在C++中有一個(gè)指針很特別,它指向的是當(dāng)前窗口,這個(gè)指針就是this指針。我們通過(guò)傳遞this指針來(lái)相互調(diào)用對(duì)方的數(shù)據(jù)。
在CSonDialog類中,我們添加一個(gè)指向父窗口的全局指針變量CProjectDlg *m_pFaher,同時(shí)添加一個(gè)函數(shù)WndCreate(CProjectDlg *pParent),代碼如下:
void CSonDialog::WndCreate(CProjectDlg *pParent)
{
Create(IDD_DIALOG1); //創(chuàng)建對(duì)話框
ShowWindow(SW_SHOW); //顯示對(duì)話框
m_pFather = pParent; //將父窗口指針傳遞進(jìn)來(lái)
}
這個(gè)函數(shù)中調(diào)用了CDialog類中的Create()和ShowWindow()函數(shù)來(lái)創(chuàng)建和顯示對(duì)話框,同時(shí)采用參數(shù)傳遞的辦法將父窗口的指針傳遞到子窗口中。而在父窗口ProjectDlg.cpp的消息響應(yīng)函數(shù)中,我們添加如下代碼:
SonWnd.WndCreate(this);
編譯運(yùn)行之后發(fā)現(xiàn)有錯(cuò),因?yàn)樵赑rojectDlg.h的頭文件中包含了SonDialog.h,而在SonDialog.h中又包含了ProjectDlg.h,這樣程序在進(jìn)行編譯的時(shí)候就會(huì)出現(xiàn)頭文件重復(fù)包含的錯(cuò)誤,有兩種辦法可以解決此問(wèn)題。
第一種辦法是在兩個(gè)頭文件中分別加入預(yù)編譯命令#ifndef #define #endif命令,在SonDialog.h最上面加入
#ifndef SONDIALOG
#define SONDIALOG
最下面加入
#endif
在ProjectDlg.h最上面加入
#ifndef RPOJECTDLG
#define PROJECTDLG
最下面加入
#endif
以上語(yǔ)句塊的意思是如果SONDIALOG/PROJECTDLG沒(méi)有被定義的話,那么就定義SONDIALOG/PROJECTDLG,如果SONDIALOG/PROJECTDLG被定義的話,直接跳轉(zhuǎn)到#endif,這樣就可以很好的避免被重復(fù)定義的情況。這種方法我在以前編程的時(shí)候很好用,但是不知道為什么最近幾次寫程序這種方法都失效了,于是我又想出了另外一種辦法。
第二種辦法的原理是采取避免在頭文件中定義具體類型的指針變量,用定義空指針的方法繞過(guò)頭文件重復(fù)包含的問(wèn)題。由于在父窗口中,指向子窗口的對(duì)象必須是全局變量,這樣才能保證子窗口在銷毀之前一直有顯示。因此在父窗口ProjectDlg.h中不得不包含SonDialog.h的頭文件,這樣就只能在SonDialog.h中想辦法了。其實(shí)仔細(xì)想來(lái)我們發(fā)現(xiàn)在SonDialog.h中只要定義一個(gè)空指針就可以解決問(wèn)題。具體方法如下:
在SonDialog.h不包含ProjectDlg.h頭文件,也不定義CProjectDlg的對(duì)象,而是定義一個(gè)空指針LPVOID m _pFather,將WndCreate()函數(shù)的參數(shù)改為L(zhǎng)PVOID pPaernt,然后在WndCreate()函數(shù)中添加如下代碼:
void CSonDialog::WndCreate(LPVOID pParent)
{
Create(IDD_DIALOG1); //創(chuàng)建對(duì)話框
ShowWindow(SW_SHOW); //顯示對(duì)話框
m_pFather = pParent; //將父窗口指針傳遞進(jìn)來(lái)
}
這樣,父窗口的this指針傳遞進(jìn)來(lái)之后到m_pFather還是一個(gè)指向任意對(duì)象的指針,只要在SonDialog.cpp的函數(shù)中需要調(diào)用父窗口中的函數(shù)或者是改動(dòng)父窗口的某些變量時(shí),在cpp文件中包含頭文件ProjectDlg.h,在函數(shù)開始時(shí)加入代碼:
CProjectDlg *Main;
Main = (CProjectDlg *)m_pFather; //強(qiáng)制將LPVOID類型轉(zhuǎn)換
Main->
就可以通過(guò)指針Main來(lái)對(duì)父窗口進(jìn)行操作。這樣就可以實(shí)現(xiàn)兩個(gè)對(duì)話框中的信息相互傳遞了。
另外在建立非模態(tài)對(duì)話框的時(shí)候要注意,重寫OnOk()和OnCancel()兩個(gè)函數(shù),要在里面加入DestoryWindow()函數(shù),OnOk()和OnCancel()函數(shù)里面并沒(méi)有銷毀窗口,而是使得窗口不可見,如果不銷毀窗口,在下一次再次打開子窗口時(shí),就會(huì)出現(xiàn)錯(cuò)誤。
以上代碼在Windows 7 家庭普通版+Visual Studio 2008 SP1下運(yùn)行通過(guò)。