MFC消息反射

来源:互联网 发布:联发科处理器优化 编辑:程序博客网 时间:2024/05/01 11:10
什么是消息反射?
    在MFC里面,子控件经常向父窗口发送消息,例如很多子控件要绘制自己的背景,就可能向父窗口发送WM_CTLCOLOR消息。对于从子控件发来的消息,父控件有可能在处理之前,把消息返还给子控件处理,这样消息看起来就像是从父窗口反射回来一样,故此得名:消息反射。

消息反射的由来
    在windows和MFC4.0版本以下,父窗口(通常是一个对话框)会对这些消息进行处理,换句话说,子控件的这些消息处理必须在父窗口类体内,每当我们添加子控件的时候,就要在父窗口类中复制这些代码,我们可以想象这是多么的复杂,代码是多么的臃肿!可以想象,如果这些消息都让父窗口类去做,父窗口就成了一个万能的神,一个臃肿不堪的代码机,无论如何消息的处理都集中在父窗口类中,会使父窗口繁重无比,但是子控件却无事可做,并且代码也无法重用,这对于一个程序员来讲是多么痛苦的一件事?!
    通过消息反射机制,子控件窗口便能够自行处理与自身相关的一些消息,增强了封装性,同时也提高了子控件窗口类的可重用性。不过需要注意的是:消息反射是MFC实现的,不是windows实现的;要让你的消息反射机制工作,你的类必须从CWnd类派生。

消息反射的流程 
  1、父窗口收到控制子窗口发来的通知消息后,调用它的虚函数CWnd::OnNotify()
CWnd::OnNotify()//主体部分:
    {
        //此时,hWndCtrl为发送窗口,即子控件的窗口句柄
        if (ReflectLastMsg(hWndCtrl, pResult))
            return TRUE;

        AFX_NOTIFY notify;
        notify.pResult = pResult;
        notify.pNMHDR = pNMHDR;

        return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);
    }
  在OnNotify()中,首先调用ReflectLastMsg(...)给子窗口一个自身处理的机会,将消息反射给子窗口处理;函数返回 TRUE,表明子窗口处理了此消息,反之则表示子窗口未处理此消息,此时,调用OnCmdMsg(...)由父窗口进行通常的处理。
  2、在ReflectLastMsg(...)中,主要是调用发送窗口的SendChildNotifyLastMsg(...),在这个函数中调用发送窗口的虚函数OnChildNotify(...)函数进行处理。 如果没有处理,则调用ReflectChildNotify(...)函数进行标准的反射消息 的消息映射处理。

消息的处理
方法1:
 
由上述处理流程可以看出来,子窗口要想自身处理此消息,重载子控件窗口的OnChildNotify虚拟函数应该是很容易想到的方式。
BOOL CStatusBarCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,LRESULT* pResult)
{

     if (message != WM_DRAWITEM) //对应不同的控制,会有不同的有特殊处理要求的消息。
         return CWnd::OnChildNotify(message, wParam, lParam, pResult);

     ...

     DrawItem((LPDRAWITEMSTRUCT)lParam);

     return TRUE;
}

void CStatusBarCtrl::DrawItem(LPDRAWITEMSTRUCT)//重载DrawItem虚函数,实现对反射消息 WM_DRAWITEM的处理。
{
     ...
}

方法2:
  从方法1可以看出,如果你不在被重载的OnChildNotify()中对消息进行处理,函数会调用CWnd::OnChildNotify(),它调用ReflectChildNotify函数对消息进行标准处理,故可以增加子窗口对应的反射消息(以”=“开头的消息)的处理函数,在消息处理函数中进行处理。


Message-Map中的处理

    一般来讲,消息反射的Message-Map是有一定的规律的,通常她在消息的前面加上一个ON_ ,然后再消息的最后加上 _REFLECT。例如我们前面提到的WM_CTLCOLOR 经过处理后变成了ON_WM_CTLCOLOR_REFLECT。凡事总会有例外,这里也是这样,这里面有3个例外:

(1) WM_COMMAND 转换成 ON_CONTROL_REFLECT;
(2) WM_NOTIFY 转换成 ON_NOTIFY_REFLECT;
(3) ON_UPDATE_COMMAND_UI 转换成 ON_UPDATE_COMMAND_UI_REFLECT;
    父窗口将消息反射回给子控件后,子控件收到的反射消息以等号”=“开头,如子控件的反射消息WM_CTLCOLOR在子类中为=WM_CTLCOLOR。

MFC消息映射宏
宏名说明DECLARE_MESSAGE_MAP在头文件声明源文件中所含有的消息映射BEGIN_MESSAGE_MAP标记源文件消息映射的开始END_MESSAGE_MAP标记源文件消息映射的结束ON_COMMAND将特定命令的处理委派给类的一个成员函数ON_CONTROL映射一个函数到一个定制控制通知消息。其中,定制控制通知消息是从一个控制发送到其父窗口的消息。ON_CONTROL_RANGE将一个控制ID的范围映射到一个消息处理函数ON_CONTROL_REFLECT映射一个由父窗口反射回控制的通知消息ON_MESSAGE将一个用户自定义消息映射到一消息处理函数ON_NOTIFY映射一个控制消息到一个函数ON_NOTIFY_RANGE映射一个控制ID范围内的控制消息到一个函数ON_NOTIFY_EX映射一个控制消息到一个函数,该成员函数返回FALSE或TRUE来表明通知是否应被传送到下一个对象以进行其他反应。ON_NOTIFY_EX_RANGE映射一个控制ID范围内的控制消息到一个函数,该成员函数返回FALSE或TRUE来表明通知是否应被传送到下一个对象以进行其他反应ON_NOTIFY_REFLECT映射一个控制消息到一个函数。该消息将会被控制的父窗口反射回来。ON_REGISTERED_MESSAGE映射一个唯一的消息到一个将要处理该注册消息的函数上。该消息是由RegisterWindowMessage()函数注册的。ON_UPDATE_COMMAND_UI映射一个函数来处理一个用户接口更新命令消息ON_UPDATE_COMMAND_UI_RANGE映射一个命令ID的范围到一个更新消息处理函数
转载出处1:http://baike.baidu.com/link?url=_HtyCyxCuKMXHp8EhcTbHAPjDO9SCylI2She5YiKAFCis9J_ucWDMOq93yZKj3v6OC4XA4ELEABHf4LQ755WDa
转载出处2:http://www.yesky.com/313/1746313.shtml

0 0
原创粉丝点击