Visual C++模態(tài)對話框消息處理機制的區(qū)分
發(fā)表時間:2024-02-15 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]摘要:消息驅(qū)動機制是Windows操作系統(tǒng)的根本,模態(tài)對話框消息處理又是不同于一般消息處理的特殊形式。通過分析這種消息機制的原理,可用來處理類似的程序設(shè)計要求! ≡赪indows操作系統(tǒng)中,面向用戶的GUI基本上可分為對話框形式和文檔/視圖兩種表現(xiàn)形式。對話框的顯示方式又可分為模態(tài)對話框和非模態(tài)...
摘要:消息驅(qū)動機制是Windows操作系統(tǒng)的根本,模態(tài)對話框消息處理又是不同于一般消息處理的特殊形式。通過分析這種消息機制的原理,可用來處理類似的程序設(shè)計要求。
在Windows操作系統(tǒng)中,面向用戶的GUI基本上可分為對話框形式和文檔/視圖兩種表現(xiàn)形式。對話框的顯示方式又可分為模態(tài)對話框和非模態(tài)對話框,以適應(yīng)不同的用戶交互需求。由于對話框和文檔/視圖框架結(jié)構(gòu)各有特色,能不能將文檔/視圖框架結(jié)構(gòu)當作一對話框來使用,或在對話框中實現(xiàn)文檔/視圖框架結(jié)構(gòu)內(nèi)的特色功能呢,答案是肯定的。
下面,從Windows 操作系統(tǒng)消息驅(qū)動機制開始,進而探討模態(tài)對話框?qū)崿F(xiàn)過程的消息封裝、傳遞和處理機制,最后以模態(tài)的形式顯示應(yīng)用到文檔/視圖框架結(jié)構(gòu)中的實例作為對所講內(nèi)容的驗證和實踐。
一、Windows消息機制
Windows是一種面向?qū)ο蟮捏w系結(jié)構(gòu),Windows環(huán)境和應(yīng)用程序都是通過消息來交互的。Windows應(yīng)用程序開始執(zhí)行后,Windows為該程序創(chuàng)建一個"消息隊列(message queue)",用以存放郵寄給該程序可能創(chuàng)建的各種不同窗口的消息。消息隊列中消息的結(jié)構(gòu)(MSG)為:
typedef struct tagMSG{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;
其中第一個成員變量是用來標識接收消息的窗口句柄;第二個參數(shù)便是消息標識號,如WM_PAINT;第三個和第四個參數(shù)的具體意義同message值有關(guān),均為消息參數(shù)。前四個參數(shù)是非常重要和經(jīng)常用到的,至于后兩個參數(shù)則分別表示郵寄消息的時間和光標位置(屏幕坐標)。把消息傳送到應(yīng)用程序有兩種方法:一種是由系統(tǒng)將消息"郵寄(post)"到應(yīng)用程序的"消息隊列"這是"進隊消息"Win32 API有對應(yīng)的函數(shù): PostMessage(),此函數(shù)不等待該消息處理完就返回;而另一種則是由系統(tǒng)在直接調(diào)用窗口函數(shù)時將消息"發(fā)送(send)"給應(yīng)用程序的窗口函數(shù),屬于"不進隊消息"對應(yīng)的函數(shù)是SendMessage()其必須等待該消息處理完后方可返回。
對于每一個正在執(zhí)行的Windows應(yīng)用程序,系統(tǒng)為其建立一個"消息隊列",即應(yīng)用程序隊列,用來存放該程序可能創(chuàng)建的各種窗口的消息。應(yīng)用程序中含有一段稱作"消息循環(huán)"的代碼,用來從消息隊列中檢索這些消息并把它們分發(fā)到相應(yīng)的窗口函數(shù)中。
消息循環(huán)代碼是應(yīng)用程序中主函數(shù)winmain ( )中類似如下的程序段:
while(GetMessage(&&msg,NULL,NULL,NULL))
{ file://從消息隊列中取得消息
TranslateMessage(&&msg);
file://檢索并生成字符消息WM_CHAR
DispatchMessage(&&msg);
file://將消息發(fā)送給相應(yīng)的窗口函數(shù)
}
由此可見,所謂"消息循環(huán)",實際是程序循環(huán)。
Windows 應(yīng)用程序創(chuàng)建的每個窗口都在系統(tǒng)核心注冊一個相應(yīng)的窗口函數(shù),窗口函數(shù)程序代碼形式上是一個巨大的switch 語句,用以處理由消息循環(huán)發(fā)送到該窗口的消息,窗口函數(shù)由Windows 采用消息驅(qū)動的形式直接調(diào)用,而不是由應(yīng)用程序顯示調(diào)用的,窗口函數(shù)處理完消息后又將控制權(quán)返回給Windows。
二、模態(tài)對話框的消息處理
由上面我們看到,Windows是一個巨大的消息驅(qū)動結(jié)構(gòu),由用戶發(fā)出消息,系統(tǒng)響應(yīng)處理。非模態(tài)對話框是響應(yīng)一個消息,系統(tǒng)處理一個消息,處理完畢后返回控制權(quán)給Windows。文檔/視圖框架結(jié)構(gòu)與其類似。模態(tài)對話框在對話框創(chuàng)建后,掛起外部的消息,只是響應(yīng)對話框內(nèi)部的消息,而外部消息則全部"過濾"掉了,直到系統(tǒng)接收到WM_DESTROY或WM_CLOSE后,系統(tǒng)返回控制權(quán)給模態(tài)對話框創(chuàng)建前的線程,繼續(xù)模態(tài)對話框創(chuàng)建前的線程將執(zhí)行下面的代碼。
讓我們看看下面的對話框DoModal實現(xiàn)代碼:
{
… …
// Disable 父窗口 (在創(chuàng)建對話框前)
HWND hWndParent = PreModal();
AfxUnhookWindowCreate();
BOOL bEnableParent = FALSE;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
::EnableWindow(hWndParent, FALSE);
bEnableParent = TRUE;
}
TRY
{
// 創(chuàng)建模態(tài)對話框
AfxHookWindowCreate(this);
if (CreateDlgIndirect(lpDialogTemplate,CWnd::FromHandle(hWndParent), hInst))
{
if (m_nFlags & WF_CONTINUEMODAL)
{
// 進入模式循環(huán)
DWORD dwFlags = MLF_SHOWONIDLE;
if (GetStyle() & DS_NOIDLEMSG) dwFlags = MLF_NOIDLEMSG;
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
}
}
}
CATCH_ALL(e)
{
DELETE_EXCEPTION(e);
m_nModalResult = -1;
}
END_CATCH_ALL
file://Enable 父窗口
if (bEnableParent)
::EnableWindow(hWndParent, TRUE);
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
::SetActiveWindow(hWndParent);
// 刪除對話框
DestroyWindow();
PostModal();
… …
}
可以看到,在此實現(xiàn)代碼中,并沒有開辟新的線程。系統(tǒng)是在RunModalLoop()中進行消息循環(huán)。當 m_nFlags 為 WF_CONTINUEMODAL時,系統(tǒng)繼續(xù)模式狀態(tài)。RunModalLoop()函數(shù)實際上也是一for(;;)循環(huán),控制重新分派Windows消息。直到ContinueModal()返回FALSE,而當調(diào)用EndModalLoop()時,ContinueModal()返回FALSE。此時,標志著模態(tài)顯示的結(jié)束。因此,實現(xiàn)模態(tài)對話框消息處理的核心部分為RunModalLoop()和EndModalLoop()函數(shù)。
三、以模態(tài)的形式顯示應(yīng)用到文檔/視圖框架結(jié)構(gòu)實例
。1)新建一工程文件:ModeFrame,選取MFC AppWizard(exe)。
。2)第二步選取Single document(單文檔)。
。3)其余幾步均為缺省值。
。4)用ClassWizard添加一新類CSubModeFrame,以CFrameWnd為基類。
。5)添加CsubModeFrame的實現(xiàn)函數(shù)DoMode();
int CsubModeFrame::DoModal()
{
HWND hWndParent = m_hWndPrt;
CRect rc(0,0,400,400);
CWnd *pParent = CWnd::FromHandle(hWndParent);
DWORD dwStyle=WS_THICKFRAME WS_MINIMIZEBOX WS_MAXIMIZEBOX WS_POPUP WS_THICKFRAME WS_VISIBLE WS_SYSMENU WS_CAPTION;
if(!Create(NULL,"模態(tài)文檔/試圖框架 ",dwStyle,rc,pParent,NULL)) return FALSE;
BOOL bEnableParent = FALSE;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
::EnableWindow(hWndParent,FALSE);
::EnableWindow(m_hWnd,TRUE);
bEnableParent = TRUE;
}
CenterWindow();
TRY
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE;
if (GetStyle() & DS_NOIDLEMSG) dwFlags = MLF_NOIDLEMSG;
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
}
CATCH_ALL(e)
{
DELETE_EXCEPTION(e);
m_nModalResult = -1;
}
END_CATCH_ALL
if (bEnableParent)
::EnableWindow(hWndParent, TRUE);
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
::SetActiveWindow(hWndParent);
// destroy modal window
DestroyWindow();
return m_nModalResult;
}
。6)添加CsubModeFrame的實現(xiàn)函數(shù)EndMode()
void CSubFrame::EndModal(){
ASSERT(::IsWindow(m_hWnd));
if (m_nFlags & (WF_MODALLOOP WF_CONTINUEMODAL)) {
EndModalLoop(1);
}
}
。7)添加CModeFrameView的實現(xiàn)函數(shù)OnLButtonDblClk()
在此函數(shù)的消息處理中:可以象顯示對話框一樣處理CsubModeFrame類。
CSubModeFrame SubModeFrame;
If(SubModeFrame.DoMode()){ MessageBox("Mode Ok");}
(8)編譯運行工程,雙擊視圖,就會彈出模態(tài)的子文檔/視圖框架結(jié)構(gòu)
結(jié)論: 通過上面的分析和實例可以看出,深入研究了解Windows的消息處理機制,可利用消息對Windows的事件進行任意的定制和處理,不用拘泥于系統(tǒng)原有的模式。對進行深入Windows編程是很有必要的。