非模態對話框允許用戶在處理非模態對話框的同時處理目標對話框。其不會壟斷用戶的輸入,如圖所示。Windows應用程式中,對話框分為兩種。另一種是模態對話框。二者的區別在於當對話框打開時,是否允許用戶進行其他對象的操作。
要建立非模態對話框需要調用兩個函式
Create()和ShowWindow()
如何創建和關閉非模態對話框
無模式對話框與有模式對話框不同的是在創建後其他視窗都可以繼續接收用戶輸入,因此無模式對話框有些類似一個彈出視窗。創建無模式對話框需要調用
BOOL CDialog::Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );之後還需要調用
BOOL CDialog::ShowWindow( SW_SHOW);進行顯示,否則無模式對話框將是不可見的。相關代碼如下:
void CYourView::OnOpenDlg(void)
{
/*假設IDD_TEST_DLG為已經定義的對話框資源的ID號*/
CTestDlg *dlg=new CTestDlg;
dlg->Create(IDD_TEST_DLG,NULL);
dlg->ShowWindow(SW_SHOW);
/*不要調用 delete dlg;*/
}
在上面的代碼中我們新生成了一個對話框對象,而且在退出函式時並沒有銷毀該對象。因為如果此時銷毀該對象(對象被銷毀時視窗同時被銷毀),而此時對話框還在顯示就會出現錯誤。那么這就提出了一個問題:什麼時候銷毀該對象。我時常使用的方法有兩個:
在對話框退出時銷毀自己:在對話框中重載OnOK與OnCancel在函式中調用父類的同名函式,然後調用DestroyWindow()強制銷毀視窗,在對話框中映射WM_DESTROY訊息,在訊息處理函式中調用delete this;強行刪除自身對象。相關代碼如下:
void CTestDlg1::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}
void CTestDlg1::OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}
void CTestDlg1::OnDestroy()
{
CDialog::OnDestroy();
AfxMessageBox("call delete this");
delete this;
}
這種方法的要點是在視窗被銷毀的時候,刪除自身對象。所以你可以在任何時候調用DestroyWindow()以達到徹底銷毀自身對象的作用。(DestroyWindow()的調用會引起OnDestroy()的調用)
通過向父親視窗傳送訊息,要求其他視窗對其進行銷毀:首先需要定義一個訊息用於進行通知,然後在對話框中映射WM_DESTROY訊息,在訊息處理函式中調用訊息傳送函式通知其他視窗。在接收訊息的視窗中利用ON_MESSAGE映射處理訊息的函式,並在訊息處理函式中刪除對話框對象。相關代碼如下:
/*更改對話框的有關檔案*/
CTestDlg2::CTestDlg2(CWnd* pParent /*=NULL*/)
: CDialog(CTestDlg2::IDD, pParent)
{/*m_pParent為一成員變數,用於保存通知視窗的指針,所以該指針不能是一個臨時指針*/
ASSERT(pParent);
m_pParent=pParent;
//{{AFX_DATA_INIT(CTestDlg2)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CTestDlg2::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}
void CTestDlg2::OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}
void CTestDlg2::OnDestroy()
{
CDialog::OnDestroy();
/*向其他視窗傳送訊息,將自身指針作為一個參數傳送*/
m_pParent->PostMessage(WM_DELETE_DLG,(WPARAM)this);
}
/*在訊息接收視窗中添加訊息映射*/
/*在頭檔案中添加函式定義*/
afx_msg LONG OnDelDlgMsg(WPARAM wP,LPARAM lP);
/*添加訊息映射代碼*/
ON_MESSAGE(WM_DELETE_DLG,OnDelDlgMsg)
END_MESSAGE_MAP()
/*實現訊息處理函式*/
LONG CMy53_s1View::OnDelDlgMsg(WPARAM wP,LPARAM lP)
{
delete (CTestDlg2*)wP;
return 0;
}
/*創建對話框*/
void CMy53_s1View::OnTest2()
{
CTestDlg2 *dlg=new CTestDlg2(this);
dlg->Create(IDD_TEST_DLG_2);
dlg->ShowWindow(SW_SHOW);
}
在這種方法中我們利用訊息來進行通知,在Window系統中利用訊息進行通知和傳遞數據的用法是很多的。
同樣無模式對話框的另一個作用還可以用來在用戶在對話框中的輸入改變時可以及時的反映到其他視窗。下面的代碼演示了在對話框中輸入一段文字,然後將其更新到視圖的顯示區域中,這同樣也是利用了訊息進行通知和數據傳遞。
/*在對話框中取出數據,並向其他視窗傳送訊息和數據,將數據指針作為一個參數傳送*/
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT,szOut,30);
m_pParent->SendMessage(WM_DLG_NOTIFY,(WPARAM)szOut);
}
/*在訊息接收視窗中*/
/*映射訊息處理函式*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)
/*在視圖中繪製出字元串 m_szOut*/
void CMy53_s1View::OnDraw(CDC* pDC)
{
CMy53_s1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->TextOut(0,0,"Display String");
pDC->TextOut(0,20,m_szOut);
}
/*處理通知訊息,保存信息並更新顯示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
m_szOut=(char*)wP;
Invalidate();
return 0;
}
此外這種用法利用訊息傳遞數據的方法對有模式對話框和其他的視窗間通信也一樣有效