注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

重读深入浅出MFC(6)-消息的种类及处理方式4  

2011-07-27 15:51:19|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

重读深入浅出MFC(6)-消息的种类及处理方式4
消息的反射(转载)
(只考虑WINDWS窗口,不考虑OLE控件)Windows 控制常常发送通知消息给它们的父窗口,通常控制消息由父窗口处理。但是在MFC 里头,父窗口在收到这些消息后,或者自己处理,或者反射这些消息给控制窗口自己处理,或者两者都进行处理。如果程序员在父窗口类覆盖了通知消息的处理(假定不调用
基类的实现),消息将不会反射给控制子窗口。这种反射机制是MFC 实现的,便于程序员创建可重用的控制窗口类。
MFC 的CWnd 类处理以下控制通知消息时,必要或者可能的话,把它们反射给子窗口
处理:
WM_CTLCOLOR,
WM_VSCROLL,WM_HSCROLL,
WM_DRAWITEM,WM_MEASUREITEM,
WM_COMPAREITEM,WM_DELETEITEM,
WM_CHARTOITEM,WM_VKEYTOITEM,
WM_COMMAND、WM_NOTIFY。

ClassWizard 添加消息处理函数时,可以处理的反射消息前面有一个等号,例如处理WM_HSCROLL 的反射消息,选择映射消息“=EN_HSC ROLL,其具体的调用过程如下:
SendChildNotifyLastMsg---》OnChildNotify(CWnd 的虚拟函数,可以被覆盖)---》ReflectChildNotify
首先,调用CWnd 的成员函数SendChildNotifyLastMsg,它从线程状态得到本线程最近一次获取的消息(关于线程状态,后面第9 章会详细介绍)和消息参数,并且把这些参数传递给函数OnChildNotify。注意,当前的CWnd 对象就是MFC 控制子窗口对象。
OnChlidNofify 是CWnd 定义的虚拟函数,不考虑OLE 控制的话,它仅仅只调用ReflectChildNotify。OnChlidNofify 可以被覆盖,所以如果程序员希望处理某个控制的通知消息,除了采用消息映射的方法处理通知反射消息以外,还可以覆盖OnChlidNotify 虚拟函数,如果成功地处理了通知消息,则返回TRUE。
ReflectChildNotify 是CWnd 的成员函数,完成反射消息的派发。对于WM_COMMAND,它直接调用CWnd::OnCmdMsg 派发反射消息WM_REFLECT_BASE+WM_COMMAND;对于WM_NOTIFY , 它直接调用CWnd::OnCmdMsg 派发反射消息WM_REFLECT_BASE+WM_NOFITY;对于其他消息,则直接调用CWnd::OnWndMsg(即CmdTarge::OnWndMsg)派发相应的反射消息,例如WM_REFLECT_BASE+WM_HSCROLL。
注意:ReflectChildNotify 直接调用了CWnd 的OnCmdMsg 或OnWndMsg,这样反射消息被直接派发给控制子窗口,省却了消息发送的过程。接着,控制子窗口如果处理了当前的反射消息,则返回反射消息被成员处理的信息。下面讲一个实例:

事实上,用发送控件颜色消息的方法来实现来定制控件颜色,有悖于面向对象编程的原则。
通过向父窗口(在这里父窗口是对话框)发送WM_CTLCOLOR消息,处理这些消息的代码都将在父窗口类中来实现,这显然不利于重用。
更符合面向对象的方法应该是让控件可以处理自己的背景颜色,这样将有利于代码重用。
微软已经认识到这点,从MFC4.0开始提供了一种称为消息反射(Message Reflection)的新机制。
消息反射允许控件自己处理类似WM_CTLCOLOR这样的通知消息(在VC的ClassWizard里显示为=WM_CTLCOLOR)。但MFC为了相后兼容,保留了旧的消息机制,允许这些通知消息能被父窗口处理(虽然后者是不合逻辑的)。
反射消息的消息映射宏与通常的消息映射宏有点微小的区别:它在其常规名字后附加了 _REFLECT 表示。
例如,用于=WM_CTLCOLOR 通知的宏是 ON_WM_CTLCOLOR_REFLECT。

下面举一个通过处理反射消息创建可重用控件的例子:
Handling Reflected Messages: An Example of a Reusable control(根据MSDN Library - July2000 整理)

这个例子创建了一个可重用的CYellowEdit控件。这一控件继承了常规编辑控件的功能,不同就是它在黄色背景中显示黑字。(当然,还可以添加其它功能。)

步骤如下:

1.在一个已存在的应用程序添加一个对话框。

2.使用 ClassWizard 创建一个基于 CEdit 类的新CYellowEdit类。

3.在 CYellowEdit 类中添加三个成员变量。

COLORREF m_clrText;   //记录文本颜色
COLORREF m_clrBkgnd; //记录背景颜色
CBrush m_brBkgnd;  //用于绘制背景的刷子


4.在构造函数中初始化这些成员变量:
CYellowEdit::CYellowEdit()
{
 m_clrText = RGB( 0, 0, 0 );
 m_clrBkgnd = RGB( 255, 255, 0 );
 m_brBkgnd.CreateSolidBrush( m_clrBkgnd );
}

5.使用 ClassWizard 给您的 CYellowEdit 类为 =WM_CTLCOLOR 反射消息添加一个处理函数。注意,消息列表中的消息名称前的等于号表明该消息是个可以被反射的消息。ClassWizard 会为您添加下面的消息映射宏以及相应的函数骨架:

ON_WM_CTLCOLOR_REFLECT()

……

HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
 // TODO: Change any attributes of the DC here

 // TODO: Return a non-NULL brush if the
 //    parent's handler should not be called
 return NULL;
}

用下面的代码代替函数的主体。这里的程序代码很简单,你可以在这里添加更多的定制功能。

pDC->SetTextColor( m_clrText );    // text
pDC->SetBkColor( m_clrBkgnd );    // text bkgnd
return m_brBkgnd;                // ctl bkgnd

6.在对话框中创建一个编辑控件,为这一控件绑定一个控件类型的成员变量。注意在为对话框增添成员变量时,选择“CYellowEdit”作为您的变量类型。

随后,ClassWizard会提醒你在你的对话框头文件中添加 CYellowEdit 类的头文件。记得include它的头文件。

对所有想定制这一颜色的编辑控件,只要绑定一个CYellowEdit类型的变量即可。
编译并运行您的程序,该编辑控件将显示一个黄色的背景。
好了,可重用的定制控件产生了。
将CyellowEdit类添加到Galllery 中去,即可实现在其它工程项目中复用这一控件

  评论这张
 
阅读(725)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017