關於“模態對話框”和“非模態對話框”的區別

關於“模態對話框”和“非模態對話框”的區別

 

先說說兩者的定義:模態對話框就是指那種“顯示出來就不可以點選位於其下面的對話框”的對話框;反之的就是非模態對話框。

兩者的區別:

一. 非模態對話框的模板必須具有Visible風格(Visible=True),否則對話框將不可見,而模態對話框則無需設置該項風格。在實際編程中更加保險的辦法是調用CWnd::ShowWindow(SW_SHOW)來顯示對話框,而不管對話框是否具有Visible風格。

二. 非模態對話框對象是用new操作符來動態創建的,而不是以成員變量的形式嵌入到別的對象中或以局部變量的形式構建的。通常應在對話框的擁有者窗口類內聲明一個指向對話框類的指針成員變量,通過該指針可訪問對話框對象。

三. 通過調用CDialog::Create函數來啓動對話框,而不是CDialog::DoModal,這是兩者之間區別的關鍵所在。由於Create函數不會啓動新的消息循環,對話框與應用程序共用同一個消息循環,這樣對話框就不會壟斷用戶輸入。Create在顯示了對話框後就立即返回,而DoModal是在對話框被關閉後才返回的。由於在Create返回後,不能確定對話框是否已關閉,這樣也就無法確定對話框對象的生存期,因此只好在堆棧中構建對話框對象,而不能以局部變量的形式來構建之。

四. 必須調用CWnd::DestroyWindow而不是CDialog::EndDialog來關閉非模態對話框。調用CWnd::DestroyWindow是直接刪除窗口的一般方法。由於缺省的CDialog::OnOK和CDialog::OnCancel函數均調用EndDialog,故程序員必須編寫自己的OnOK和OnCancel函數並且在函數中調用DestroyWindow來關閉對話框。

五. 因爲是用new操作符構建非模態對話框對象,因此必須在對話框關閉後,用delete操作符刪除對話框對象。在屏幕上一個窗口被刪除後,框架會調用CWnd::PostNcDestroy,這是一個虛擬函數,程序可以在該函數中完成刪除窗口對象的工作,具體代碼如下
void CModelessDialog::PostNcDestroy
{delete this;     //刪除對象}
這樣,在刪除屏幕上的對話框後,對話框對象將被自動刪除。擁有者就不必顯式地調用delete來刪除對話框對象了。

六. 必須有一個標誌表明非模態對話框是否打開的。這樣做的原因是用戶有可能在打開一個模態對話框的情況下,又一次選擇打開命令。程序根據標誌來決定是打開一個新的對話框,還是僅僅把原來打開的對話框激活。通常可以用擁有者窗口中的指向對話框對象的指針作爲這種標誌,當對話框關閉時,給該指針賦NULL值,以表明對話框對象已不存在了。
例如:
創建模態對話框
CTestDlg dlg;
dlg.DoModal();
創建非模態對話框
CTestDlg * dlg = new CTestDlg;
dlg->Create(IDD_TEST_DLG);
dlg->ShowWindow(SW_SHOW);
使用非模態對話框與使用模態對話框相似,但是也有一些重要的區別:
首先,非模態對話框通常包含一個標題列和一個系統菜單按鈕。當您在Developer Studio中建立對話框時,這些是內定選項。用於非模態對話框的對話框模板中的STYLE敘述形如:
 
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE        標題列和系統菜單允許使用者,使用鼠標或者鍵盤將非模態對話框移動到另一個顯示區域。對於模態對話框,您通常無須提供標題列和系統菜單,因爲使用者不能在其下面的窗口中做任何其它的事情。
第二項重要的區別是:注意,在我們的範例STYLE敘述中包含有WS_VISIBLE樣式。在 Developer Studio中,從「Dialog Properties」對話框的「More Styles」頁面卷標中選擇此選項。如果省略了WS_VISIBLE,那麼您必須在CreateDialog呼叫之後呼叫ShowWindow:
 
hDlgModeless = CreateDialog (  . . .  ) ;   ShowWindow (hDlgModeless, SW_SHOW) ;        如果您既沒有包含WS_VISIBLE樣式,又沒有呼叫ShowWindow,那麼非模態對話框將不會被顯示。如果忽略這個事實,那麼習慣於模態對話框的程序寫作者在第一次試圖建立非模態對話框時,經常會出現問題。
第三項區別:與模態對話框和消息框的消息不同,非模態對話框的消息要經過程序式的消息隊列。要將這些消息傳送給對話框窗口消息處理程序,則必須改變消息隊列。方法如下:當您使用CreateDialog建立非模態對話框時,應該將從呼叫中傳回的對話框句柄儲存在一個整體變量(如hDlgModeless)中,並將消息循環改變爲:
 
while (GetMessage (&msg, NULL, 0, 0))       
{                 
    if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))     
    {                         
        TranslateMessage (&msg) ;     
        DispatchMessage  (&msg) ;   
    }  
如果消息是發送給非模態對話框的,那麼IsDialogMessage將它發送給對話框中窗口消息處理程序,並傳回TRUE(非0);否則,它將傳回FALSE(0)。只有hDlgModeless爲0或者消息不是該對話框的消息時,才必須呼叫TranslateMessage和DispatchMessage函數。如果您將鍵盤快捷鍵用於您的程序窗口,那麼消息循環將如下所示:
 
while (GetMessage (&msg, NULL, 0, 0))      
{
    if (hDlgModeless == 0 || !IsDialogMessage (hDlgModeless, &msg))
    {
        if (!TranslateAccelerator (hwnd, hAccel, &msg))
        {                                           
            TranslateMessage (&msg) ;
            DispatchMessage  (&msg) ;
        }
    }
}
由於整體變量被初始化爲0,所以hDlgModeless將爲0,直到建立對話框爲止,從而保證不會使用無效的窗口句柄來呼叫IsDialogMessage。在清除非模態對話框時,您也必須注意這一點,正如最後一點所說明的。
hDlgModeless變量也可以由程序的其它部分使用,以便對非模態對話框是否存在加以驗證。例如,程序中的其它窗口可以在hDlgModeless不等於0時給對話框發送消息。
最後一項重要的區別:使用DestroyWindow而不是EndDialog來結束非模態對話框。當您呼叫DestroyWindow後,將hDlgModeless整體變量設定爲0。
使用者習慣於從系統菜單中選擇「Close」來結束非模態對話框。儘管啓用了「Close」選項,Windows內的對話框窗口消息處理程序並不處理WM_CLOSE消息。您必須自己在對話框程序中處理它:
 
case WM_CLOSE :                DestroyWindow (hDlg) ;         hDlgModeless = NULL ;            break ;        注意這兩個窗口句柄之間的區別:DestroyWindow的hDlg參數是傳遞給對話框程序的參數;hDlgModeless是從CreateDialog傳回的整體變量,程序在消息循環內檢驗它。
您也可以允許使用者使用按鍵來關閉非模態對話框,處理方式與處理WM_CLOSE消息一樣。對話框必須傳回給建立它的窗口之任何數據都可以儲存在整體變量中。如果不喜歡使用整體變量,那麼您也可以用CreateDialogParam來建立非模態對話框,並按前面介紹的方法讓它儲存一個結構指針。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章