针对NM_CUSTOMDRAW消息的学习
消息的形式:1 窗口消息,2 命令消息,3 WM_NOTIFY消息,4 自定义消息
我们的NM_CUSTOMDRAW消息就是就属于第三种WM_NOTIFY消息,而添加消息映射的方法分为两种:
BEGIN_MESSAGE_MAP(CListCtrlColor, CListCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,OnCustomMyList)
END_MESSAGE_MAP()
第一种用到的是消息反射机制:
在Windows的消息处理中,控制子窗口的发给其父窗口的通知消息只能由其父窗口进行处理,这使得控制子窗口的自身能动性大大降低(你想,它连改变自己 的背景色,处理一个自身滚动问题都要其父窗口来完成),为了解决这个问题,在MFC中引入了反射消息“Reflect Message”的概念,进行消息反射,可以使得控制子窗口能够自行处理与自身相关的一些消息,增强了封装性,从而提高了控制子窗口的可重用性。通常在封装一些类是就用这个,比如本文中用的封装类,就是以CListCtrl控件作为基类。
BEGIN_MESSAGE_MAP(CListCtrlColor,CListCtrl)
ON_NOTIFY(NM_CUSTOMDRAW,IDC_LIST,OnCustomMyLIst)
END_MESSAGE_MAP()
第二种则常用在父窗口中不用反射,直接由父窗口处理该消息。例如:创建基于对话框的窗口,在其上加入CListCtrl控件,则用第二种对该控件发生的变化做出处理。

LRESULT参数:该参数相当于函数的返回值函数执行以后系统可以根据该结果作出相应的操作。
函数执行原理:该函数处理NM_CUSTOMDRAW消息的,只要触发该消息就会执行该函数,在本文中ListCtrl控件的重绘都会出发该消息。
函数执行过程:
该处理函数将控件的绘制分为两部分:擦除和绘画。Windows在每部分的开始和结束都会发送NM_CUSTOMDRAW消息。所以总共就有4个消息。但是 实际上你的程序所收到消息可能就只有1个或者多于四个,这取决于你想要让WINDOWS怎么做。每次发送消息的时段被称作为一个“绘画段”。你必须紧紧抓 住这个概念,因为它贯穿于整个“重绘”的过程。
所以,你将会在以下的时间点收到通知:
l 一个item被画之前——“绘画前”段
l 一个item被画之后——“绘画后”段
l 一个item被擦除之前——“擦除前”段
l 一个item被擦除之后——“擦除后”段
并不是所有的消息都是一样有用的,实际上,我不需要处理所有的消息,直到这篇文章完成之前,我还没使用过擦除前和擦除后的消息。所以,不要被这些消息吓到你。
NM_CUSTOMDRAW消息将会给你提供以下的信息:
1.lListCtrl的句柄
2.ListCtrl的ID
3.当前的“绘画段”
4.绘画的DC,让你可以用它来画画
5.正在被绘制的控件、item、subitem的RECT值
6.正在被绘制的Item的Index值
7.正在被绘制的SubItem的Index值
8.正被绘制的Item的状态值(selected,
grayed, 等等)
9.lItem的LPARAM值,就是你使用CListCtrl::SetItemData所设的那个值
其中4的获得方法:CDC
*pDC=CDC::FromHandle(pLVCD->nmcd.hdc);
其中5的获得方法:item=(int)pLVCD->nmcd.dwItemSpec;subitem=
pLVCD->iSubItem;


这两个图分别是刚才那两个值的对应值,图一中返回值解释如下
从图一中我们可以看到返回值分为两个部分:
1.当pLVCD->nmcd.dwDrawStage= CDDS_PREPAINT时即绘画周期开始前:
CDRF_DODEFAULT:返回该值之后该控件自己绘制,整个绘画周期内他不会发送任何其他的NM_CUSTOMDRAW消息,
CDRF_NOTIFYITEMDRAW:该返回值返回以后会通知父窗口相关项的绘画操作,并且在项的绘画开始前和开始后都会发送NM_CUSTOMDRAW;
2.当pLVCD->nmcd.dwDrawStage=CDDS_ITEMPREPAINT时即在该项绘画开始前
CDRF_NOTIFYSUBITEMDRAW:在视图项被绘制之前,你的应用程序会收到一个NM_CUSTOMDRAW消息,该消息中的dwDrawStage为CDDS_ITEMPREPAINT | CDDS_SUBITEM,这时你可以指定画笔和颜色对每个子项进行修改,否则返回CDRF_DODEFAULT默认处理。
CDRF_NEWFONT:你的应用程序使用指定的画笔,然后控件将会调用。
CDRF_SKIPDEFAULT:应用程序绘制这个项,控件不绘制。
上面是我们用到的其他自己研究吧!
看了上面的解释也许你还是一头雾水,那这里我就给你解答:
首先你要明白函数的过程是一个简单的绘画操作,绘画周期开始前 ,绘画前,绘画中,绘画后,你第一次触发NM_CUSTOMDRAW消息肯定是绘画开始前的所以第一个if语句肯定是成立的,这样就执行了第一个if语句,而接下来绘画前,绘画中,绘画后都不会触发,都不执行,这样一个关键点就是返回值了LRESULT了,其返回值就决定了在绘画过程中会不会触发NM_CUSTOMDRAW,这样你也就明白了第一个if中的返回值了吧。
而第二个if是绘画前和第一个的道理是一样的,从上面的解释中我们可以看到其返回值有三个,这三个中我尤其有说明的是CDRF_NOTIFYSUBITEMDRAW,因为该返回值决定是否触发消息进入绘画中,后面的代码中我们会看到在绘画中修改代码……….。
hdr NMHDR对象
dwDrawStage 当前绘制状态,其取值如表7所示:
类型值 含义
CDDS_POSTERASE 擦除循环结束
CDDS_POSTPAINT 绘制循环结束
CDDS_PREERASE 准备开始擦除循环
CDDS_PREPAINT 准备开始绘制循环
CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam参数有效
CDDS_ITEMPOSTERASE 列表项擦除结束
CDDS_ITEMPOSTPAINT 列表项绘制结束
CDDS_ITEMPREERASE 准备开始列表项擦除
CDDS_ITEMPREPAINT 准备开始列表项绘制
CDDS_SUBITEM 指定列表子项
表7 dwDrawStage的类型值与含义
hdc指定了绘制操作所使用的设备环境。
rc指定了将被绘制的矩形区域。
dwItemSpec 列表项的索引
uItemState 当前列表项的状态,其取值如表8所示:
类型值 含义
CDIS_CHECKED 标记状态。
CDIS_DEFAULT 默认状态。
CDIS_DISABLED 禁止状态。
CDIS_FOCUS 焦点状态。
CDIS_GRAYED 灰化状态。
CDIS_SELECTED 选中状态。
CDIS_HOTLIGHT 热点状态。
CDIS_INDETERMINATE 不定状态。
CDIS_MARKED 标注状态。
表8 uItemState的类型值与含义
lItemlParam 当前列表项的绑定数据
pResult 指向状态值的指针,指定系统后续操作,依赖于dwDrawStage:
当dwDrawStage为CDDS_PREPAINT,pResult含义如表9所示:
类型值 含义
CDRF_DODEFAULT 默认操作,即系统在列表项绘制循环过程不再发送NM_CUSTOMDRAW。
CDRF_NOTIFYITEMDRAW 指定列表项绘制前后发送消息。
CDRF_NOTIFYPOSTERASE 列表项擦除结束时发送消息。
CDRF_NOTIFYPOSTPAINT 列表项绘制结束时发送消息。
表9 pResult的类型值与含义(一)
当dwDrawStage为CDDS_ITEMPREPAINT,pResult含义如表10所示:
类型值 含义
CDRF_NEWFONT 指定后续操作采用应用中指定的新字体。
CDRF_NOTIFYSUBITEMDRAW 列表子项绘制时发送消息。
CDRF_SKIPDEFAULT 系统不必再绘制该子项。
pNMCD->nmcd.dwItemSpec 是项的索引
只有当CDRF_NOTIFYSUBITEMDRAW时pNMCD->iSubItem才是子项索引, 否则为0.
针对NM_CUSTOMDRAW消息的学习的更多相关文章
- CORBA GIOP消息格式学习
想要深入理解ORB的工作过程与原理,学习与了解GIOP消息格式必不可少.我们知道GIOP是独立于具体通信的更高级别的抽象,因此这里针对GIOP在TCP/IP上的实现IIOP协议进行学习与分析(IIOP ...
- Flask框架flash消息闪现学习与优化符合闪现之名
Flask的flash 第一次知道Flask有flash这个功能时,听这名字就觉得高端,消息闪现-是跳刀blink闪烁躲技能的top10操作吗?可结果让我好失望,哪里有什么闪现的效果,不过是平常的消息 ...
- MFC中ClistCtrl的=NM_CUSTOMDRAW消息
=NM_CUSTOMDRAW是你点击列表内部是的消息映射: 例如:我想在我删除一行列表的数据,但是删除后下一行数据继续保持高亮状态 void CChildView::OnDel() { int cou ...
- PHP消息队列学习
在我们平常网站设计时,会遇到“给用户群发短信”,“商城订单系统大批量订单处理”,“商城秒杀活动”等需求,这些功能,都有一个共同的特点:就是在面对高迸发的同时,必须要保证系统处理数据的有效性.那么如何处 ...
- kafka消息深入学习
Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域. 1 快写 快读 看下面的图: 传统应用是 硬件到缓存,到应用 再socket进行传输,再进行网络传输,再到用 ...
- NSQ:分布式消息队列学习记录
参考资料: NSQ:分布式的实时消息平台 初识NSQ分布式实时消息架构 深入NSQ之旅 nsq topic和channel的区别
- NM_CUSTOMDRAW 消息
When the control first starts to paint itself, in response to a WM_PAINT, you receive a NM_CUSTOMDRA ...
- java消息服务学习之JMS高级特性
将介绍的内容是: 控制消息确认.为发送消息指定选项.创建临时目的地.使用JMS本地事务.异步发送消息 五个方面. 1.控制消息确认 在JMS消息得到确认之前,并不认为它已经成功使用.要成功使用消息,通 ...
- java消息服务学习之JMS概念
JMS即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信. ...
随机推荐
- Main函数中的参数argc,argv的使用简单解析
本篇文章是对Main函数中的参数argc,argv的使用进行了简单的分析介绍,需要的朋友参考下: C/C++语言中的main函数,经常带有参数argc,argv,如下: int main(int a ...
- 快速开启MySQL慢日志查询的方法
MySQL慢日志查询对于很多刚接触MySQL数据的新人来说比较陌生,下面就为您介绍MySQL慢日志查询的用法和好处,供您参考. mysql有一个功能就是可以log下来运行的比较慢的sql语句,默认是 ...
- StringMVC
public class FirstController implements Controller { public ModelAndView handleRequest(HttpServletRe ...
- 【部分补充】【翻译转载】【官方教程】Asp.Net MVC4入门指南(4):添加一个模型
4. 添加一个模型 · 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-mo ...
- 数据结构-List接口-LinkedList类-Set接口-HashSet类-Collection总结
一.数据结构:4种--<需补充> 1.堆栈结构: 特点:LIFO(后进先出);栈的入口/出口都在顶端位置;压栈就是存元素/弹栈就是取元素; 代表类:Stack; 其 ...
- git remote add 用法
前一阵子,对于git remote add 的内容一直调错,现在明确一下: 这里是gitStack的用法:git remote add gitServerName http://ip/name(这里没 ...
- (六)我的JavaScript系列:更好的JavaScript之CoffeeScript
世界上的很多天才都在为构建更好的JavaScript而努力.已经有了很多尝试,其中最有前途的,无非就是CoffeeScript和TypeScript了.面对CoffeeScript,我有一见如故的感觉 ...
- ALTER AVAILABILITY GROUP (Transact-SQL)
更改 SQL Server 中现有的 AlwaysOn 可用性组. 只有当前主副本支持大多数 ALTER AVAILABILITY GROUP 参数. 但是,只有辅助副本支持 ...
- 数组Array和字符串String的indexOf方法,以及ES7(ES2016)中新增的Array.prototype.includes方法
前言 我们在判断某一个字符是否存在于一个字符串中或者某一个值是否存在于一个数组中时,ES7之前我们需要使用indexOf,ES7引入了新的方法includes 语法 数组:Array.inexOf(s ...
- 洛谷 P1074 靶形数独
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的 ...