关于WM_NOTIFY及反射机制的来龙去脉

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

  这是一篇关于MFC里消息的路由问题,由于水平有限,难免有错误,如有发现,请指出。感激之至。

我打算从OnWndMsg()开始讲,这是窗口真正处理消息的函数。在这函数里对三种消息进行了处理。

1.标准Window消息,正常处理就行了(具体怎样请参考<<深入浅出MFC>>)在这里不是重点

2.WM_COMMAND消息,会调用OnCommand()

3.WM_NOTIFY消息,会调用OnNotify().

 

然后开始WM_NOTIFY消息:

控件通知消息,是指这样一种消息,一个窗口内的子控件发生了一些事情,需要通知父窗口。通知消息只适用于标准的窗口控件如按钮、列表框、组合框、编辑框,以及Windows公共控件如树状视图、列表视图等。例如,单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知消息。她类似于命令消息,当用户与控件窗口交互时,那么控件通知消息就会从控件窗口发送到它的主窗口。但是这种消息的存在并不是为了处理用户命令,而是为了让主窗口能够改变控件,例如加载、显示数据。例如按下一个按钮,他向父窗口发送的消息也可以看作是一个控件通知消息;单击鼠标所产生的消息可以由主窗口直接处理,然后交给控件窗口处理。
控件通知消息主要由窗口类即直接或间接由CWND类派生类处理

控件通知格式
控件通知经历了一个演变过程,因而SendMessage( )的变量Message、wParam和lParam有三种格式。
第一控件通知格式
第一控件通知格式只是窗口消息的子集。它的特征格式如下:WM_XXXX。它主要来自下面的3种消息类型:
(1)表示一个控件窗口要么已经被创建或销毁,要么已经被鼠标单击的消息:WM_PARENTNOTIFY;
(2)发送到父窗口,用来绘制自身窗口的消息,例如: WM_CTLCOLOR、WM_DRAWITEM、WM_MEASUREITEM、WM_DELETEITEM、WM_CHARTOITEM、 WM_VKTOITEM、WM_COMMAND和WM_COMPAREITEM
(3)有滚动调控件发送,通知父窗口滚动窗口的消息:WM_VSCROLL和WM_HSCROLL

用到的宏是:ON_COMMAND
第二控件通知格式
第二控件通知格式与命令消息共享,它的特征格式如下:WM_COMMAND。
  在WM_COMMAND中,lParam用来区分是命令消息还是控件通知消息:如果lParam为NULL,则这是个命令消息,否则lParam里面放的必然就是控件的句柄,是一个控件通知消息。对于wParam则是低位放的是控件ID,高位放的是相应的消息事件。

      用到的宏是:ON_CONTROL,按钮的点击通知消息就是用到了此宏,ON_BN_CLICKED(ID,FUNC)就是ON_CONROL(ID,BN_CLICKED,FUNC).
第三控件通知格式

  这个才真正涉及到我们要讲的内容,同时他也是最为灵活的一种格式。它的特征格式如下:WM_NOTIFY。

在WM_NOTIFY中,lParam中放的是一个称为NMHDR结构的指针。在wParam中放的则是控件的ID。

      用到的宏是:ON_NOTIFY

具体通知消息采用哪种显示,是MFC内部的事,我们在手工添加的时候一定要注意。

 

NMHDR结构是很值得一提的,该结构包括有关制作该通知的控件的任何内容,而不受空间和类型的限制,他的来历也是很有意思的。
  在最初的windows3.x中,根本就不存在什么WM_NOTIFY,控件通知它们父窗口,如鼠标点击,控件背景绘制事件,通过发送一个消息到父窗口。简单的通知仅发送一个WM_COMMAND消息,包含一个通知码和一个在wParam中的控件ID及一个在lPraram中的控件句柄。这样一来,wParam和lParam就都被填充了,没有额外的空间来传递一些其它的消息,例如鼠标按下的位置和时间。
  为了克服这个困难,windows3.x就提出了一个比较低级的解决策略,那就是给一些消息添加一些附加消息,最为明显的就是控件自画用到的 DRAWITEMSTRUCT。不知道大家对这个结构熟悉不,不过,如果你是老手,你应该非常清楚这个结构,这个结构包含了9个内容,几乎你需要控制的信息都给你提供了。为什么说它比较低级呢?因为不同的消息附加的内容不同,结果就是一盘散沙,非常混乱。
  在win32中,MS又提出了一个更好的解决方案:引进NMHDR结构。这个结构的引进就是消息统一起来,利用它可以传递复杂的信息。这个结构的布局如下:
NMHDR
{
     HWnd hWndFrom ; 相当于原WM_COMMAND传递方式的lParam
     UINT idFrom ; 相当于原WM_COMMAND传递方式的wParam(low-order)
     UINT code ; 相当于原WM_COMMAND传递方式的Notify Code(wParam"s high-order)
};

类向导可以创建ON_NOTIFY消息映射入口并提供一个处理函数的框架,来处理 WM_NOTIFY类型的消息。ON_NOTIFY消息映射宏有如下语法:ON_NOTIFY(wNotifyCode,id,memberFxn)

有时我们可能需要为一组控件处理相同的WM_NOTIFY消息。这时需要使用ON_NOTIFY_RANGE而不是ON_NOTIFY。

 

下面介绍发射机制:

由上面的介绍,在命令消息中也有可以是通知消息

     如果在OnCommnd中要进行判断。判断的方法:如果lParam是有效的控件句柄就是通知消息,如果不是命令消息,现在不考虑是命令消息的情况。如果是通知消息,则调用ReflectLastMsg()给子控件一次处理的机会。如果没处理,则会调用把通知消息转换成命令消息并调用OnCmdMsg。

     如果在OnNotify()中:首先调用ReflectLastMsg()给子控件一次处理的机会。如果没处理,则会调用把通知消息转换成命令消息并调用OnCmdMsg。

 

以下就是重点了。

1.ReflectLastMsg

主要是调用子类的SendChildNotifyLastMsg(...)。


2.SendChildNotifyLastMsg

调用子窗口的OnChildNotify函数进行处理,此函数是虚函数。

 

3.OnChildNotify()

调用子类的ReflectChildNotify()

 

4.ReflectChildNotify()

ReflectChildNotify()把消息转换成REFLECT的形式如:

WM_CTLCOLOR 经过处理后变成了ON_WM_CTLCOLOR_REFLECT;WM_MEASUREITEM则变成ON_WM_MEASUREITEM_REFLECT。
 (1) WM_COMMAND 转换成 ON_CONTROL_REFLECT;
 (2) WM_NOTIFY  转换成 ON_NOTIFY_REFLECT;
 (3) ON_UPDATE_COMMAND_UI 转换成 ON_UPDATE_COMMAND_UI_REFLECT;

 

5.再调用子控件的OnCmdMsg对消息进行处理。

 

利用方面:

如果不是自定义的控件,在对话框中,可以右键点击增加通知消息,这时子控件没有处理通知消息。

如果是自定义控件,我们任然可以是父对话框里处理通知消息,但是我们也可以在子控件里通知,在增加消息

处理的地方,有的消息前面有个“=”就表示是通知消息。

 

MFC子窗口与父窗口之间消息的传递 使用VS2015写的MFC子窗口与父窗口之间消息的传递,可以直接执行 立即下载

相关推荐

OnNotify与OnChildNotify以及CStatic的DrawItem实现源代码

OnNotify是用于子控件向父窗口发送消息用的。该消息的接收对象是父窗口。OnChildNotify是子控件向父窗口发送消息后,父窗口反射消息给子窗口用的。该消息的接收对象是子窗口。如:CDialog上有一个CStatic。在CStatic上点击鼠标,则CStatic会发送OnNotify消息给CDialog。CDialog接收OnNotify消息并处理。然后CDialog会发送OnChildN...

超频化石鱼的博客 1539

WM_NOTIFY

1、WM_NOTIFY的由来。 对于窗口上的控件。控件上的行为会交由窗口处理,也就是控件(或者说系统为控件)发送一个消息通知窗口,这个消息就是WM_NOTIFY.其对应的处理函数是虚函数 OnNotify,所以可以在窗口的OnNotify中给出处理。如果想让控件自己处理,可以重载控件的OnChildNotify函数。 即: 窗口实现OnNotify 控件派生类,并重载OnChildN

学而不思则罔 1979

ON_NOTIFY

(声明:原文来自MSDN 2001 Oct版,原文内涉及的连接由于是脱机连接,所以译文内的连接是本人尽量找自MSDN online)TN061: ON_NOTIFY and WM_NOTIFY Messages这个技术文章介绍了关于新WM_NOTIFY消息, 还描述了建议使用的一种在你的MFC应用程序中处理WM_NOTIFY消息的方法。Windows 3.x 的 通告消息在Wind

wzyzb的专栏 2万+

MFC中的模态对话框与非模态对话框的消息循环及消息传递问题(都可以通过SendMessage传递消息)

还有一个必须重载的函数就是PostNcDestroy,这也是一个虚函数,通常的非模态对话框是用类的指针,通过new创建的,这就需要在PostNcDestroy函数中delete掉这个指针。众所周知,在MFC程序中,窗口对象的生存期应长于对应的窗口,也就是说,不能在未关闭屏幕上窗口的情况下先把对应的窗口对象删除掉。由于在Create返回后,不能确定对话框是否已关闭,这样也就无法确定对话框对象的生存期,因此只好在堆中构建对话框对象,而不能以局部变量的形式来构建之。但由于是对话框,它对一些消息有特殊的处理。

Willing_hope的博客 3031

WM_NOTIFY 详解

WM_NOTIFYWindows 操作系统中的,用于控件(如按钮、列表框、树形控件等)向其父窗口传递事件或请求信息。

felicity_one的博客 752

MFCWM_NOTIFY消息处理流程

参考文章:MFC的消息反射机制 在前一篇文章:MFC消息处理流程概述中描述了MFC消息处理的大体流程。由CWnd::OnWndMsg函数可知,当消息为WM_NOTIFY消息时,调用的是virtual CWnd::OnNotify处理。 if (message == WM_NOTIFY) { NMHDR* pNMHDR = (NMHDR*)lParam; if (pNM

Hisin Wang的专栏 6369

全面解读WM_NOTIFY & 消息反射

原文:http://blog.csdn.net/hustli/category/12732.aspx   摘要:控件通知消息有很多种,但是有一种是很常用,但是又不是很容易掌握的,那就是WM_NOTIFY,我试着对此做一下比较全面的论述,有不对的地方,还希望各路大虾批评指正。 控件通知消息 在《深度解析VC中的消息(上)》中,我们提到了消息的分类有3种:窗口消息、命令消息和控件通知消

worldy的专栏 5140

分析与理解VC的通知消息WM_NOTIFY

  引入WM_NOTIFY消息的原因  1、问题的提出:  在Windows3.x中,不存在WM_NOTIFY消息,控制子窗口的通知消息同菜单的命令消息及加速键消息一样,均使用WM_COMMAND来发送,此时,根据WM_COMMAND消息传递的做法,可知道含有如下的传递结构:wParam high-order

801

WM_Notify与消息反射

关于WM_NOTIFY与消息反射—耗费我两天时间才解决的问题 www.firnow.com 时间 : 2010-06-22 作者:佚名 编辑:壹枝雪糕 点击: 1306 [ 评论 ] 综合资源电子书社区 其实,问题很简单,我想在listctrl响应NM_SETFOCUS的同时通知其父窗口(其实我这句话说错了,listctrl只能响应=NM_SETFOCUS,为什么有个“=”呢?稍后解释),最幼

u010042142的专栏 606

深度剖析消息反射机制

深度剖析消息反射机制作者:hustli 摘要:在前面我们分析了控件通知消息WM_NOTIFY,和WM_NOTIFY紧密联系的还有一个MFC新特性:消息反射。本文中,我想就这个问题作一个全面的论述,如果有错误,还望各路大虾批评指正。 什么是消息反射? 在windows里面,子控件经常向父控件发送消息,例如很多子控件要绘制自己的背景,就可能向父窗口发送消息WM_CTLCOLOR。对...

SurpassLi的专栏 35

WM_CTLCOLOR

在前面我们分析了控件通知消息WM_NOTIFY,和WM_NOTIFY紧密联系的还有一个MFC新特性:消息反射。本文中,我想就这个问题作一个全面的论述,如果有错误,还望各路大虾批评指正。        什么是消息反射?         在windows里面,子控件经常向父控件发送消息,例如很多子控件要绘制自己的背景,就可能向父窗口发送消息WM_CTLCOLOR。对于从子控件发来的消息,父控件有可

feimashenhua的专栏 3437

深度剖析MFC消息反射机制收藏

 深度剖析MFC消息反射机制收藏function StorePage(){d=document;t=d.selection?(d.selection.type!=None?d.selection.createRange().text:):(d.getSelection?d.getSelection():);void(keyit=window.open(http://www.3

skyremember的专栏 1244

关于WM_NOTIFY与消息反射————耗费我两天时间才解决的问题

谁让我这么菜呢!不过,没有菜鸟,哪来高手?-_-| 其实,问题很简单,我想在listctrl响应NM_SETFOCUS的同时通知其父窗口(其实我这句话说错了,listctrl只能响应=NM_SETFOCUS,为什么有个“=”呢?稍后解释),最幼稚的想法是让在listctrl和父窗口中都添加对此消息的响应,很不幸,我在一开始就是这么想的-_-| 。。。很明显我失败了!后来我又发现,如果在li

yingzai621的专栏 1101

剖析消息反射机制

 摘要:在前面我们分析了控件通知消息WM_NOTIFY,和WM_NOTIFY紧密联系的还有一个MFC新特性:消息反射。本文中,我想就这个问题作一个全面的论述,如果有错误,还望各路大虾批评指正。     什么是消息反射?    在windows里面,子控件经常向父控件发送消息,例如很多子控件要绘制自己的背景,就可能向父窗口发送消息WM_CTLCOLOR。对于从子控件发来的消息,父控件有可

蜡笔小辛的专栏 893
上一篇: 关于EnumChildWindows和EnumChildProc的应用
下一篇: 属性表的学习
FlowShell
博客等级 码龄17年 119粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值