深入MFC中WM_COMMAND命令消息的传递

MFC将windows消息系统进行了高度的抽象和封装,其根本原理是运用C++的高级特性并结合一定的设计模式(如工厂模式,模板方法等)来实现的。一般的windows消息(WM_XXX),则一定是由派生类流向基类,没有旁流的可能。如果是命令消息(WM_COMMAND),那就有比较奇特的路线了。下面就针对多文档/单文档(Document-View)、对话框两种应用程序比较讨论WM_COMMAND消息的传递处理过程。讨论前首先得明确命令消息的来源,命令消息一般是用户选择某个菜单项,或一个加速键被翻译,或一个子控件发送一个通知消息给它的父窗口时产生的。对一个菜单而言,消息接收者是Frame窗口或拥有它的对话框;对一个工具栏而言,消息接收者是它的父窗口。两种应用程序命令消息处理流程如下图所示。

从上图可知,文档视图型的处理路线是先向下再向上,而对话框型的路线是一直向上,消息接收者只有一个,而处理者次序有多个,每个处理者内部首先都是调用根基类CCmdTarget的OnCmdMsg虚函数,在这个函数内逐级向基类遍历消息映射表,根据命令ID和通知码找到对应的消息映射结构体AFX_MSGMAP_ENTRY,如果找到再处理这个命令消息,否则返回FALSE,退回到this对象所在的OnCmdMsg函数进行下一步处理。如果到最后一层都没有找到对应命令的消息映射,则返回到系统的默认处理DefWindowProc。再综合考虑下,如果一个对话框接收到了一个命令消息例如是点击它的子控件工具栏某个按钮发出的,而这个对话框类没有添加相应的ON_COMMAND映射,就会进入到它的父窗口类OnCmdMsg函数进行处理,如果这个父窗口正好是Frame窗口,那么命令消息的处理流程就由上图右边转到左边了。而最终命令消息能否得处理,就看上图5种对象(Frame、View、Document、Dialog、App、Thread)是否添加了对应的ON_COMMAND映射。到此为止,我们已经明确了WM_COMMAND消息的处理流程,但是发现最终处理却是由收到消息的窗口传递的,不是消息通知者自己处理的,有的时候为了提高代码的封装性,可能需要自己处理这些命令比较方便,比如有一个工具栏CPlayToolBar子类从CToolBar继承,有播放、暂停、停止3个按钮,它的父窗口是CPlayDialog对话框。按照常规,这3个按钮命令事件的处理一般是在CPlayDialog类中3个ON_COMMAND映射宏和处理函数的,但如果在CPlayToolBar类中添加3个ON_COMMAND映射宏和处理函数,是得不到处理的,其原因在于对话框型的路线是一直向上,再者MFC中没有对应的命令反射ON_COMMAND_REFLECT这个宏。为了能使CPlayToolBar类自己处理这3个按钮命令事件,就需要从CPlayDialog类中转移路线,使之流向其子窗口工具栏,这样CPlayToolbar
类就得到了自己处理的机会。具体操作是重载CPlayToolBar和CPlayDialog的OnCommand虚函数,  CPlayDialog代码如下所示:

 1  BOOL   CPlayDialog::OnCommand(WPARAM wParam, LPARAM lParam)

 2  {

 3         if (lParam==(LPARAM)m_playtoolbar.m_hWnd)

 4        {

 5              m_playtoolbar.OnCommand(wParam,lParam);   //m_playtoolbar为CPlayToolBar对象,注意使OnCommand成为公有成员

 6        }

 7       else

 8       {

 9            return   CDialog::OnCommand(wParam, lParam);

10       }

11   }

CPlayToolBar类代码如下所示:

 1    BEGIN_MESSAGE_MAP(CPlayToolBar, CToolBar)

 2         ON_COMMAND(ID_PLAY,  Play)

 3         ON_COMMAND(ID_PAUSE,  Pause)

 4         ON_COMMAND(ID_STOP,  Stop)

 5    END_MESSAGE_MAP()

 6

 7    void   CPlayToolBar::Play()

 8    {

 9    }

10   void   CPlayToolBar::Pause()

11   {

12   }

13   void   CPlayToolBar::Stop()

14   {

15   }

现在,3个按钮命令事件能在CPlayToolBar类中独立处理了,这样一来就提高了代码的封装性,简化了父窗口CPlayDialog类的处理

时间: 2024-10-13 21:46:34

深入MFC中WM_COMMAND命令消息的传递的相关文章

在Linux中利用命令行去传递参数给Python

: 今天在实验楼答题做挑战的时候,遇到个一点都没头绪的题目,链接:https://www.shiyanlou.com/courses/running,题目如上,因为之前没接触到这类型的题目,所以无法入手百度了一下,知道了原来有个sys.argv[]这样的东西用.要从Linux中利用命令行去传递参数给Python文件 1,要先导入系统接口模块import sys 2,再调用系统命令行参数sys.argv,这是一个列表. 索引为0的sys.argv[0]是当前文档的路径,这不是我们想要的.索引为1的

《深入浅出MFC》第九章 消息映射与命令传递

Windows程序的本质是借着消息来维持脉动.每个消息都有一个代码,并以WM_开头的常量表示.来自菜单和工具栏者,都以WM_COMMAND表示,参数wParam记录消息的发出者. MFC的消息分为三大类,命令消息(WM_COMMAND),凡派生自CCmdTarget的类都有资格接收命令消息.除WM_COMMAND外,所有以WM_开头的都属于标准消息,派生自CWnd的类可接收此类消息.由控件产生的消息,为的是向父窗口传递某种情况,这种消息是以WM_COMMAND形式呈现. MFC通过三个宏来进行消

MFC命令消息路由过程(视图、框架、应用)

一.环境 IDE:VC6.0 OS:WindowsXp 二.编写测试代码和环境配置 新建一个Win32 Application 选择 "A Simple Win32 Application" 打开stdafx.h头文件把 #include <windows.h> 更改为: #include <afxwin.h> 修改工程设置使用MFC静态库以便能够查看微软提供的MFC源代码 Project->Settings->MicrosoftFoundation

MFC窗口WM_COMMAND消息

通过分析MFC的源代码,我们可以得到WM_COMMAND的消息响应顺序如下: 多文档框架中,有打开的文档时:视图 > 文档 > 子框架窗口 > 应用程序 >主框架窗口 多文档框架在没有打开文档时,应用程序和主框架窗口的顺序相反:主框架窗口 > 应用程序 在单文档框架应用程序中,因为没有子框架窗口,所以顺序应该是:视图 > 文档 >主框架窗口> 应用程序.无论有没有打开文档,主框架窗口都比应用程序类更优先. 事实上在多文档框架中,系统自动生成的代码使用的是CD

MFC中消息响应机制

由于视类窗口始终覆盖在框架类窗口之上,因此所有操作,包括鼠标单击.鼠标移动等操作都只能由视类窗口捕获.一个MFC消息响应函数在程序中有三处相关信息:函数原型.函数实现和以及用来关联消息和消息响应函数的宏. (1)在消息响应函数的原型代码中,函数声明的前部有一个afx_msg限定符,也是一个宏,该宏表明这个函数是一个消息响应函数的声明. (2)消息映射宏:在视图类的源文件中,BEGIN_MESSAGE_MAP()和 END_MASSAGE_MAP()这两个宏之间定义了消息映射表,例如对于画线,其中

iOS中消息的传递机制(KVO、Notification、delegation、block以及target-action)---转载

注1:本文由破船[博客]译自Communication Patterns. 本文目录如下所示: 可用的机制 做出正确的选择 Framework示例 小结 每个应用程序或多或少,都由一些松耦合的对象构成,这些对象彼此之间要想很好的完成任务,就需要进行消息传递.本文将介绍所有可用的消息传递机制,并通过示例来介绍这些机制在苹果的Framework中如何使用,同时,还介绍了一些最佳实践建议,告诉你什么时机该选择使用什么机制. 虽然这一期的主题是关于Foundation Framework的,不过本文中还

IOS OS X 中集中消息的传递机制

1 KVO (key-value Observing) 是提供对象属性被改变是的通知机制.KVO的实现实在Foundation中,很多基于 Foundation 的框架都依赖与它.如果只对某一个对象的值的改变感兴趣的话.就可以使用KVO消息传递.满足KVO的前提条件:1接受者(接受对象改变的通知的对象)需要知道发送者(值会改变的对象):2,接受者需要知道发送者的生命周期,因为它需要在发送者被销毁前注销观察者身份.如果这两个要求都符合的话,这个消息传递机制可以一对多(多个观察者可以注册同一个对象的

iOS中消息的传递机制

小结 每个应用程序或多或少,都由一些松耦合的对象构成,这些对象彼此之间要想很好的完成任务,就需要进行消息传递.本文将介绍所有可用的消息传递机制,并通过示例来介绍这些机制在苹果的Framework中如何使用,同时,还介绍了一些最佳实践建议,告诉你什么时机该选择使用什么机制. 虽然这一期的主题是关于Foundation Framework的,不过本文中还介绍了一些超出Foundation Framework(KVO和Notification)范围的一些消息传递机制,另外还介绍了delegation,

MFC中如何在TreeCtrl控件中获取鼠标左键消息时的有效点击位置

MFC中,当在TreeCtrl控件中添加鼠标左键消息时,就意味着,凡是在该控件中点击左键后即会响应鼠标左键的消息,可有时我们只想记下有效的鼠标左键点击的事件,如图所示: 只想在CheckBox中点击鼠标左键时,将已选中的Item的句柄存入到链表中,那么如何只将有效的鼠标左键的消息存入链表中呢? 下面是响应鼠标左键消息时从所有鼠标左键消息都响应到只响应有效的左键消息的三个版本: 当响应鼠标左键的消息时,第一个版本: 获取鼠标的点击位置(注意:此时获取的是针对于当前屏幕的鼠标点击位置,所以需要将其转