MFC中的模態對話框與非模態對話框


模態對話框創建:

MyDialog mydlg;
mydlg.DoModal()

當前只能運行此模態對話框,且停止主窗口的運行,直到模態對話框退出,才允許主窗口運行。

模態對話框的關閉順序:

OnClose:按關閉符號X后,響應WM_CLOSE消息

OnKillFocus:窗口即將失去輸入焦點,響應WM_KILLFOCUS消息

OnDestroy:窗口即將被銷毀時,響應WM_DESTROY消息

OnNcDestroy:窗口被銷毀或,響應WM_NCDESTROY消息

PostNcDestroy:由onNcDesyroy調用,是Cwnd虛函數

非模態對話框通常是通過new創建的:

MyDialog *mydlg = new MyDialog;
mydlg->Create(IDD_DIALOG1,this);
mydlg->ShowWindow(SW_SHOW);

非模態對話框關閉順序:
OnClose:按關閉符號X后,響應WM_CLOSE消息

OnDestroy:窗口即將被銷毀時,響應WM_DESTROY消息

OnNcDestroy:窗口被銷毀或,響應WM_NCDESTROY消息

PostNcDestroy:由onNcDesyroy調用,Cwnd函數

為了銷毀對話框指針,可以在對話框類中重載PostNcDestroy,添加delete this。

void MyDialog::PostNcDestroy()
{
    CDialogEx::PostNcDestroy();
    delete this;
}

注意:

Onclose函數結束后實際上又調用了Oncannel,Oncannel中調用的是EndDialog(),該函數用於關閉模態對話框。其工作原理為:enddialog是用來結束domodal的循環使用的,domodal內部結束后有destroywindow的調用。但是對於非模態對話框,因其沒有domodal循環,故就不會自動調用destroywindow函數,也就沒有后續的ondestroy等操作,所以非模態對話框要重載oncannel函數,直接執行destroywindow。

void MyDialog::OnCancel()
{
    DestroyWindow();
}

關閉非模態對話框的注意事項MSDN上也有說明[1]:

When you implementa modeless dialog box, always override the OnCancel member function and call DestroyWindow from within it. Don't call thebase class CDialog::OnCancel, because it calls EndDialog, which will make the dialog box invisible but willnot destroy it. You should also override PostNcDestroy for modeless dialog boxes inorder to delete this, since modeless dialog boxes areusually allocated with new. Modal dialog boxes are usuallyconstructed on the frame and do not need PostNcDestroy cleanup
除了點擊關閉符號關閉對話框外,MFC還可以通過OnOK(),OnCancle()關閉對話框,二者分別對應默認對話框界面上的”確定”和”取消”按鈕,兩個函數都是CDialog類的virtual成員函數,兩個函數有一個共同點,就是都會調用EndDialog。
因此,若要通過OnOK或OnCancle關閉非模態對話框,則仍需要對其進行重載,使其調用DestroyWindow。
現在實現一個應用:
在一個基於對話框的MFC程序中,點擊按鈕,彈出另一個子對話框,在彈出的子對話框中輸入一串字符串,點擊按鈕,子對話框關閉,主對話框上顯示輸入的字符串。
右擊資源視圖中Dialog標簽,選擇插入Dialog,雙擊插入的對話框,進入MFC添加類向導,添加一個與該對話框綁定的對話框類:

我們將添加的dialog編輯成如下形式。編輯框接收輸入,點擊button1,將從編輯框中取輸入,銷毀dialog,並將結果傳遞給父對話框。

主對話框也編輯成相同形式,編輯框用於顯示輸出,點擊button1將產生一個子對話框。

下面分別實現彈出模態和非模態對話框。

(1)模態對話框
父對話框按鈕響應:

void CModalTestDlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知處理程序代碼
    Mydialog mydlg;
    if(IDOK==mydlg.DoModal())
    {
        outstr=mydlg.instr;
    }
    GetDlgItem(IDC_EDITOUTPUT)->SetWindowText(outstr);
}

子對話框的按鈕響應:

void Mydialog::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知處理程序代碼
    GetDlgItem(IDC_EDITINPUT)->GetWindowText(instr);//取輸入字符串
    CDialogEx::OnOK();//關閉對話框並返回IDOK
}

一個MFC窗口對象包括兩方面的內容:一是窗口對象封裝的窗口,即存放在m_hWnd成員中的HWND(窗口句柄),二是窗口對象本身是一個C++對象。要刪除一個MFC窗口對象,應該先刪除窗口對象封裝的窗口,然后刪除窗口對象本身。當Domodal返回時,模態對話框窗口已經銷毀,但對話框類仍然存在,股可以直接從mydlg中取輸入變量。mydlg屬於局部變量,OnBnClickedButton1執行完后,自動銷毀。

(2)非模態對話框

父對話框按鈕響應:

void CModelessTestDlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知處理程序代碼
    Mydialog *mydlg = new Mydialog;
    mydlg->Create(IDD_DIALOG1, this);
    mydlg->ShowWindow(SW_SHOW);
}

子對話框按鈕響應:

void Mydialog::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知處理程序代碼
    CString *instr=new CString;
    GetDlgItem(IDC_EDITINPUT)->GetWindowText(*instr);
    HWND parhwnd=GetParent()->m_hWnd;//取得父窗口句柄
    ::PostMessage(parhwnd,WM_UPDATE,(WPARAM)instr,0);//向父窗口發消息
    OnCancel();
}

 

為了將字符串從子對話框向父對話框傳遞,我們使用了Postmessage發送自定義消息WM_UPDATE。因為父對話框Create了一個非模態對話框后就立即返回了,並不能像對模態對話框那樣等待其結束直接取結果。

在子對話框中使用了OnCancle關閉對話框,故需要對其進行重載:

void Mydialog::OnCancel()
{
    // TODO: 在此添加專用代碼和/或調用基類

    //CDialogEx::OnCancel();
    DestroyWindow();
}

另外還需重載PostNcDestroy:

void Mydialog::PostNcDestroy()
{
    // TODO: 在此添加專用代碼和/或調用基類

    CDialogEx::PostNcDestroy();
    delete this;
}

可以通過MFC類向導找到要重載的虛函數:

在父對話框類中定義消息響應函數,將子對話框發來的消息參數轉為字符串顯示:

//消息響應函數
LRESULT CModelessTestDlg::Onupdate(WPARAM wParam, LPARAM lParam)
{
    CString * outstr =(CString*)(wParam);
    GetDlgItem(IDC_EDITOUTPUT)->SetWindowText(*outstr);
    delete outstr;
    return true;
}

源碼:MFC模態非模態對話框

參考:

[1]https://msdn.microsoft.com/en-us/library/132s802t.aspx

[2]http://blog.csdn.net/hanyujianke/article/details/8507064

[3]http://blog.csdn.net/xiaominggunchuqu/article/details/49895325


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM