下载

3下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 [VC-MFC编程实例]

[VC-MFC编程实例]

[VC-MFC编程实例]

zhouekn
2011-05-17 0人阅读 举报 0 0 暂无简介

简介:本文档为《[VC-MFC编程实例]pdf》,可适用于IT/计算机领域

本文由shashoushou贡献pdf。下载下载第章消息处理第章讨论了MFC用户界面的基本要素:窗口,窗口类和CWnd第章讨论了构成MFC库的其他类,尤其是那些构成MFC应用程序内核的类在本章中,我们将讨论MFC类和它们的窗口怎样进行互相通信的我们发现有三种类型的消息:窗口,命令(Command)和控件通知(ControlNotification),并且这些消息既可以发送(sent),也可以寄送(post)接着,将跟踪一个被MFC窗口进程处理的消息最后,将讨论重定向消息的方法发送或寄送一个消息第章已提及,每个窗口使用窗口进程处理发送给它的消息消息可以来自系统,你的应用程序或别的应用程序消息告诉窗口进程执行某个任务(如初始化自己,绘制或销毁一个窗口等),或者通知它发生某个事件(如鼠标正单击窗口)系统或应用程序有两种传输消息的方法:发送消息或寄送消息发送一个消息发送一个消息时,直接调用窗口的窗口进程通信是即时的,直到窗口进程为调用函数返回一个结果后,应用程序才能继续寄送一个消息寄送一个消息时,把消息发送到拥有那个窗口的应用程序消息队列中一有空闲,应用程序就搜索消息队列,并在消息队列中处理消息,即从队列中删除它们,并将它们发送到即定窗口通信将可能延迟,直到目标应用程序获得处理消息的时间调用函数发送消息后即返回,但结果只是表示消息寄送成功与否,而不是被调用窗口进程的结果(见图)窗口对象WndProc地址①被发送的消息直接调用该窗口的窗口进程消息泵消息n消息n消息n消息n消息队列③当应用程序空闲时,抽出寄送到队列中的消息并调用该窗口的窗口进程②被寄送的消息延迟在应用程序消息队列中图发送消息时通信是即时的,而寄送消息时通信可能延迟发送一个消息与寄送一个消息的比较鼠标和键盘消息通常是寄送的,而所有其他消息通常都是发送的在消息队列中,寄送下载有鼠标和键盘消息被处理之后第章消息处理的消息接受特殊的鼠标和键盘处理通常,应该尽量发送一个消息,除非想把动作延迟到所怎样使用MFC发送一个消息用MFC发送一个消息的方法是,首先,应获取接收消息的CWnd类对象的指针然后,调用CWnd的成员函数SendMessage()LRESULTRes=pWnd>SendMessage(UINTMsg,WPARAMwParam,LPARAMlParam)pWnd指针指向目标CWnd类对象变量Msg是消息,wParam和lParam变量包含消息的参数,如鼠标单击哪里或选择了什么菜单项目标窗口返回的消息结果放在变量Res中发送消息到一个没有CWnd类对象的窗口,可以用下列目标窗口的句柄直接调用WindowsAPI:LRESULTRes=::SendMessage(HWNDhWnd,UINTMsg,WPARAMwParam,LPARAMlParam)这里的hWnd是目标窗口的句柄怎样用MFC寄送一个消息用MFC寄送一个消息与发送一个消息几乎相同,但寄送时用PostMessage(),而不是用SendMessage()返回值Res也不一样,Res不是一个由目标窗口返回的值,而是一个布尔值,用来表示消息是否成功地放到消息队列中检索一个寄送消息正常情况下,一旦消息被寄送后,应用程序在后台发送它但是在特殊情况下,需要你自page己去删除一个消息,例如想在应用程序接收到某种消息之前停止应用程序有两种方法可以从应用程序消息队列中删除一个消息,但这两种方法都没有涉及MFC■第一种方法:在不干扰任何事情之下窥视消息队列,看看一个消息是否在那里BOOLres=::PeekMessage(LPMSGlpMsg,HWNDhWnd,UINTwMsFilterMin,UINTwMsgFilterMax,UINTwRemoveMsg)■第二种方法:实际上是等待,一直等到一个新的消息到达队列为止,然后删除并返回该消息BOOLres=::GetMessage(LPMSGlpMsg,HWNDhWnd,UINTwMsgFilterMin,UINTwMsgFilterMax)在这两种方法中,变量hWnd指定要截获消息的窗口,如果该变量设为NULL,所有窗口消息将被截获wMsgFilterMin和wMsgFilterMax变量与SendMessage()中的变量Msg相对应,指定查看消息的范围如果用",",则所有的消息都将被截获如果用WMKEYFIRST,WMKEYLAST或WMMOUSEFIRST,WMMOUSELAST,则所有键盘或鼠标的消息将被截获wRemoveMsg变量指定PeekMessage()是否应该真正地从队列中删除该消息(GetMessage()总是删除消息)该变量可以取两个值:■■PMREMOVE,PeekMessage()将删除消息PMNOREMOVE,PeekMessage()将把消息留在队列里,并返回它的一个拷贝当然,如果把消息留在消息队列中,然后再次调用PeekMessage()查看相同类型的消息,则将返回完全相同的消息第一部分基础知识下载lpMsg变量是一个指向MSG结构的指针,MSG包含检索到的消息typedefstructtagMSG{HWNDhwndwindowhandlemessageisintendedforUINTmessageWPARAMwParamLPARAMlParamDWORDtimethetimethemessagewasputinthequeuePOINTptthelocationofthemousecursorwhenthemessagewasputinthequeue}MSG三种类型的消息在MFC应用程序中传输的消息有三种类型:窗口消息,命令消息和控件通知窗口消息窗口消息(WindowMessage)一般与窗口的内部运作有关,如创建窗口,绘制窗口和销毁窗口等通常,消息是从系统发送到窗口,或从窗口发送到窗口当用SendMessage()或PostMessage()发送一个窗口消息时,变量Message,wParam和lParam的格式如下:MessageWMXXXwParam定义的命令lParam定义的命令WMXXX可以是许多窗口消息之一,如下列窗口:■WMCREATE,告诉窗口初始化自己■WMPAINT,告诉窗口绘制自己■WMMOUSEMOVE,告诉窗口鼠标移经它有关某些公共窗口消息,参见附录B若需要窗口消息的完全的列表,请参考MFC文档命令消息命令消息一般与处理用户请求相关,当用户单击一个菜单项或工具栏时,命令消息产生,并被发送到能处理该请求的类对象(如,装载文件,编辑文本和保存选项等)当用SendMessage()或PostMessage()发送窗口消息时,变量Message,wParam和lParam的格式如下:MessageWMCOMMANDwParamCommandIDlParamCommandID要么是选中菜单项的ID,要么是被单击的工具栏按钮注意CommandID不能大于一个字长,如果使它大于一个字长,系统就只用来填充高位字某些控件通知也用WMCOMMAND消息,区别两种消息的唯一方法是lParam是否为控件通知通常,控件通知在某些重要事件发生时,由控件窗口发送到父窗口,如打开一个组合框下载page组合框初建时得不到的消息填充它第章消息处理控件通知为父窗口进一步控制子窗口提供了机会例如,打开一个组合框时,父窗口可以用控件通知经历了一个演变过程,因而SendMessage()的变量Message,wParam和lParam有三种格式第一控件通知格式第一控件通知格式只是窗口消息的子集MessageWMXXXwParam定义的命令lParam定义的命令WMXXX可以是下面消息中的任何一种:■WMPARENTNOTIFY表示一个控件窗口要么已被建立或销毁,要么鼠标已单击了该窗口■WMCTLCOLOR,WMDRAWITEM,WMMEASUREITEM,WMDELETEITEM,WMCHARTOITEM,WMVKEYTOITEM或WMCOMPAREITEM都是送往父窗口的消息,用来绘制自身的控件窗口■WMHSCROLL或WMVSCROLL由滚动条控件发送,通知父窗口滚动窗口第二控件通知格式第二控件通知格式使用WMCOMMAND消息,与命令消息共享MessageWMCOMMANDwParamXNXXX控件IDlParam窗口句柄lParam变量用来区分是命令消息还是控件通知控件通知在lParam中有一个有定义的句柄,用来标识发出通知的控件而命令消息中lParam为XNXXX值因发出通知的控件不同而不同,例如,XNXXX值为ENCHANGE,告诉父窗口显示在编辑框控件中的文本已发生变化还有其他一些例子列在附录B中第三控件通知格式第三控件通知格式也是最灵活的通知格式,它用WMNOTIFY消息MessageWMNOTIFYwParam控件IDlParam指向NMHDR的指针lParam值指向一个结构,该结构包括有关制作该通知的控件的任何内容,而不受空间和类型的限制,该结构叫做NMHDRtypedefstructtagNMHDR{HWNDhwndFromWindowhandleofControlWindowmakingthenotificationUINTidFromControlIDofControlWindowmakingthenotificationUINTcodenotificationcodeex:theuserhasclickedtheControlWindow}NMHDRNMHDR代表通知消息头(NotificationMessageHeader)为什么要这个头因为某些控件用NMHDR作为头发送一个更大结构的消息,即使那些不知道更大结构内容的函数还是能处理通知头第一部分基础知识下载MFC怎样接收一个寄送的消息MFC处理一个寄送和发送消息的唯一明显不同是寄送的消息要在应用程序的消息队列中花费一些时间在消息泵(messagepump)弹出它之前,它要一直在队列中消息泵MFC应用程序中的消息泵在CWinApp的成员函数Run()中应用程序开始运行时,Run()就被调用,Run()把时间分割成两部分一部分用来执行后台处理,如取消临时CWnd对象另一部分用来检查消息队列当一个新的消息进来时,Run()抽取它即用GetMessage()从队列中取出该消息,运行两个消息翻译函数,然后用DispatchMessage()函数调用该消息预期的目标窗口进程(见图)空闲处理(内务处理,后台处理)新的消息出现在消息队列中page翻译字符消息发送消息到窗口进程图消息泵执行后台处理并检查消息队列消息泵调用的两个翻译函数是PreTranslateMessage()和::TranslateMessage()目标窗口的MFC类可调用PreTranslateMessage在发送消息给它之前进行消息翻译,例如,CFrameWnd用PreTranslateMessage()将加速键(如,CtrlS存储文件)转换为命令消息翻译前的消息通常被处理掉,而翻译后的消息(如果有的话)将被重新寄送到队列里::TranslateMessage是一个窗口函数,将原始键码转换为键字符消息一旦被DispatchMessage()发送,MFC处理它就像处理SendMessage()发送的消息一样MFC怎样处理一个接收到的消息处理接收到的消息的目的非常简单:将消息指向一个函数,该函数通过消息中的消息标识符处理它非MFC窗口用简单的case语句来实现该目标,每个case语句执行一些函数,或调用其他一些函数MainWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam){switch(message){caseWMCREATE::::下载breakcaseWMPAINT::::breakdefault:return(DefWindowProc(hWnd,message,wParam,lParam))}return()}第章消息处理任何遗漏的消息将被传输到一个默认的消息处理函数,但是,case语句不能很好地适应C和封装技术在C环境中,要求消息被一个专门处理该类型消息的类的成员函数处理因此,MFC不采用case语句,而采用更加复杂和回旋的方法但它允许用私有类处理消息,而只需做下面三件事情:■从将要接收消息的CWnd类对象派生类(对于命令消息是CCmdTarget)■在派生类中写一个处理消息的成员函数■在类中定义一个查找表(叫做消息映像),该表具有成员函数的条目和它要处理的消息的标识符然后,MFC依次调用下面的函数,指引输入消息到处理函数)AfxWndProc()接收消息,寻找消息所属的CWnd对象,然后调用AfxCallWndProc())AfxCallWndProc()存储消息(消息标识符和参数)供未来参考,然后调用WindowProc())WindowProc()发送消息给OnWndMsg(),然后,如果消息未被处理,则发送给DefWindowproc())OnWndMsg()要么为WMCOMMAND消息调用OnCommand(),要么为WMNOTIFY消息调用OnNotify()任何被遗漏的消息都将是一个窗口消息OnWndMsg()搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数如果OnWndMsg()不能找到这样的处理函数,则把消息返回到WindowProc(),由它将消息发送给DefWindowProc())OnCommand()查看这是不是一个控件通知绝映射的消息,OnCommand()就调用OnCmdMsg())OnNotify()也试图将消息映射到制造通知的控件如果映射不成功,OnNotify()就调用相同的OnCmdMsg()函数)根据接收消息的类,OnCmdMsg()将在一个称为命令传递(CommandRouting)的过程中潜在地传递命令消息和控件通知例如,如果拥有该窗口的类是一个框架类,则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数为什么要消息映像为什么要消息映像这毕竟是C语言为什么OnWndMsg()不为每个窗口消息调用一个预定义的虚拟函数因为它太占CPU若是那样,当扫描一个消息映像以加速该过程时,OnWndMsg()可能会做出意想不到的事情,并陷入汇编器注意通过重载WindowProc(),OnWndMsg(),OnCommand(),OnNotify()或(lParam不是NULL)如果它是,OnCommand()就试图将消息映射到制造通知的控件如果它不是一个控件通知,或者控件拒第一部分基础知识下载OnCmdMsg()可以修改这一过程重载OnWndMsg()可以在窗口消息被排序之前插page入该过程重载OnCommand()或OnNotify()可以在消息被反射之前插入该过程消息映射和命令传递将在下面部分进行详细讨论现在,一步一步地跟踪窗口进程接收和解释一个消息AfxWndProc()所有MFC窗口的窗口进程是:LRESULTAfxWndProc(HWNDhWnd,UINTnMsg,WPARAMwParam,LPARAMlParam)如果一个消息被发送,则SendMessage()本质上直接调用AfxWndProc()如果一个消息被寄送,则消息泵通过DispatchMessage()调用AfxWndProc()AfxWndProc()要做的第一件事是找到目标窗口的CWnd对象虽然一个窗口不知道它的CWnd对象的任何情况,但应用程序在映像中跟踪窗口和类的配对一旦CWnd对象被找到,AfxCallWndProc()就会被调用AfxCallWndProc()AfxCallWndProc()的原型是:LRESULTAfxCallWndProc(CWnd*pWnd,HWNDhWnd,UINTnMsg,WPARAMwParam,LPARAMlParam)AfxCallWndProc()保存消息为将来引用事实上,即使以后改变消息中的参数,当窗口进程用Default()成员函数进行默认处理时,窗口进程也将引用保存在这里的参数一旦消息保存,WindowProc()就被调用WindowProc()WindowProc()的原型函数为:LRESULTWindowProc(UINTnMsg,WPARAMwParam,LPARAMlParam)WindowProc()接着调用OnWndMsg(),它试图在类中为该消息寻找一个处理函数任何返回到WindowProc()的未被处理的消息都被传输到DefWindowProc()DefWindowProc()是所有未被处理的消息的贮藏所如果没有消息处理函数,并不意味着该消息不重要,例如,几乎不需处理WMPAINT消息,但它是重要的,因为DefWindowProc()用该消息来绘制窗口的非客户区注意MFC的CControlBar类(工具栏,对话条和状态栏的基类)重载WindowProc(),如果任何一个下面所列的消息未经处理就传给了控制条,它们将被发送回它的父类(通常是主框架类)WMNOTIFYWMDELETEITEMWMCOMMANDWMCOMPAREITEMWMDRAWITEMWMVKEYTOITEMWMMEASUREITEMWMCHARTOITEM也可以在父窗口中自动地处理工具栏,状态栏或对话条的按钮但是,应该尽可能地将这些功能封装到工具栏,状态栏或对话条类中CMainFrame()类具有非常好的集成特性OnWndMsg()OnWndMsg()的原型函数为:BOOLOnWndMsg(UINTmessage,WPARAMwParam,LPARAMlParam,LRESULT*pResult)下载第章消息处理当消息为WMCOMMAND时,OnWndMsg()调用OnCommand()当消息是WMNOTIFY时,则OnWndMsg()调用OnNotify()所有其他消息都被认为是窗口消息,并且OnWndMsg()搜索类中的消息映像以找到一个处理函数消息映像OnWndMsg()通过搜索类和派生类中的消息映像为窗口消息寻找一个消息处理函数消息映像是数据静态表,包含类中每个消息处理函数的一个条目每个CWnd的派生类可以有一个消息映像(见图)CWnd对象③如果CWnd在该消息映像中不能找到一个消息处理函数,则在下一个派生CWnd的类中寻找①两个类从CWnd派生CWnd派生于CWnd对象CWnd,CWnd派生于CWnd每个派生类都有它自己的消息映像②当消息进入CWnd中时,首先在最顶层派生类的消息映像中寻找一个处理函数CWnd对象④如果CWnd找到一个消息处理函数,则用该消息调用它图OnWndMsg()搜索消息映像为窗口消息定位消息处理函数page每个消息映像都被括在两个宏之间BEGINMESSAGEMAP(CXxx,CYyy):::MessageMapentries:::ENDMESSAGEMAPCXxx是该类的派生类名,CYyy是OnWndMsg()要搜索的下一个派生类名,通常CXxx派生于CYyy在下一个类中的BEGINMESSAGEMAP宏标识派生它的类,以此类推,直到所有类中的消息映像都被搜索为止除了为OnWndMsg()标识消息映像的位置外,可以忽略这些宏是怎样工作的每个消息映像条目使用下面的结构:structAFXMSGMAPENTRY{UINTnMessageUINTnCodeUINTnIDUINTnLastIDUINTnSigAFXPMSGpfn}第一部分基础知识下载■UNINT■UNINTnMessage标识特定的WMXXX消息nCode是控件通知代码,对于窗口消息该值为我们将在下文中看到,处理命令消息和控件通知的函数使用与此相同的消息映像■UINT■UINTnID是命令ID,对于窗口消息该值为nLastID是以nID开始的命令ID范围内的最后一个命令ID,对于窗口消息该值为nSig定义消息处理函数的调用变量在AFXMSGH中,为nSig预定义了多个处理命令消息的函数能够处理某一范围的ID■UINT值,例如,nSig值为iww,则在调用消息处理函数前,使OnWndMsg()格式化wParam和lParam为两个UINT变量,返回值为整型■AFXPMSGpfn是消息处理函数的地址因此,当OnWndMsg()得到一个窗口消息时,在它的派生类中寻找第一个消息映像然后,OnWndMsg()扫描那里的条目进行nMessage匹配,如果找到,它就格式化wParam和lParam为nSig指定的调用变量,并调用pfn指定的函数如果没有在第一个消息映像中找到一个条目,它将检查BEGINMESSAGEMAP宏找出下一个要扫描的消息映像,以此类推,直到检查完一个对象中的所有消息映像为止如果OnWndMsg()扫描一个对象中的所有消息映像后,没有发现消息处理函数,则窗口消息返回给WindowProc(),接着由它将消息发送给DefWindowProc()消息映像宏AFXMSGH不仅包含nSig的预定义值,还包含一些有助于简化创建消息映像条目的宏这些宏以两种格式出现:■ONMESSAGE宏用来处理任何WMXXX消息■一个以ONWMXXX形式出现的窗口消息宏,这里的WMXXX是任何当前定义的窗口消息通常,应该用ClassWizard自动地将这些宏添加到类的消息映像中(见例)但是,不是所有这些宏都可以被自动添加,这时,可以通过参考附录B中宏的详细列表,手工添加这些宏OnCommand()下面,继续讨论WMCOMMAND消息,上面我们已经看到,它们被发送到OnCommand()进行处理LRESULTOnCommand(WPARAMwParam,LPARAMlParam)此时,一个WMCOMMAND消息既可以是命令消息,也可以是一个控件通知OnCommand()查看lParam是不是一个有效的窗口句柄,如果是,则OnCommand()以控件通知处理该消息,这里lParam是控件的句柄,并且将消息反射到发送它的窗口消息反射前面已提及,当控件状态发生变化时,控件通知被发送到父窗口因此,控件通知提供给父窗口有限的能力,用来定制和补充控件工作的方式例如,当一个组合框下拉时,父窗口通过修改下拉列表内容作出反应然而,把这项功能交给父窗口违背了面向对象编程的意图,因为它要求每个对象都应该page下载第章消息处理包括所有属于它自己的功能在上面的例子中,每次组合框移到一个新的父窗口中,则下拉功能也要移到新的父窗口因此,将控件通知处理功能交给控件会更可取因为每个控件已经有一个可以通过重载添加其他功能的MFC类,所以若能按照那列表来处理控件通知的话将会是非常好的这样,每当把控件移到一个新的父窗口时,不必考虑必须把哪些代码拷贝到新的父窗口MFC用一个叫做"消息映射"的过程来支持该项功能无论什么时候,当MFC窗口刚刚接收到一个控件通知时,它知道该通知有一个控件窗口在某处,并且很可能有一个MFC派生类在控制它,因此,MFC窗口试图将那通知映射回到MFC派生类,并给它处理该通知的机会(见图)用这种方法可以将任何一个控件的所有功能放到一个井然有序的类包里④CMyButton可能有一个该消息的处理函数,若没有,则CMyDialog使它返回CMyButton类对象CMyDialog类对象③CMyDialog用子分类截获该消息,查看它是否是控件通知若是,则把它提供给控制该窗口的MFC类,即CMyButton⑤如果CMyDialog也不接收该通知,则最后由对话窗口进程处理它①创建一个CMyButton类和一个CMyDialog类,以及它们的窗口对象,使按钮控件成为该对话的一个子窗口按钮窗口进程对话窗口进程②按钮窗口进程发送控件通知到它的父窗口,如BNCLICKED图消息映射提供了使控件通知返回到控件窗口的功能如果控件不想该消息返回,OnCommand()如处理通用消息一样处理该消息,并调用OnCmdMsg()OnNotify()WMNOTIFY消息被发送到OnNotify()函数BOOLOnNotify(WPARAMwParam,LPARAMlParam,LRESULTlResult)任何发送到这里的消息都自动地被认为是一个控件通知,并且消息被反射如果控件类不想该消息返回,则OnNotify()调用OnCmdMsg()OnCommand()和OnNotify()都调用ReflectLastMsg(),以提供一个控件通知返回到它的控件窗口ReflectLastMsg()获取控件窗口的窗口句柄,并在它的消息映像中寻找WMCOMMANDWMREFLECTBASE或WMNOTIFYWMREFLECTBASE和通知代码消息映像宏有三组预定义的宏(每种控件通知格式对应一组),在控件窗口消息映像中,可以用它来处理它所反射的消息:■ONWMXXXREFLECT()用于第一控件通知格式第一部分基础知识下载■ONCONTROLREFLECT(■ONNOTIFYREFLECT()用于第二控件通知格式)用于第三控件通知格式请参考附录B,以获得有关的详细列表OnCmdMsg()如果一个控件通知被它的控件窗口拒绝,则OnCommand()和OnNotify()通过调用下面的函数,像处理命令消息一样处理它:BOOLOnCmdMsg(UINTnID,intnCode,void*pExtra,AFXCMDHANDLERINFO*pHandlerInfo)这里:■UINT■IntnID是命令IDnCode是通知代码对于一个命令消息,该变量将赋值为CNCOMMAND(相当于)*pExtra取决于正被处理的消息的类型:Pextra包含的内容指向NMHDR的AFXNOTIFY结构的指针指向CCmdUI派生类的指针(后面将讨论)page■Void消息类型WMNOTIFY控件通知菜单项和工具栏更新(启用,禁用等)任何其他类型■当OnCommand()或OnNotify()调用OnCmdMsg()时,AFXCMDHANDLERINFO*pHandlerInfo总是为当该变量不包含一个AFXCMDHANDLERINFO结构指针时,OnCmdMsg()不执行任何它所找到的命令消息处理函数相反,OnCmdMsg()只是返回它本应执行的处理函数的地址structAFXCMDHANDLERINFO{CCmdTarget*pTargettheobjectthefunctionresidesinvoid(AFXMSGCALLCCmdTarget::*pmf)(void)thefunctionaddress}当启用或禁用菜单项和工具栏按钮时,将使用该附加功能,我们将在下文中讨论接着,在一个称为命令传递的过程中,命令消息和控件通知被提供给一些类命令传递OnCmdMsg()实际上是CCmdTarget的成员函数,而不是CWnd的成员函数认识这一点很重要,因为它允许任何从CCmdTarget派生的类接收一个命令消息,即使那些没有一个窗口的类也可以例如,文档类没有相关联的窗口,它依赖视图类显示它的文档但是一个文档类是处理一个装载或保存命令的最好的地方,因此,虽然一个文档类不能处理类似于WMCREATE或WMDESTROY的命令消息但OnCmdMsg()允许它处理类似于WMCOMMAND和WMNOTIFY的命令消息CWnd本身是从CCmdTarget派生而来的,因此,它也能支持命令消息,如图所示在所有的主应用程序类(应用程序,框架,视图和文档类)中,MFC通过重载OnCmdMsg()执行命令传递例如,视图类重载OnCmdMsg(),使它能为文档类提供命令和控件通知消息文档类重载OnCmdMsg(),使它能为文档模板类提供命令消息下面的列表显示了命令和控件通知怎样被传递到应用程序的主类:下载框架消息映像②在查看它自己的消息映像以前,框架类中的OnCmdMsg()首先调用视图类的OnCmdMsg()视图消息映像文档消息映像第章消息处理⑤在初始的IDFILESAVE消息被框架窗口接收以后,该消息使用OnCmdMSg()重载函数在类间传输框架类中的OnCmdMsg()重载函数视图类中的OnCmdMsg()重载函数文档类中的OnCmdMsg()重载函数④文档类中的OnCmdMsg()检查消息映像,如果找到OnSaveFile(),则调用它③视图类中的OnCmdMsg()函CWnd窗口进程数检查它的消息映像,如果没找到任何东西,则调用文档类中的OnCmdMsg()①主菜单发送IDFILESAVE消息到框架窗口进程图CCmdTarget支持没有窗口的MFC对象的消息映像OnCmdMsg()命令传递发送到MFC类的命令消息CFrameWnd按下面的顺序传递到所列类中拥有输入焦点的所有Cview的派生类它自身的消息映像所有CwinApp的派生类CMDIFrameWnd拥有输入焦点的所有CMDICHildWnd的派生类拥有输入焦点的所有Cview的派生类它自身的消息映像所有CwinApp的派生类CMDIChildWndCViewCDocumentCDialog它自身的消息映像它自身的消息映像所有CDocument的派生类它自身的消息映像所有CDocumentTemplate的派生类它自身的消息映像它的父类的消息映像它的线程的消息映像CPropertySheet它自身的消息映像它的父类的消息映像它的线程的消息映像传递效果具有累积性被发送到CMDIFrameWnd的命令消息,首先被提供给有效的CMDIFrameWnd中的消息映像,接着给有效的CView,有效CView的CDocument,那个文档的CDocTemplate,CMDIFrameWnd自身的消息映像,最后给CWinApp一旦OnCmdMsg()找到一个消息处理函数,命令传递就停止在前面的例子中,如果OnCmdMsg()在CDocument中找到一个处理函数,它将用page命令消息调用该处理函数并返回结果,而不用继续传递给CDocTemplate消息映像宏虽然命令消息和控件通知被传递的方法是相同的,但是它们预定义的消息映像宏却是不同的命令消息采用的形式为:第一部分基础知识下载ONCOMMAND()而控件通知采用的一般形式为:ONCONTROL()ONNOTIFY()为WMCOMMAND通知为WMNOTIFY通知参见附录B的详细列表参见图⑥OnWndMsg()发送WMCOMMAND消息到OnNotify(),发送WMNOTIFY到OnNotify(),而为剩下的消息在找到的类的消息映像中寻找一个处理函数②AfxWndProc()找到拥有该窗④WindowProc()调口的类对象,并调用用OnWndMsg()AfxWndCallProc()⑧根据类的类型,OnCmdMsg()可能调用其他类中OnCmdMsg()重载函数否则,在该类的消息映像中搜索一个处理函数①发送到所有由MFC创建的窗口中的消息都被AfxWndProc()处理③AfxWndCallproc()保⑤任何未被OnWndMsg()处存消息后调用找到的类的WindowProc(),从现在起,所有被调用的函数都可以被重载理的消息被发送到DefWindowProc()⑦OnCommand()和OnNotify()把控件通知反射回到控制类(未显示出来)任何未被反射的消息被发送到OnCmdMsg()⑨通过完成所有这些过程,消息可以在类中被处理,控件通知可以被反射回到它们的控件,而命令消息可以被传递到应用程序的任何地方图描述MFC如何处理接受的信息处理用户界面的对象刚刚讨论过的一些成员函数也被MFC用来更新用户界面的状态具体地讲,MFC用OnCmdMsg()来启用,禁用或检查一个菜单中的所有菜单项和控制条中的所有控件(工具栏,对话条和状态栏)无论何时打开一个菜单项,MFC都将更新菜单项的状态每当应用程序空闲时,它就更新控制条中控件的状态对于任一事件,MFC进入一个循环,在该循环中为每个菜单项或控制条控件调用OnCmdMsg(),最多可达两次第一次调用OnCmdMsg()时,应用程序可以自己启用或禁用菜单项或控件如果不能为请求的行为提供一个特定的用户界面处理函数,则OnCmdMsg()被第二次调用,以检查菜单项或控件究竟有没有一个消息处理函数,如果没有,OnCmdMsg()将自动禁用菜单项或控件注意如果想关闭这一自动禁用特性,可以将CMainFrame类中的mbAutoMenuEnable设为FALSE但是,这对工具栏不起作用当OnCmdMsg()被调用,并允许应用程序更新界面时,它被赋予如下参数:OnCmdMsg(nID,CNUPDATECOMMANDUI,CCmdUI*pCmdUI,)■nID是需要更新的菜单项或控制条控件的控件ID下载第章消息处理■*pCmdUI指向一个类,该类包含允许应用程序更新菜单项和控件的成员函数接着,按命令消息中相同的次序,OnCmdMsg()仔细查看相同的消息映像,直到发现一个特定的用户界面消息处理函数处理CNUPDATECOMMANDUI的预定义的宏是:ONUPDATECOMMANDUI(id,Handler)对于某一范围内的控件ID,预定义的宏是:ONUPDATECOMMANDUIRANGE(id,idLast,Handler)对于每个宏,处理函数有相同的格式:voidHandler(CCmdUI*pCmdUI){pCmdUI>Enable(pFlag)}pageCCmdUI对象包含如下重要的成员变量和函数:■mnID是控件ID,当某个范围的控件ID可以用相同的处理函数更新时,它对第二宏格式是有用的■Enable(BOOLbOn),如果bOn设为FALSE,将使菜单项或控件无效(intnCheck),如果nCheck为,则将检查菜单项(BOOLbOn),更新单选按钮■SetCheck■SetRadio■SetText(LPCTSTRstring),设置控件或菜单项的文本这些成员函数中的每一个都被重载,以便当菜单被更新时,调用禁用菜单项的代码,当一个控制条被更新时,调用禁用控件的代码当OnCmdMsg()被第二次调用来确定应用程序是否有一个菜单项或控件的处理函数时,它被赋予如下变量:BOOLbHandler=OnCmdMsg(nID,CNCOMMAND,CCmdUI*pCmdUI,AFXCMDHANDLERINFO*info)在第一次看到OnCmdMsg()的变量时已提及,存在一个AFXCMDHANDLERINFO结构的指针,使OnCmdMsg()只查找一个消息处理函数而不执行如果返回值为FALSE,则没有处理函数,菜单项和控件被禁用关于用CCmdUI类对象更新用户界面的例子,参见例,例,例创建自定义窗口消息从WMNULL到WMUSER有个系统定义的窗口消息根据自己的意愿,用户可以创建两种自定义的窗口消息:静态定义的大于WMUSER值的窗口消息,在给定字符串标识符时由系统动态定义的窗口消息注意请记住,窗口消息主要是为窗口内在运行机制设计的,而不是为处理用户命令设计的如果只想告诉应用程序的一部分或别的应用程序处理一个用户命令,那么用已定义的WMCOMMAND窗口消息和一个新的命令ID静态分配的窗口消息Windows保留了和WMUSER之间的整数范围,作为系统定义的窗口消息还有一个定义消息:第一部分基础知识下载从WMUSER一直到OXfff的整数范围,留给自定义消息用可以用一个简单的#define语句#defineWMMYMESSAGEWMUSER#defineWMMYMESSAGEWMUSER:::然后,可以像处理任何其他窗口消息一样,发送或寄送这些消息SendMessage(WMMYMESSAGE,wParam,lParam)或PostMessage(WMMYMESSAGE,wParam,lParam)可以用下面的宏在消息映像中获取这些新消息:ONMESSAGE(WMMYMESSAGE,Handler)在这里,处理函数将具有如下格式:LRESULTHandler(WPARAM,LPARAM){}通过修改下面的宏,可以定义完全属于用户自己的消息映像宏#defineONMYMESSAGE(){WMMYMESSAGE,,,,AfxSiglwl,(AFXPMSG)(AFXPMSGW)(LRESULT(AFXMSGCALLCWnd::*)(WPARAM,PARAM))OnMyMessage},在这里,自动赋予处理函数名为OnMessage,但还是具有相同的调用变量为了改变调用变量,在AfXMSGH文件中寻找一个更加合适的nSig值,并替换AfxSiglwl,然后修改宏中的最后一行,以映射新变量有关例子参见例动态分配的窗口消息为了在应用程序间发送消息,应该用下面的语句创建一个基于描述性字符串的新的窗口消息UINTwmMyMessage=:

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/13

[VC-MFC编程实例]

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利