深度剖析消息反射机制

深度剖析消息反射机制
作者:hustli
    摘要:在前面我们分析了控件通知消息WM_NOTIFY,和WM_NOTIFY紧密联系的还有一个MFC新特性:消息反射。本文中,我想就这个问题作一个全面的论述,如果有错误,还望各路大虾批评指正。
    什么是消息反射?
    在windows里面,子控件经常向父控件发送消息,例如很多子控件要绘制自己的背景,就可能向父窗口发送消息WM_CTLCOLOR。对于从子控件发来的消息,父控件有可能在处理之前,把消息返还给子控件处理,这样消息看起来就想是从父窗口反射回来一样,故此得名:消息反射。
    消息反射的由来
    在windows和MFC4.0版本一下,父窗口(通常是一个对话框)会对这些消息进行处理,换句话说,自控件的这些消息处理必须在父窗口类体内,每当我们添加子控件的时候,就要在父窗口类中复制这些代码,我们可以想象这是多么的复杂,代码是多么的臃肿!
    我们可以想象,如果这些消息都让父窗口类去做,父窗口就成了一个万能的神,一个臃肿不堪的代码机,无论如何消息的处理都集中在父窗口类中,会使父窗口繁重无比,但是子控件却无事可做,并且代码也无法重用,这对于一个程序员来讲是多么痛苦的一件事?!
    在老版本的MFC中,设计者也意识到了这个问题,他们对一些消息采用了虚拟机制,例如:WM_DRAWITEM,这样子控件就有机会控制自己的动作,代码的可重用性有了一定的提高,但是这还没有达到大部分人的要求,所以在高版本的MFC中,提出了一种更方便的机制:消息反射。
    通过消息反射机制,子控件窗口便能够自行处理与自身相关的一些消息,增强了封装性,同时也提高了子控件窗口类的可重用性。不过需要注意的是:消息反射是MFC实现的,不是windows实现的;要让你的消息反射机制工作,你得类必须从CWnd类派生。
    Message-Map中的处理
    如果想要处理消息反射,必须了解相应的Message-Map宏和函数原型。一般来讲,Message-Map是有一定的规律的,通常她在消息的前面加上一个ON_ ,然后再消息的最后加上 _REFLECT。例如我们前面提到的WM_CTLCOLOR 经过处理后变成了ON_WM_CTLCOLOR_REFLECT;WM_MEASUREITEM则变成了ON_WM_MEASUREITEM_REFLECT。
    凡事总会有例外,这里也是这样,这里面有3个例外:
    (1) WM_COMMAND 转换成 ON_CONTROL_REFLECT;
    (2) WM_NOTIFY  转换成 ON_NOTIFY_REFLECT;
    (3) ON_UPDATE_COMMAND_UI 转换成 ON_UPDATE_COMMAND_UI_REFLECT;
    对于函数原型,也必须是以 afx_msg 开头。
    利用ClassWizard添加消息反射
    (1)在ClassWizard中,打开选择项Message Maps;
    (2)在下拉列表Class name中选择你要控制的类;
    (3)在Object IDs中,选中相应的类名;
    (4)在Messages一栏中找到前面带有=标记的消息,那就是反射消息;
    (5)双击鼠标或者单击添加按钮,然后OK!
    消息处理的过程
  (1)子窗口向父窗口发送通知消息,激发父窗口去调用它的虚函数CWnd::OnNotify。大致的结构如下
       BOOL CWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
       {
          if (ReflectLastMsg(hWndCtrl, pResult)) 
file://hWndCtrl
,为发送窗口
                                    return TRUE; file://如果子窗口已处理了此消息,返回
          AFX_NOTIFY notify;
          notify.pResult = pResult;
          notify.pNMHDR = pNMHDR;
          return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY)? notify:NULL);
      }
  (2)ReflectLastMsg声明如下:static BOOL PASCAL ReflectLastMsg(HWND hWndChild, LRESULT* pResult = NULL);
     它的主要任务就是调用发送窗口的SendChildNotifyLastMsg。 
  (3)SendChildNotifyLastMsg声明如下:BOOL SendChildNotifyLastMsg(LRESULT* pResult = NULL);
     调用发送窗口的虚函数OnChildNotify函数,进行处理。 如果发送窗口没有进行重载处理,则调用ReflectChildNotify(...)函数进行标准的反射消息的消息映射处理。
    使用的一个例子
    这里面我们举一个简单的例子,希望大家能够更清晰的掌握消息反射机制。
    (1)创建一个基于对话框的工程。
    (2)利用向导创建一个新的类:CMyEdit,基类是CEdit。
    (3)在CMyEdit头文件中加入3个成员变量:
         COLORREF m_clrText ;
 COLORREF m_clrBkgnd ;
 CBrush   m_brBkgnd;
    (4)利用向导在其中加入WM_CTLCOLOR(看到了么,前面是不是有一个=?),并且将它的函数体改为:
         HBRUSH CMyEdit::CtlColor(CDC* pDC, UINT nCtlColor) 
        {
  pDC->SetTextColor( m_clrText );    // text
  pDC->SetBkColor( m_clrBkgnd );    // text bkgnd
  return m_brBkgnd;                // ctl bkgnd
        }
        同时我们在.cpp文件中会看到ON_WM_CTLCOLOR_REFLECT(),这就是我们所说的经过处理的宏,是不是很符合规则?
    (5)在对话框中加入一个Edit,增加一个关联的变量,选择Control属性,类别为CMyEdit。
    (6)在对话框.cpp文件中加入#include "MyEdit.h",运行,看到了什么?呵呵。
    
     事情到了一个阶段,希望你能够喜欢,明天见!

http://blog.csdn.net/zyc464301/archive/2007/10/29/1854930.aspx

http://blog.csdn.net/xiexievv/article/details/6282205

时间: 2024-08-01 10:43:05

深度剖析消息反射机制的相关文章

Message Reflection for Windows Controls(消息反射机制)

https://msdn.microsoft.com/en-us/library/eeah46xd.aspx 转自: //http://blog.csdn.net/zhuce0001/article/details/9152515. 在基于对话框的程序中,有一个任务是改变编辑框控件的背景,怎么办? 实现思路如下,子控件要绘制时会向父类(这里是主窗口)发送WM_CTLCOLOR 消息,在父类中(这里是主窗口)响应WM_CTLCOLOR,根据消息传递过来的 参数进行相应的操作,具体代码如下: [cp

elasticsearch中filter执行原理深度剖析(bitset机制与caching机制)

(1)在倒排索引中查找搜索串,获取document list date来举例 word doc1 doc2 doc3 2017-01-01 * *2017-02-02  *   *2017-03-03 *   * * filter:2017-02-02 到倒排索引中一找,发现2017-02-02对应的document list是doc2,doc3 (2)为每个在倒排索引中搜索到的结果,构建一个bitset,[0, 0, 0, 1, 0, 1] 非常重要 使用找到的doc list,构建一个bit

Java反射机制剖析(四)-深度剖析动态代理原理及总结

动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Proxy0)的源代码和整个动态代理的流程. $Proxy0生成的代码如下: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; impo

Java反射机制剖析(三)-简单谈谈动态代理

通过Java反射机制剖析(一)和Java反射机制剖析(二)的学习,已经对反射有了一定的了解,这一篇通过动态代理的例子来进一步学习反射机制. 1.     代理模式 代理模式就是为其他对象提供一种代理来控制对这个对象的访问.其实代理模式是在访问的对象时引入一定程度的间接性,这种间接性可以附加多种用途. 它 的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会 存在关联关系,一个代理类的对象与一个委托类的对象

深度剖析JDK动态代理机制

摘要 相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象. 代理模式 使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加"前置通知"和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能. 使用动态代理的五大步骤 1.通过实现InvocationHandler接口来自定义自己的Invocati

java反射机制剖析(三)—类类型Class

为了区别于我们常用的Class,因此给了个中文名类类型.目的就是为了知道此Class非彼Class.上一篇博客已经介绍了Class Loader,它的作用是根据提供的信息来加载类到内存中.我之前有提过这个类信息的提供者就是本篇博客要介绍的Class.提醒:一个类的Class对象和它的Instance是不一样的,切记,不然你会混乱的.开始了! 概念 Class类是所有类(注意是对象)的共有信息的抽象,比如该类实现的接口.对应的加载器.类名等等.一句话,类类型保存了每个类所对应的类型信息.每一个类都

【54】Java反射机制剖析

java反射机制: 1.指的是可以于运行时加载,探知和使用编译期间完全未知的类. 2.程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能调用他的任意一个方法和属性; 3.加载完类之后, 在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象), 这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射. 4.每个类被加载进入内存之后,系统

java反射机制剖析(二)— Class Loader

上一篇博客简要的提了一下java反射机制中涉及到的一些相关知识,那么ClassLoader就是其中之一.本篇博客就详细的对ClassLoader做一个相对深入的了解.作为了解需要知道的是,其实类类型(Class Class)是和ClassLoader分不开的,因为ClassLoader需要的信息是由它提供的.类类型将在下一篇博客介绍. 简介 ClassLoader是负责加载类的对象,作用是根据Jvm请求提供的类信息,将请求的类加载的内存中或者说加载到Jvm中.另外,每一个类的Class对象(注意

[Android] Toast问题深度剖析(二)

欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者: QQ音乐技术团队 题记 Toast 作为 Android 系统中最常用的类之一,由于其方便的api设计和简洁的交互体验,被我们所广泛采用.但是,伴随着我们开发的深入,Toast 的问题也逐渐暴露出来. 本系列文章将分成两篇: 第一篇,我们将分析 Toast 所带来的问题 第二篇,将提供解决 Toast 问题的解决方案 (注:本文源码基于Android 7.0) 1.回顾 上一篇 [[Android] Toast问题深度剖析(一)]