分享
 
 
 

Visual C++模态对话框消息处理机制的分析

王朝vc·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

摘要:消息驱动机制是Windows操作系统的根本,模态对话框消息处理又是不同于一般消息处理的特殊形式。通过分析这种消息机制的原理,可用来处理类似的程序设计要求。

在Windows操作系统中,面向用户的GUI基本上可分为对话框形式和文档/视图两种表现形式。对话框的显示方式又可分为模态对话框和非模态对话框,以适应不同的用户交互需求。由于对话框和文档/视图框架结构各有特色,能不能将文档/视图框架结构当作一对话框来使用,或在对话框中实现文档/视图框架结构内的特色功能呢,答案是肯定的。

下面,从Windows 操作系统消息驱动机制开始,进而探讨模态对话框实现过程的消息封装、传递和处理机制,最后以模态的形式显示应用到文档/视图框架结构中的实例作为对所讲内容的验证和实践。

一、Windows消息机制

Windows是一种面向对象的体系结构,Windows环境和应用程序都是通过消息来交互的。Windows应用程序开始执行后,Windows为该程序创建一个"消息队列(message queue)",用以存放邮寄给该程序可能创建的各种不同窗口的消息。消息队列中消息的结构(MSG)为:

typedef struct tagMSG{

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

DWORD time;

POINT pt;

}MSG;

其中第一个成员变量是用来标识接收消息的窗口句柄;第二个参数便是消息标识号,如WM_PAINT;第三个和第四个参数的具体意义同message值有关,均为消息参数。前四个参数是非常重要和经常用到的,至于后两个参数则分别表示邮寄消息的时间和光标位置(屏幕坐标)。把消息传送到应用程序有两种方法:一种是由系统将消息"邮寄(post)"到应用程序的"消息队列"这是"进队消息"Win32 API有对应的函数: PostMessage(),此函数不等待该消息处理完就返回;而另一种则是由系统在直接调用窗口函数时将消息"发送(send)"给应用程序的窗口函数,属于"不进队消息"对应的函数是SendMessage()其必须等待该消息处理完后方可返回。

对于每一个正在执行的Windows应用程序,系统为其建立一个"消息队列",即应用程序队列,用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作"消息循环"的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。

消息循环代码是应用程序中主函数winmain ( )中类似如下的程序段:

while(GetMessage(&&msg,NULL,NULL,NULL))

{ file://从消息队列中取得消息

TranslateMessage(&&msg);

file://检索并生成字符消息WM_CHAR

DispatchMessage(&&msg);

file://将消息发送给相应的窗口函数

}

由此可见,所谓"消息循环",实际是程序循环。

Windows 应用程序创建的每个窗口都在系统核心注册一个相应的窗口函数,窗口函数程序代码形式上是一个巨大的switch 语句,用以处理由消息循环发送到该窗口的消息,窗口函数由Windows 采用消息驱动的形式直接调用,而不是由应用程序显示调用的,窗口函数处理完消息后又将控制权返回给Windows。

二、模态对话框的消息处理

由上面我们看到,Windows是一个巨大的消息驱动结构,由用户发出消息,系统响应处理。非模态对话框是响应一个消息,系统处理一个消息,处理完毕后返回控制权给Windows。文档/视图框架结构与其类似。模态对话框在对话框创建后,挂起外部的消息,只是响应对话框内部的消息,而外部消息则全部"过滤"掉了,直到系统接收到WM_DESTROY或WM_CLOSE后,系统返回控制权给模态对话框创建前的线程,继续模态对话框创建前的线程将执行下面的代码。

让我们看看下面的对话框DoModal实现代码:

{

… …

// Disable 父窗口 (在创建对话框前)

HWND hWndParent = PreModal();

AfxUnhookWindowCreate();

BOOL bEnableParent = FALSE;

if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))

{

::EnableWindow(hWndParent, FALSE);

bEnableParent = TRUE;

}

TRY

{

// 创建模态对话框

AfxHookWindowCreate(this);

if (CreateDlgIndirect(lpDialogTemplate,CWnd::FromHandle(hWndParent), hInst))

{

if (m_nFlags & WF_CONTINUEMODAL)

{

// 进入模式循环

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();

… …

}

可以看到,在此实现代码中,并没有开辟新的线程。系统是在RunModalLoop()中进行消息循环。当 m_nFlags 为 WF_CONTINUEMODAL时,系统继续模式状态。RunModalLoop()函数实际上也是一for(;;)循环,控制重新分派Windows消息。直到ContinueModal()返回FALSE,而当调用EndModalLoop()时,ContinueModal()返回FALSE。此时,标志着模态显示的结束。因此,实现模态对话框消息处理的核心部分为RunModalLoop()和EndModalLoop()函数。

三、以模态的形式显示应用到文档/视图框架结构实例

(1)新建一工程文件:ModeFrame,选取MFC AppWizard(exe)。

(2)第二步选取Single document(单文档)。

(3)其余几步均为缺省值。

(4)用ClassWizard添加一新类CSubModeFrame,以CFrameWnd为基类。

(5)添加CsubModeFrame的实现函数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,"模态文档/试图框架 ",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的实现函数EndMode()

void CSubFrame::EndModal(){

ASSERT(::IsWindow(m_hWnd));

if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL)) {

EndModalLoop(1);

}

}

(7)添加CModeFrameView的实现函数OnLButtonDblClk()

在此函数的消息处理中:可以象显示对话框一样处理CsubModeFrame类。

CSubModeFrame SubModeFrame;

If(SubModeFrame.DoMode()){ MessageBox("Mode Ok");}

(8)编译运行工程,双击视图,就会弹出模态的子文档/视图框架结构

结论: 通过上面的分析和实例可以看出,深入研究了解Windows的消息处理机制,可利用消息对Windows的事件进行任意的定制和处理,不用拘泥于系统原有的模式。对进行深入Windows编程是很有必要的。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有