日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MFC中实现模态对话框的结构与原理

發布時間:2023/12/18 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC中实现模态对话框的结构与原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 模態對話框

在涉及GUI程序開發的過程中,常常有模態對話框以及非模態對話框的概念

模態對話框:在子界面活動期間,父窗口是無法進行消息響應。獨占用戶輸入
非模態對話框:各窗口之間不影響

模態框和非模態框的主要區別:

1.模態對話框會阻塞線程其他窗口的輸入消息,其他窗口無法響應包括用戶輸入;
2.模態對話框會中斷執行流程,關閉模態窗口,后會繼續執行;

在用戶層的主要邏輯如下:?

TestDlg dlg;if (dlg.DoModal() == IDOK) {//處理完畢后的操作 } .......//后續處理

在具體實現中,有如下幾個步驟:
1. 讓父窗口失效 EnableWindow(parentWindow, FALSE)
2. 建立模態對話框自己的消息循環(RunModalLoop)
3. 直至接收關閉消息,消息循環終止,并銷毀窗口。

INT_PTR CDialog::DoModal() {//對話框資源加載......//在創建模態窗口之前先讓父窗口失效,不響應鍵盤、鼠標產生的消息HWND hWndParent = PreModal();AfxUnhookWindowCreate();BOOL bEnableParent = FALSE;if (hWndParent && hWndParent != ::GetDesktopWindow() && ::IsWindowEnabled(hWndParent)){::EnableWindow(hWndParent, FALSE);bEnableParent = TRUE;.......}//創建模態窗口,并進行消息循環,若窗口不關閉,則循環不退出AfxHookWindowCreate(this);VERIFY(RunModalLoop(dwFlags) == m_nModalResult);//窗口關閉,銷毀窗口DestroyWindow();PostModal();//釋放資源,并讓父窗口有效pMainWnd->EnableWindow(TRUE);//返回return m_nModalResult; }

2. 模態窗口中的消息循環

int CWnd::RunModalLoop(DWORD dwFlags) {//要檢查窗口狀態是否是模態窗口//若狀態一直為模態,則一直進行消息循環for (;;){ASSERT(ContinueModal());// phase1: check to see if we can do idle workwhile (bIdle &&!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)){ASSERT(ContinueModal());// show the dialog when the message queue goes idleif (bShowIdle){ShowWindow(SW_SHOWNORMAL);UpdateWindow();bShowIdle = FALSE;}// call OnIdle while in bIdle stateif (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0){// send WM_ENTERIDLE to the parent::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);}if ((dwFlags & MLF_NOKICKIDLE) ||!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++)){// stop idle processing next timebIdle = FALSE;}}//在有消息的情況下取消息處理do{ASSERT(ContinueModal());// pump message, but quit on WM_QUITif (!AfxPumpMessage()){AfxPostQuitMessage(0);return -1;}// show the window when certain special messages rec'dif (bShowIdle &&(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN)){ShowWindow(SW_SHOWNORMAL);UpdateWindow();bShowIdle = FALSE;}if (!ContinueModal())goto ExitModal;// reset "no idle" state after pumping "normal" messageif (AfxIsIdleMessage(pMsg)){bIdle = TRUE;lIdleCount = 0;}} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));}ExitModal:m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);return m_nModalResult; }

GetMessage與PeekMessage的區別:
GetMessage:用于從消息隊列讀取消息。若隊列中沒有消息,GetMessage將導致線程阻塞。
PeekMessage:檢測隊列中是否有消息,并立即返回,不會導致阻塞。

3. APP中的消息循環

//thrdcore.cpp // main running routine until thread exits int CWinThread::Run() { // for tracking the idle time state BOOL bIdle = TRUE; LONG lIdleCount = 0; //消息讀取乃至分發 當為WM_QUIT時,退出循環 for (;;) { //檢查是否為空閑時刻while (bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) { // call OnIdle while in bIdle state if (!OnIdle(lIdleCount++)) bIdle = FALSE; // assume "no idle" state } //有消息,讀消息并分發 do { // pump message, but quit on WM_QUIT if (!PumpMessage()) return ExitInstance(); // reset "no idle" state after pumping "normal" message if (IsIdleMessage(&m_msgCur)) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); } }

4. 模態對話框中局部消息循環和APP全局消息循環的關系

4.1 APP消息循環和模態對話框中局部消息循環的關系

根據上圖可以看出,在APP的消息循環再派發ONOK消息后,調用ModalDlg的響應函數,pWnd->OnOk();在該消息中,
會 進入模態對話框的消息循環,除非將模態對話框關閉,否則APP的DispatchMessage函數一直出不來。

一旦創建了模態對話框,進行局部消息循環,那么APP的消息循環就被阻斷。整個程序的消息循環有模態對話框中得消息循環取代。所以給父窗口發送的非窗口消息,一樣可以響應。

由于局部消息循環只在對話框中的一個響應函數中,而全局的消息循環也被阻斷,局部循環一直運行,如果用戶不進行處理并關閉模態對話框,該循環會一直不退出。其他對話框也得不到處理。

4.2 局部消息循環存在的必要性

我之前一直有這樣一個疑問,覺得模態對話框中的局部消息循環沒有必要,可以通過如下方式達到模態對話框的效果:

pParentWnd->EnableWindow(FALSE);CDialog *pDlg; pDlg = new CDialog(); pDlg->Create(); pDlg->Show();pParentWnd->EnableWindow(TRUE);

并且做了個實驗,貌似OK。但是這邊有個疏漏的是,模態對話框的作用有兩個:
1. 使父窗口失效,無法響應用戶的輸入
2. 在當前窗口為處理完畢時,禁止進入后續操作。
上述例子只達到了要求1,沒有達到要求二

所以模態對話框中有如下代碼:

1

if?(dlg.DoModal() == IDOK)

若對話框沒有關閉,是無法進行后續操作的。
但是按照我先前的理解,如果代碼是這樣的:

void CAppDoModelTestApp::OnTestModaltest() {CWnd* pMainWnd = AfxGetMainWnd();pMainWnd->EnableWindow(FALSE);m_pTestDlg1 = new CModalDlg();m_pTestDlg1->Create(IDD_DIALOG1);m_pTestDlg1->ShowWindow(SW_SHOW);m_pTestDlg2 = new CModalDlg();m_pTestDlg2->Create(IDD_DIALOG1);m_pTestDlg2->ShowWindow(SW_SHOW); }

在對話框TestDlg1后產生后,TestDlg2一樣會出現。但是我們模態對話框希望的效果是:在TestDlg1未關閉前,TestDlg2不創建。所以此處體現出了局部消息循環的優勢,就是在當前窗口為處理完畢時,一直循環, 拒絕進入后續代碼中。

/*******************MFC創建模態對話框和非模態對話框的方法*********************/

在MFC中對話框有兩種形式,一個是模態對話框(model dialog box),一個是非模態對話框(modeless dialog box)。本文對此分別簡述其創建方法。

一、模態對話框(model dialog box)

在程序運行的過程中,若出現了模態對話框,那么主窗口將無法發送消息,直到模態對話框退出才可以發送。
點擊模態對話框中的OK按鈕,模態對話框會被銷毀。
創建一個模態對話框的代碼如下所示:

1

2

3

//創建一個模態對話框

CTestDialog td;

td.DoModal();

其中CTestDialog為我自己所新建的和一個對話框資源相關聯的對話框類。
可以創建一個布局模態對話框類變量,不用擔心它會隨著所在函數返回而被銷毀。因為DoModal()函數的一個功能是,當前只能運行此模態對話框,且停止主窗口的運行,直到模態對話框退出,才允許主窗口運行。
DoModal()函數也有顯示對話框的功能,所以也無需調用其他函數來顯示對話框。

二、非模態對話框(modaless dialog box)

在程序運行的過程中,若出現了非模態對話框,主窗口還可以發送消息。
點擊非模態對話框中的OK按鈕,非模態對話框沒有銷毀,只是隱藏了。若想點擊OK按鈕時,非模態對話框也銷毀,那么CTestDialog類必須重載其基類CDialog的虛函數OnOK(),在此函數里調用DestroyWindow()來銷毀此對話框。

此處采用和上面一樣的方式來創建一個非模態對話框,代碼如下:

1

2

3

CTestDialog td;

td.Create(IDD_DIALOG1); //創建一個非模態對話框

td.ShowWindow(SW_SHOWNORMAL); //顯示非模態對話框

那么,在運行時,你會發現此對話框無法顯示。這是因為你聲明的對話框變量td是局部變量,但這個函數返回時,td也被析構了,所以無法顯示此對話框。

創建非模態對話框,必須聲明一個指向CTestDialog類的指針變量,且需要顯示的調用ShowWindow()才能將對話框顯示出來。有兩種創建方法:

(1)采用局部變量創建一個非模態對話框

1

2

3

4

//采用局部變量創建一個非模態對話框

CTestDialog *pTD = new CTestDialog();

pTD->Create(IDD_DIALOG1); //創建一個非模態對話框

pTD->ShowWindow(SW_SHOWNORMAL); //顯示非模態對話框

因為指針在聲明的時候是被放在堆棧中,只有整個應用程序關閉后才會被銷毀,所以可以正常顯示對話框。
這種方法雖然不影響程序的運行,可是指針pTD所指向的內存卻導致不可用,這樣的編程很不好。

(2)采用成員變量創建一個非模態對話框
首先在你所要編寫的類的頭文件中聲明一個指針變量:

1

2

private:

CTestDialog *pTD;

然后再在相應的CPP文件,在你要創建對話框的位置添加如下代碼:

1

2

3

4

//采用成員變量創建一個非模態對話框

pTD = new CTestDialog(); //給指針分配內存

pTD->Create(IDD_DIALOG1); //創建一個非模態對話框

pTD->ShowWindow(SW_SHOWNORMAL); //顯示非模態對話框

最后在所在類的析構函數中收回pTD所指向的內存:

1

delete pTD;

總結

以上是生活随笔為你收集整理的MFC中实现模态对话框的结构与原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。