1. 程式人生 > 實用技巧 >MFC的奇異non-modality模態對話方塊

MFC的奇異non-modality模態對話方塊

介紹 非程式設計師,模態對話方塊是那些拒絕消失 直到你認為,這通常是通過單擊OK或取消 按鈕。程式設計師(non-VB的)模態對話方塊 那些禁用直接父視窗建立之前,和 使他們的父視窗時關閉。因此一個模態的本質 對話方塊是你不能做任何事情直到你關閉父視窗 模態對話方塊。非模態的對話方塊中相對更有禮貌和不挑剔 他們不堅持認為允許您訪問他們的父母 窗戶我相信,現在,任何你可能有無窮小的疑慮 關於對話方塊的形式已經被完全根除。 MFC類稱為CDialog CWnd派生類 專門用於建立和顯示對話方塊在螢幕上——兩個 支援模態和非模態的對話方塊。建立非模態的對話方塊 Create(),你必須摧毀他們自己使用隱藏,複製Code

DestroyWindow()

和他們的行為就像任何正常非模態的視窗。 模態對話方塊建立和顯示使用強大的DoModal () CDialog類的方法。你關閉一個模態對話方塊 函式呼叫EndDialog()或者通過呼叫位置() 或虛()這兩個內部呼叫EndDialog()。 CDialog:: EndDialog方法將呼叫EndDialog 在user32.dll Win32 API函式定義。EndDialog (API函式)不會立即關閉該對話方塊,而是將設定一個 標記將指示訊息佇列退出迴圈,破壞對話方塊 並啟用父視窗的視窗。到目前為止一切順利;一切都那麼 和平和寧靜,樹上的小鳥在院子裡 推特在一個美麗的聲音。 non-modality因素 Win32 API支援相關功能,包括各種對話方塊 函式用於建立模態和非模態的對話方塊。有隱藏,複製像CreateDialog Code

CreateDialogXXX

函式集,隱藏,複製Code

CreateDialogIndirect

等用於建立非模態的對話方塊 和DialogBoxXXX組函式對話方塊, DialogBoxIndirect等產生模態對話方塊。正如前面提到的 在前一節中也有EndDialog函式 只用於模態對話方塊和模態對話方塊。非模態的對話方塊必須 通過呼叫DestroyWindow直接終止。基本的原因 你不應該試圖使用EndDialog非模態的對話方塊 非模態的對話方塊不有自己的訊息迴圈也不模態 關閉父視窗,基本上消除了的實用價值 使用EndDialog。 好了,這就是會給你一個固體 踢——基於MFC CDialog模態對話方塊沒有模態對話方塊。只是在 情況下你沒有讀到正確的第一次,在這裡再次MFC CDialog基於模態對話方塊沒有模態對話方塊。我就會說這一個 第三次,但害怕被稱為一隻鸚鵡阻撓我這樣做。開放 dlgcore.cpp並檢查原始碼,您將看到這個 驚人的宣告是正確的。MFC CDialog類使用的隱藏,Code

CreateDialogIndirect

API函式來建立一個副本和pseudo-modal對話方塊 如果你查詢CreateDialogIndirect MSDN上你將會看到它 用於建立一個非模態的對話方塊。使用MFC命令路由機制 訊息對映和虛擬函式來實現它, 真正的模態對話方塊將完全破壞這種機制,因為模態 訊息迴圈控制的範圍之外MFC命令路由 機械。因此,開發人員創造一個pseudo-modal別無選擇 非模態的對話方塊然後文件作為一個模態對話方塊非常強烈。 基本上這些都是總結步驟pseudo-modal時完成 建立對話方塊通過CDialog: DoModal - bEnableParent是一個布林標誌設定為FALSE,如果啟用父視窗,然後它被禁用和隱藏,複製CodebEnableParent 建立對話方塊設定為TRUE使用CreateDialogIndirect訊息泵維護使用CWnd:: RunModalLoop一旦模態迴圈退出(當CDialog:: EndDialog) 啟用了父視窗對話方塊視窗如果bEnableParent是真的是被呼叫DestroyWindow和DoModal返回引數傳遞給隱藏,複製CodeEndDialog 正如你所看到的開發者已經確保煞費苦心 pseudo-modal對話方塊應該按照模態對話方塊。他們有 甚至試圖容納不同尋常的場景可能會有兩個模態 對話方塊都擁有相同的父——這就是bEnableParent 發揮作用了。因此,當第二模態對話框出現,它不會設定 bEnableParent真的因為父視窗 已禁用。因此當它認為它不會啟用父視窗 這正是因為另一個對話方塊模態到相同的父需要什麼 視窗仍然活躍在螢幕上。 EndDialog -一個微小的缺陷 在本章中已經多次提到,模態對話方塊是 使用EndDialog駁回。讓我們看看EndDialog是什麼 看起來像(如果感興趣的話,它是在dlgcore.cpp中定義的) 隱藏,複製Code

void CDialog::EndDialog(int nResult)
{
    ASSERT(::IsWindow(m_hWnd));

    if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
        EndModalLoop(nResult);

    ::EndDialog(m_hWnd, nResult);
}

呼叫CWnd::EndModalLoop退出由 CWnd::RunModalLoop很好,然後EndDialog API函式是 呼叫以終止模態對話方塊。這也很好,嘿,嘿,嘿,就等著棉花 選擇分鐘! !將使用EndDialog API函式 僅關閉模態對話方塊,但這裡我們試圖使用它來關閉 偽模態對話方塊實際上只是一個偽裝成的非模態對話方塊 反映一種它並不真正擁有的形態。(震驚的沉默……),後 最初的震驚,讓我們放鬆一點。畢竟這不是結束 world和EndDialog並不是一個非常有害的函式呼叫;它 將只嘗試結束不存在的模態訊息迴圈,並將啟用 對話方塊視窗的父視窗。前一種嘗試顯然會失敗 後一種嘗試只會做一些我們無論如何都會做的事情 擁有,因為偽模態泵一退出,DoModal就會退出 重新啟用父視窗。那麼,一切都好嗎?鳥兒也一樣 再一次安靜地鳴叫? 這個錯誤 還記得我們之前討論過的“友善的父母”嗎 以及我如何提到如何使用這個標誌來確保 當有相同父視窗的多個模態對話方塊同時存在時, 屬性之一時,此標誌防止過早啟用父視窗 模態對話方塊兄妹被駁回?嗯你猜怎麼著?粗心的程式設計師 編寫這個特殊函式的微軟剛剛渲染了所有這些 預防措施完全無效。因為現在任何MFC模態對話方塊 這是關閉使用EndDialog(這也意味著OnOK和 虛,因為這些 函式將內部呼叫EndDialog)將啟用它的父視窗 不管bEnableParent持有什麼價值。這基本上 意味著如果你有兩個或更多的MFC模態對話方塊,它們有相同的父對話方塊 視窗,然後當你關閉任何一個模態對話方塊,所有 其他模態對話方塊將失去它們的模態,因為現在父視窗已經失去了模態 被重新啟用。 重現這個錯誤的步驟 建立一個基於MFC對話方塊的應用程式,新增一個新的對話方塊,並將一個名為CChildDialog的類與它關聯在主對話方塊的OnInitDialog方法中設定兩個計時器:複製CodeSetTimer(1000、1000、空); 凝固時間(2000、2000、空); 在定時器處理程式中,每個彈出一個偽模態對話方塊:OnTimer(UINT nIDEvent) { 消磨時間的(nIDEvent); CChildDialog dlg(這個); dlg.DoModal (); CDialog:定時(nIDEvent); } 執行程式並等待2秒,此時您將擁有主程式 對話方塊和兩個模態子對話方塊試圖訪問主對話方塊,您將無法這樣做,因為 兩個模態對話方塊的出現現在使用OK或取消按鈕來關閉一個子對話方塊,現在嘗試訪問主對話方塊,你會驚訝地看到 您將能夠這樣做,儘管在螢幕上存在模態對話方塊 我附加的專案是使用vc++建立的。NET 2003最終Beta和I 向沒有這個版本的同學道歉。但後 上面提到的步驟最多隻需要幾分鐘。什麼 是如此的神奇,這個bug已經被忽略了幾個版本 MFC。我檢查了早在vc++ 6和有完全相同的問題。作為 在我看來,所有人要做的就是註釋掉或刪除呼叫 EndDialog API呼叫。我猜事情是這樣的 MFC開發人員非常習慣於從 它們的包裝器函式(例如,它們會呼叫MessageBox) API從CWnd::Messagebox內部),某人必須有 不經思考就自動輸入這一行,QA人員也必須有 忽略了這個錯誤。這個問題一直不為人所知,因為它是 非常罕見的情況下,一個程式有一個多模態視窗體系結構 其中幾個模態對話方塊視窗有相同的父視窗。 變通辦法 好了,在微軟糾正這個錯誤之前,我們能做的(除了 必須糾正MFC程式碼和重新編譯MFC)是覆蓋OK和 取消按鈕處理程式,並使用以下程式碼代替預設值:- 隱藏,複製Code

{
    if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
        EndModalLoop(IDOK); // or IDCANCEL
}

注意我們是如何沒有呼叫基類的(如果我們這樣做::EndDialog(…)) 我們所有的努力都白費了)。如果您想退出模態對話方塊 在外面的一個地方e OK/Cancel按鈕處理程式,你應該使用相同的程式碼 除了您可能希望返回一個不同的值之外(比如IDYES) 例如)。 結論 據我所知,我可能是鎮上最大的蠢蛋,而且可能會有 這是完全正當的理由,但有些東西告訴我 是一種非常遙遠的偶然性。順便說一下,我要感謝Shog9派我來 vc++ 6版本的dlgcore.cpp在一個相當晚的時間 (對他來說,這相當於我們大多數人的中午)。我也想 這裡明確地指出,本文絕不是試圖模仿 開發MFC庫的一組令人驚歎的微軟程式設計師。 版本歷史 2003年4月5日-文章首次發表2003年4月7日-文章更新瞭解決問題的方法 本文轉載於:http://www.diyabc.com/frontweb/news5144.html