按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
545
…………………………………………………………Page 608……………………………………………………………
第篇 深入 MFC 程式設計
546
…………………………………………………………Page 609……………………………………………………………
第9章
消息映射与命令绕行
Message Mapping and mand Routing
消息映射机制与命令绕行,活像是米诺托斯的迷宫,
是MFC 最曲折幽深的神秘地带。
你已经从前一章中彻底了解了MFC 程序极端重要的Document/View 架构。本章的重点
有两个,第一个是修改程序的人机接口,增添菜单项目和工具栏按钮。这一部份藉Visual
C++ 工具之助,非常简单,但是我们往往不知道该在程序的什么地方(哪一个类别之中)
处理来自菜单和工具栏的消息(也就是WM_MAND 消息)。本章第二个重点就是
要解决这个迷惑,我将对所谓的消息映射(Message Map )和命令绕行(mand Routing)
机制做深入的讨论。这两个机制宛如MFC 最曲折幽深的神秘地带,是把杂乱无章的
Windows API 函数和Windows 消息对象导向化的大功臣。
到底要解决什么
Windows 程序的本质系借着消息来维持脉动。每一个消息都有一个代码,并以WM_ 开
头的常数表示之。消息在传统SDK 程序方法中的流动以及处置方式,在第1章已经交
待得很清楚。
各种消息之中,来自菜单或工具栏者,都以WM_MAND 表示,所以这一类消息我
们又称之为命令消息(mand Message ),其wParam 记录着此一消息来自哪一个菜单
项目。
547
…………………………………………………………Page 610……………………………………………………………
第篇 深入 MFC 程式設計
除了命令消息,还有一种消息也比较特殊,出现在对话框函数中,是控制组件(controls )
传送给父窗口(即对话框)的消息。虽然它们也是以WM_MAND 为外衣,但特别
归类为「notification 消息」。
注意:Windows 95 新的控制组件(所谓的mon controls )不再传送WM_MAND
消息给对话框,而是送WM_NOTIFY 。这样就不会纠缠不清了。但为了回溯兼容,旧有
的控制组件(如edit 、list box、bo box。。。 )都还是传送WM_MAND。
消息会循着Application Framework 规定的路线,游走于各个对象之间,直到找到它的依
归(消息处理函数)。找不到的话,Framework 最终就把它交给::DefWindowProc 函数
去处理。
但愿你记忆犹新,第6章曾经挖掘MFC 源代码,得知MFC 在为我们产生窗口之前,
如果我所指定的窗口类别是NULL ,MFC 会自动先注册一个适当的窗口类别。这个类别
在动态联结、除错版、非Unicode 环境的情况下,可能是下列五种窗口类别之一:
〃AfxWnd42d〃
〃AfxControlBar42d〃
〃AfxMDIFrame42d〃
〃AfxFrameOrView42d〃
! AfxOleControl42d!§ ¨
每一个窗口类别有它自己的窗口函数。根据SDK 的基础,我们推想,不同窗口所获得
的消息,应该由不同的窗口函数来处理。如果都没有能够处理,最后再交由Windows API
函数::DefWindowProc 处理。
这是很直觉的想法,而且对于一般消息(如WM_MOVE 、WM_SIZE、WM_CREATE 等)
也是天经地义的。但是今天Application Framework 比传统的SDK 程序多出了一个
Document/View 架构,试想,如果菜单上有个命令项关乎文件的处理,那么让这个命令
548
…………………………………………………………Page 611……………………………………………………………
第9章 訊息映射與命令繞行
消息流到Document 类别去不是最理想吗?一旦流入Document 大本营,我们(程序员)
就可以很方便地取得Document 成员变量、调用Document 成员函数,做爱做的事。
但是Document 不是窗口,也没有对应的窗口类别,怎么让消息能够七拐八弯地流往
Document 类别去?甚至更往上流向Application 类别去?这就是所谓的命令绕行机制!
而为了让消息的流动有线路可循,MFC 必须做出一个巨大的网,实现所有可能的路线,
这个网就是所谓的消息映射地图(Message map )。最后,MFC 还得实现一个消息推动
引擎,让消息依Framework 的意旨前进,该拐的时候拐,该弯的时候弯,这个邦浦机制
埋藏在各个类别的WindowProc、Onmand、OnCmdMsg、DefWindowProc 虚拟函数
中。
没有命令绕行机制,Document/View 架构就像断了条胳臂,会少掉许多功用。
很快你就会看到所有的秘密。很快地,它们统统不再对你构成神秘。
消息分类
Windows 的消息都是以WM_xxx 为名,WM_ 的意思是〃Windows Message〃。消息可以
是来自硬件的「输入消息」,例如WM_LBUTTONDOWN ,也可以是来自USER 模块的
「窗口管理消息」,例如WM_CREATE。这些消息在MFC 程序中都是隐晦的(我的意
思是不像在SDK 程序中那般显明),我们不必在MFC 程序中撰写switch case 指令,
不必一一识别并处理由系统送过来的消息;所有消息都将依循Framework 制定的路线,
并参照路中是否有拦路虎(你的消息映射表格)而流动。WM_PAINT 一定流往你的
OnPaint 函数去,WM_SIZE 一定流往你的OnSize 函数去。
所有的消息在MFC 程序中都是暗潮汹涌,但是表面无波。
MFC 把消息分为三大类:
■ 命令消息(WM_MAND):命令消息意味着「使用者命令程序做某些动作」。
凡由UI 对象产生的消息都是这种命令消息,可能来自菜单或加速键或工具栏
549
…………………………………………………………Page 612……………………………………………………………
第篇 深入 MFC 程式設計
按钮,并且都以WM_MAND 呈现。如何分辨来自各处的命令消息?SDK
程序主要靠消息的wParam 辨识之,MFC 程序则主要靠菜单项目的识别码
(menu ID )辨识之…两者其实是相同的。
什么样的类别有资格接受命令消息?凡衍生自CCmdTarget 之类别,皆有资格。从
mand target 的字面意义可知,这是命令消息的目的地。也就是说,凡衍生自
CCmdTarget 者,它的骨子里就有了一种特殊的机制。把整张MFC 类别阶层图摊开
来看,几乎构造应用程序的最重要的几个类别都衍生自CCmdTarget,剩下的不能接
收消息的,是像CFile、CArchive、CPoint、CDao (数据库)、