ImageVerifierCode 换一换
格式:DOCX , 页数:19 ,大小:36.60KB ,
资源ID:6347396      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6347396.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(VCMFC编程实例03.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

VCMFC编程实例03.docx

1、VCMFC编程实例03 本文由sha_shoushou贡献 pdf文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。 下载 下载 第3章 消 息 处 理 第1章讨论了 M F C用户界面的基本要素:窗口,窗口类和 C W n d;第2章讨论了构成 M F C 库的其他类,尤其是那些构成 M F C应用程序内核的类.在本章中,我们将讨论 M F C类和它们 的窗口怎样进行互相通信的.我们发现有三种类型的消息:窗口,命令 ( C o m m a n d )和控件通 知(Control Notification),并且这些消息既可以发送 ( s e n t ),也可以寄送

2、 ( p o s t );接着,将跟踪 一个被MFC窗口进程处理的消息;最后,将讨论重定向消息的方法. 3.1 发送或寄送一个消息 第1章已提及,每个窗口使用窗口进程处理发送给它的消息.消息可以来自系统,你的应 用程序或别的应用程序.消息告诉窗口进程执行某个任务 (如初始化自己,绘制或销毁一个窗 口等),或者通知它发生某个事件 (如鼠标正单击窗口 ). 系统或应用程序有两种传输消息的方法:发送消息或寄送消息. 3.1.1 发送一个消息 发送一个消息时,直接调用窗口的窗口进程.通信是即时的,直到窗口进程为调用函数 返回一个结果后,应用程序才能继续. 3.1.2 寄送一个消息 寄送一个消息时,把消

3、息发送到拥有那个窗口的应用程序消息队列中.一有空闲,应用 程序就搜索消息队列,并在消息队列中处理消息,即从队列中删除它们,并将它们发送到即 定窗口.通信将可能延迟,直到目标应用程序获得处理消息的时间.调用函数发送消息后即 返回,但结果只是表示消息寄送成功与否,而不是被调用窗口进程的结果 (见图3-1). 窗口对象 WndProc 地址 被发送的消息直接 调用该窗口的窗口 进程 消息泵 消息n+1 消息n+2 消息n+3 消息n+4 消息队列 当应用程序空闲时, 抽出寄送到队列中 的消息并调用该窗 口的窗口进程 被寄送的消息延迟在 应用程序消息队列中 图3-1 发送消息时通信是即时的,而寄送消息

4、时通信可能延迟 3.1.3 发送一个消息与寄送一个消息的比较 鼠标和键盘消息通常是寄送的,而所有其他消息通常都是发送的.在消息队列中,寄送 下载 有鼠标和键盘消息被处理之后. 第3章 消 息 处 理 33 的消息接受特殊的鼠标和键盘处理.通常,应该尽量发送一个消息,除非想把动作延迟到所 3.2 怎样使用MFC发送一个消息 用MFC发送一个消息的方法是,首先,应获取接收消息的 CWnd类对象的指针;然后,调 用CWnd的成员函数 SendMessage( ). LRESULT Res=pWnd-SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam)

5、; p W n d指针指向目标 C W n d类对象.变量 M s g是消息, w P a r a m和l P a r a m变量包含消息的参 数,如鼠标单击哪里或选择了什么菜单项.目标窗口返回的消息结果放在变量 R e s中.发送消 息到一个没有CWnd类对象的窗口,可以用下列目标窗口的句柄直接调用 Windows API: LRESULT Res=:SendMessage(HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam); 这里的hWnd是目标窗口的句柄. 3.3 怎样用MFC寄送一个消息 用M F C寄送一个消息与发送一个消息几乎

6、相同,但寄送时用 PostMessage( ) ,而不是用 SendMessage( );返回值 R e s也不一样, R e s不是一个由目标窗口返回的值,而是一个布尔值, 用来表示消息是否成功地放到消息队列中. 检索一个寄送消息 正常情况下,一旦消息被寄送后,应用程序在后台发送它.但是在特殊情况下,需要你 自己去删除一个消息,例如想在应用程序接收到某种消息之前停止应用程序.有两种方法可 以从应用程序消息队列中删除一个消息,但这两种方法都没有涉及 MFC. 第一种方法:在不干扰任何事情之下窥视消息队列,看看一个消息是否在那里. BOOL res=:PeekMessage(LPMSG lpMs

7、g, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg); 第二种方法:实际上是等待,一直等到一个新的消息到达队列为止,然后删除并返回 该消息. BOOL res=:GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax); 在这两种方法中,变量 h W n d指定要截获消息的窗口,如果该变量设为 N U L L,所有窗口 消息将被截获. w M s g F i l t e r M i n和w M s g F i l t

8、e r M a x变量与SendMessage( )中的变量 M s g相对应, 指定查看消息的范围.如果用 0, 0 ,则所有的消息都将被截获.如果用 W M _ K E Y F I R S T, WM_KEYLAST或WM_MOUSEFIRST, WM_MOUSELAST,则所有键盘或鼠标的消息将被截 获. w R e m o v e M s g变 量 指 定 PeekMessage( )是 否 应 该 真 正 地 从 队 列 中 删 除 该 消 息 . (GetMessage( )总是删除消息).该变量可以取两个值: PM_REMOVE,PeekMessage( )将删除消息. PM_N

9、OREMOVE,PeekMessage( )将把消息留在队列里,并返回它的一个拷贝. 当然,如果把消息留在消息队列中,然后再次调用 PeekMessage( )查看相同类型的消息, 则将返回完全相同的消息. 34 第一部分 基 础 知 识 下载 lpMsg变量是一个指向 MSG结构的指针,MSG包含检索到的消息. typedef struct tagMSG HWND hwnd; / window handle message is intended for UINT message; WPARAM wParam; LPARAM lParam; DWORD time; / the time th

10、e message was put in the queue POINT pt; / the location of the mouse cursor when the / message was put in the queue MSG; 3.4 三种类型的消息 在MFC应用程序中传输的消息有三种类型:窗口消息,命令消息和控件通知. 3.4.1 窗口消息 窗口消息(Window Message)一般与窗口的内部运作有关,如创建窗口,绘制窗口和销毁窗 口等.通常,消息是从系统发送到窗口,或从窗口发送到窗口. 当用 S e n d M e s s a g e ( )或P o s t M e s

11、s a g e ( )发送一个窗口消息时,变量 M e s s a g e,w P a r a m和 lParam的格式如下: Message WM_XXX wParam 定义的命令 lParam 定义的命令 WM_XXX可以是许多窗口消息之一,如下列窗口: WM_CREATE,告诉窗口初始化自己. WM_PAINT,告诉窗口绘制自己. W M _ M O U S E M O V E,告诉窗口鼠标移经它. 有关某些公共窗口消息,参见附录 B.若需要窗口消息的完全的列表,请参考 MFC文档. 3.4.2 命令消息 命令消息一般与处理用户请求相关,当用户单击一个菜单项或工具栏时,命令消息产生, 并

12、被发送到能处理该请求的类对象 (如,装载文件,编辑文本和保存选项等 ). 当用SendMessage( )或PostMessage( )发送窗口消息时,变量 Message,wParam和lParam的 格式如下: Message WM_COMMAND 0 wParam Command ID lParam 0 Command ID要么是选中菜单项的 I D,要么是被单击的工具栏按钮.注意 Command ID不 能大于一个字长,如果使它大于一个字长,系统就只用 0来填充高位字.某些控件通知也用 WM_COMMAND消息,区别两种消息的唯一方法是 lParam是否为NULL. 3.4.3 控件通

13、知 通常,控件通知在某些重要事件发生时,由控件窗口发送到父窗口,如打开一个组合框. 下载 组合框初建时得不到的消息填充它. 第3章 消 息 处 理 35 控件通知为父窗口进一步控制子窗口提供了机会.例如,打开一个组合框时,父窗口可以用 控件通知经历了一个演变过程,因而 SendMessage( )的变量M e s s a g e,w P a r a m和l P a r a m有 三种格式. 1. 第一控件通知格式 第一控件通知格式只是窗口消息的子集. Message WM_XXX wParam 定义的命令 lParam 定义的命令 WM_XXX可以是下面消息中的任何一种: W M _ PA R

14、 E N T N O T I F Y表示一个控件窗口要么已被建立或销毁,要么鼠标已单击了该 窗口. W M _ C T L C O L O R,W M _ D R AW I T E M,W M _ M E A S U R E I T E M,W M _ D E L E T E I T E M, W M _ C H A RTO I T E M,W M _ V K E Y TO I T E M或WM_COMPAREITEM都是送往父窗口的 消息,用来绘制自身的控件窗口. W M _ H S C R O L L或W M _ V S C R O L L由滚动条控件发送,通知父窗口滚动窗口. 2. 第二

15、控件通知格式 第二控件通知格式使用 WM_COMMAND消息,与命令消息共享. Message WM_COMMAND wParam XN_XXX 控件ID lParam 窗口句柄 l P a r a m变量用来区分是命令消息还是控件通知.控件通知在 l P a r a m中有一个有定义的句 柄,用来标识发出通知的控件;而命令消息中 lParam为NULL. X N _ X X X值因发出通知的控件不同而不同,例如, X N _ X X X值为E N _ C H A N G E,告诉父 窗口显示在编辑框控件中的文本已发生变化.还有其他一些例子列在附录 B中. 3. 第三控件通知格式 第三控件通知

16、格式也是最灵活的通知格式,它用 WM_NOTIFY消息. Message WM_NOTIFY wParam 控件ID lParam 指向NMHDR的指针 l P a r a m值指向一个结构,该结构包括有关制作该通知的控件的任何内容,而不受空间和 类型的限制,该结构叫做 NMHDR. typedef struct tagNMHDR HWND hwndFrom; / Window handle of Control Window / making the notification. UINT idFrom; / Control ID of Control Window / making the

17、notification. UINT code; / notification code ex: the user / has clicked the Control Window NMHDR; NMHDR代表通知消息头 (Notification Message Header).为什么要这个头?因为某些控件 用NMHDR作为头发送一个更大结构的消息,即使那些不知道更大结构内容的函数还是能处理 36 通知头. 第一部分 基 础 知 识 下载 3.5 MFC怎样接收一个寄送的消息 M F C处理一个寄送和发送消息的唯一明显不同是寄送的消息要在应用程序的消息队列中 花费一些时间.在消息泵 (mes

18、sage pump)弹出它之前,它要一直在队列中. 消息泵 MFC应用程序中的消息泵在 CWinApp的成员函数 Run( )中.应用程序开始运行时, Run( ) 就被调用, Run( )把时间分割成两部分.一部分用来执行后台处理,如取消临时 C W n d对象; 另一部分用来检查消息队列.当一个新的消息进来时, Run( )抽取它 即用GetMessage( )从 队列中取出该消息,运行两个消息翻译函数,然后用 DispatchMessage( )函数调用该消息预期 的目标窗口进程 (见图3-2). 空闲处理 (内务处理, 后台处理) 新的消息出 现在消息队 列中? 翻译字 符消息 发送消

19、息到 窗口进程 图3-2 消息泵执行后台处理并检查消息队列 消息泵调用的两个翻译函数是 PreTranslateMessage( )和:TranslateMessage( ).目标窗口的 M F C类可调用 P r e Tr a n s l a t e M e s s a g e在发送消息给它之前进行消息翻译,例如, C F r a m e W n d用 P r e TranslateMessage( )将加速键 (如,C t r l + S存储文件 )转换为命令消息.翻译前的消息通常被 处理掉,而翻译后的消息 (如果有的话 )将被重新寄送到队列里. :TranslateMessage是一个窗

20、口函数,将原始键码转换为键字符. 消息一旦被 DispatchMessage( )发送, M F C处理它就像处理 SendMessage( )发送的消息一 样. 3.6 MFC怎样处理一个接收到的消息 处理接收到的消息的目的非常简单:将消息指向一个函数,该函数通过消息中的消息标 识符处理它.非 MFC窗口用简单的case语句来实现该目标,每个 case语句执行一些函数,或调 用其他一些函数. MainWndProc(HWND hWnd, UINT message, W PARAM wParam, LPARAM lParam) switch(message) case WM_CREATE: :

21、 : : 下载 break; case WM_PAINT: : : : break; default: return(DefWindowProc(hWnd, message, wParam, lParam); return(NULL); 第3章 消 息 处 理 37 任何遗漏的消息将被传输到一个默认的消息处理函数,但是, c a s e语句不能很好地适应 C+和封装技术.在 C+环境中,要求消息被一个专门处理该类型消息的类的成员函数处理. 因此, M F C不采用 c a s e语句,而采用更加复杂和回旋的方法.但它允许用私有类处理消 息,而只需做下面三件事情: 从将要接收消息的 C W n

22、d类对象派生类(对于命令消息是 CCmdTarget). 在派生类中写一个处理消息的成员函数. 在类中定义一个查找表 (叫做消息映像 ),该表具有成员函数的条目和它要处理的消息的 标识符. 然后,MFC依次调用下面的函数,指引输入消息到处理函数. 1) AfxWndProc( )接收消息,寻找消息所属的 CWnd对象,然后调用 AfxCallWndProc( ). 2) AfxCallWndProc( )存储消息(消息标识符和参数 )供未来参考,然后调用 WindowProc( ). 3) WindowProc( ) 发送消息给 OnWndMsg( ) ,然后,如果消息未被处理,则发送给 De

23、fWindowproc( ). 4) OnWndMsg( )要么为WM_COMMAND消息调用OnCommand( ),要么为 WM_NOTIFY 消息调用 OnNotify( ).任何被遗漏的消息都将是一个窗口消息. OnWndMsg( )搜索类的消息 映像,以找到一个能处理任何窗口消息的处理函数.如果 OnWndMsg()不能找到这样的处理函 数,则把消息返回到 WindowProc( ),由它将消息发送给 DefWindowProc( ). 5) OnCommand( )查看这是不是一个控件通知 绝映射的消息, OnCommand( )就调用OnCmdMsg( ). 6) OnNotif

24、y( )也试图将消息映射到制造通知的控件;如果映射不成功, OnNotify( )就调 用相同的OnCmdMsg( )函数. 7) 根据接收消息的类, OnCmdMsg( )将在一个称为命令传递 (Command Routing)的过程中 潜在地传递命令消息和控件通知.例如,如果拥有该窗口的类是一个框架类,则命令和通知 消息也被传递到视图和文档类,并为该类寻找一个消息处理函数. 为什么要消息映像? 为什么要消息映像?这毕竟是C+语言;为什么OnWndMsg( )不为每个窗口消息调 用一个预定义的虚拟函数?因为它太占 CPU.若是那样,当扫描一个消息映像以加速 该过程时,OnWndMsg( )可

25、能会做出意想不到的事情,并陷入汇编器. 注意 通过重载 WindowProc( ) ,OnWndMsg( ) ,OnCommand( ) ,OnNotify( ) 或 ( l P a r a m不是 N U L L );如果它是, OnCommand( )就试图将消息映射到制造通知的控件;如果它不是一个控件通知,或者控件拒 38 第一部分 基 础 知 识 下载 OnCmdMsg( )可以修改这一过程.重载OnWndMsg( )可以在窗口消息被排序之前插入该 过程.重载OnCommand( )或OnNotify( )可以在消息被反射之前插入该过程. 消息映射和命令传递将在下面部分进行详细讨论.

26、现在,一步一步地跟踪窗口进程接收和解释一个消息. 1. AfxWndProc( ) 所有MFC窗口的窗口进程是: LRESULT AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam); 如果一个消息被发送,则 SendMessage( )本质上直接调用 AfxWndProc( );如果一个消息 被寄送,则消息泵通过 DispatchMessage( )调用AfxWndProc( ). AfxWndProc( )要做的第一件事是找到目标窗口的 C W n d对象.虽然一个窗口不知道它的 CWnd对象的任何情况,但应用程序在映

27、像中跟踪窗口和类的配对. 一旦CWnd对象被找到,AfxCallWndProc( )就会被调用. 2. AfxCallWndProc( ) AfxCallWndProc( )的原型是: LRES U LT AfxCallWndProc(CWnd *pWnd, HWND hWnd, UINT nMsg, WPARAM wParam, LPA R A M lParam); AfxCallWndProc( )保存消息为将来引用.事实上,即使以后改变消息中的参数,当窗口 进程用 Default( )成员函数进行默认处理时,窗口进程也将引用保存在这里的参数;一旦消息 保存,WindowProc( )就被

28、调用. 3. WindowProc( ) WindowProc( )的原型函数为: LRESULT WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam); WindowProc( )接着调用 OnWndMsg( ),它试图在类中为该消息寻找一个处理函数;任何 返回到WindowProc( )的未被处理的消息都被传输到 D e f WindowProc( );D e f WindowProc( )是 所有未被处理的消息的贮藏所.如果没有消息处理函数,并不意味着该消息不重要,例如, 几乎不需处理 WM_PAINT消息,但它是重要的,因为 D e f

29、 WindowProc( )用该消息来绘制窗口 的非客户区. 注意 MFC的CControlBar类(工具栏,对话条和状态栏的基类)重载WindowProc( ),如 果任何一个下面所列的消息未经处理就传给了控制条,它们将被发送回它的父类 (通常 是主框架类). WM_NOTIFY WM_DELETEITEM WM_COMMAND WM_COMPAREITEM WM_DRAWITEM WM_VKEYTOITEM WM_MEASUREITEM WM_CHARTOITEM 也可以在父窗口中自动地处理工具栏,状态栏或对话条的按钮.但是,应该尽可 能地将这些功能封装到工具栏,状态栏或对话条类中. CM

30、ainFrame( )类具有非常好的 集成特性. 4. OnWndMsg( ) OnWndMsg( )的原型函数为: BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pResult); 下载 第3章 消 息 处 理 39 当消息为WM_COMMAND时,OnWndMsg( )调用OnCommand( );当消息是WM_NOTIFY 时,则On WndMsg( )调用OnNotify( ).所有其他消息都被认为是窗口消息,并且 OnWndMsg( ) 搜索类中的消息映像以找到一个处理函数. 消息映像 OnWnd

31、Msg( )通过搜索类和派生类中的消息映像为窗口消息寻找一个消息处理函数.消 息映像是数据静态表,包含类中每个消息处理函数的一个条目.每个 CWnd的派生类可以有一 个消息映像 (见图3-3). CWnd2对象 如果CWnd在该消息映 像中不能找到一个消息 处理函数,则在下一个 派生CWnd的类中寻找 两个类从 CWnd 派生 CWnd1派生于 CWnd1对象 CWnd,CWnd2派生于 CWnd1.每个派生类 都有它自己的消息映 像 当消息进入 CWnd 中 时,首先在最顶层派 生类的消息映像中寻 找一个处理函数 CWnd对象 如果 CWnd找到一 个消息处理函数, 则用该消息调用它 图3-

32、3 OnWndMsg( )搜索消息映像为窗口消息定位消息处理函数 每个消息映像都被括在两个宏之间 BEGIN_MESSAGE_MAP(CXxx,CYyy) : : : Message Map entries : : : END_MESSAGE_MAP C X x x是该类的派生类名, C Y y y是OnWndMsg( )要搜索的下一个派生类名,通常 C X x x派 生于C Y y y;在下一个类中的 B E G I N _ M E S S A G E _ M A P宏标识派生它的类,以此类推,直到所 有类中的消息映像都被搜索为止.除了为 OnWndMsg( )标识消息映像的位置外,可以忽略这 些宏是怎样工作的. 每个消息映像条目使用下面的结构: struct AFX_MSGMAP_ENTRY UINT nMessage; UINT nCode; UINT nI

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1