- /*
- 编程框架调用消息响应函数的原理
- 1:消息的发送与接收
- 大多数的消息来源于用户与程序的交互。命令消息来源于鼠标对菜单及工具栏的
- 点击及快捷键的按下。当用户改变窗口的大小或位置时,也会产生消息。另外,
- 当启动或关闭程序及窗口得到或失去焦点时也会产生普通消息。控件通知消息产生
- 自己鼠标对控件的操作,比如对话框上的按钮或列表框被点击时。
- 类CWinApp的Run方法会从消息队列中提取消息,然后再将它们发送到相关的窗口。
- 多数的命令消息会被发送到程序的主窗口。类库预先定义的WindowProc会得到这些
- 消息然后根据消息的不同类型采用不同的路由方式进行路由。
- 消息的接收细节:
- 消息的最初接收者必须是一个窗口对象。普通消息通常由窗口对象直接处理,
- 命令消息,通常来自于主窗口,会根据命令-目标链进行路由。
- 每一个能够接收消息或命令的对象都具有自身的消息映射,这个映射可以将
- 消息或命令与其处理函数联系起来。
- 当一个命令目标对象接收到一个消息或者命令,它会检查自身的消息映射,
- 如果它发现自身具有一个处理此消息或命令的处理函数,就是调用之。
- 2:非命令消息与其处理函数的关联
- 不像命令消息,标准的Windows消息不会通过命令目标链进行路由,而是由接收此
- 消息的窗口直接处理。这个窗口可能是主窗口,也可能是多文档子窗口,也可能
- 是标准控件或对话框或视图等。
- 在运行时,每一个Windows窗口都与一个窗口对象(派生自CWnd)联系在一起,
- 这个窗口对象具有与自身相关联的消息映射和处理函数群。编程框架会通过这个
- 消息映射,像命令消息一样,将消息与处理函数联系起来。
- 3: 命令路由
- 在与涉及到命令消息的工作中,程序员的责任公局限于搭建一个消息映射以建立命令
- 与处理函数之间的联系。这个任务可以通过属性窗口完成。有一点很重要,就是程序
- 员要写命令处理函数体。
- Windows标准消息通常发送给主窗口,但是命令消息在此基础上还得被路由到其它
- 对象。编程框架以一个标准的序列在命令目标对象间路由命令消息,这些对象的一个
- 应该有与正在被路由的命令相对应的处理函数。每一个命令目标对象都会检查自己
- 的消息映射表以决定自己可否处理当前命令。
- 不同的命令目标类会在不同的时间检查自己的消息映射表,通常情况下,一个类会
- 先在一些特定的对象间路由命令以给这些对象优先的处理权,如果这些特定的对象
- 无法处理这个命令,这个类就会检查自身的消息映射表。如果其自身也无法提供一个
- 处理函数,那么它会在其它的更多的对象间路由这个命令。
- 命令路由的通常顺序如下:
- A:自己当前的处理活动状态的子对象。
- B:自己
- C:其它
- 命令路由花费的代价并不高,相对于消息处理函数花费的代码,路由是微不足道的。因为
- 我们都知道,命令消息只有在用户与UI对应交互时才会产生。
- 例子:
- CMDIFrameWnd First: Active CMDIChildWnd
- Second: This frame window
- Third: Application(CWinApp Object)
- Document frame window First: Active View
- (CFrameWnd,CMDIChildWnd) Second: This frame window
- Third: Application(CWinApp Object)
- View First: This view
- Second: Document attached to the view
- Document First: This document
- Second: Document template attached
- to the document
- Dialog Box First: This dialog box
- Second: Window that own this dialog
- Third: Application(CWinApp Object)
- 4:命令路由的例子
- 用户选择了一个MDI程序下Edit菜单下的一项,则命令路由的过程如下:
- A:主窗口首先接收到这条命令
- B:MDI框架窗口给当前活动状态的MDI子框架窗口一次处理的机会
- C:MDI子框架窗口在检查自己的消息映射表之前先给它所有的视图一次处理的机会
- D:视图先检查自己的消息映射表,如无合适处理函数,会将命令传送给与其相关联
- 的文档。
- E:文档检查自己的消息映射表且发现了一个合适的处理函数
- 最终在文档中发现的处理函数会被调用,路由结束。
- 如果在E中文档也没有发现合适的处理函数,则文档会在与其相关的文档模板间进行路由,
- 然后命令会返回到视图及框架窗口。最终框架窗口会检查其自身的消息映射表,如果自身
- 还不具备合适的处理函数,那么命令会被回送到MDI框架窗口或更上一层的CWinApp对象。
- CWinApp对象是未被处理命令的最终目的地,即处理地点。要吧推测,应用程序对象本身
- 会对所有的命令有一个默认的处理。
- 5:处理函数OnCmdMsg
- 为了继续路由,每一个命令目标站都会调用下一个命令目标站的OnCmdMsg方法,这样
- 依次的调用就可以保证路由不停地进行下去。命令目标站会通过OnCmdMsg检查其自身
- 能否处理此命令,如果不能就将命令传递到下一个命令目标站。
- 每一个命令目标类都应该重载OnCmdMsg函数,这样可以自定义下一个命令目标站。
- 类CCmdTarget对OnCmdMsg的默认实现是通过消息映射表为接收到的命令查找合适的
- 处理函数,对于普通消息也是这样子实现的。如果它找到了合适的处理函数,就是调用它。
- 6:重载标准的命令路由方式
- 只有在很少数的情况下,为了满足自己的需求,我们必须重载标准的路由方式。基本
- 方法就是重载一个类或几个类的OnCmdMsg方法,按下面的方法:
- A:在将在打破标准顺序的类中添加一个非默认的对象
- B:在这个新添加的对象或命令目标站中轮流为其传递命令
- 如果在路由链中插入了新的对象,要确定这些对象所属的类是命令目标类,即派生自
- CCmdTarget。在你重载的OnCmdMsg中,要确保已调用了原版的OnCmdMsg。
- */
How the Framework Calls a Handler(译自MSDN)
最新推荐文章于 2025-04-24 17:26:09 发布