2012mfc,自绘列表控件
原文
使用常用控件版本4.70
中的自定义绘画功能
自定义列表控件的外观
.
介绍
常见控件的4.70
版引入了一项叫自定义绘画
的功能.
可按轻量易用
的自画版本
对待自定义绘画
.易用性
来自,即只需
处理一条消息(NM_CUSTOMDRAW
),且你可让窗口
为你干活,因此你不必完成物主绘画
中的所有粗活
.
本文介绍重点如何用列视控件
自定义绘画
.
自画基础
我尽量在此总结
自定义绘画过程
.对这些示例
,假设你在对话框
中有一个列表控件
,且该列表
是带多列的报表视图模式
.
勾挂自定义DrawMessage
映射项
自定义绘画
是一个类似回调
的过程.窗口
在绘画列表控件
过程中的某些时刻
通过通知消息
通知程序.你可选择完全忽略
通知(此时,会看到标准列表控件
),自己处理绘画的某些部分
(来实现简单的效果
),甚至与在自画控件
一样,自己绘画控件
.
真正卖点
是,你可选择只响应部分通知
.这样,只需绘画
你需要的部分,窗口
完成其余工作
.
假设想在现有列表控件
中添加自定义绘画
,以加一些光晕
.假设在系统上拥有
正确的常用控件DLL
,窗口
已按你的方式
发送NM_CUSTOMDRAW
消息;
你只需为消息
添加一个处理器
,即可开始使用自定义绘画
.处理器
如下:
ON_NOTIFY ( NM_CUSTOMDRAW, IDC_MY_LIST, OnCustomdrawMyList )
…原型如下:
afx_msg void OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult );
这会告诉MFC
,在NM_CUSTOMDRAW
通知码时,想处理从列表控件
(其ID
为IDC_MY_LIST
)发送的WM_NOTIFY
消息.
处理器
叫OnCustomdrawMyList
.如果要给它添加自定义绘画
的CListCtrl
继承类,则可改用ON_NOTIFY_REFLECT
:
ON_NOTIFY_REFLECT ( NM_CUSTOMDRAW, OnCustomdraw )
消息处理器
有同上的原型
,但它在继承类
中.
自定义绘画阶段
自定义绘画
将绘画过程
分为两部分
:擦除和绘画
.窗口
可能会在每个部分
的开头和结尾
,发送NM_CUSTOMDRAW
消息.
所以总共
有四条信息
.但是,根据你告诉窗口
期望内容,应用
实际上可能会收到少至一条或多于四条消息
.可发送通知
的时间叫"绘画阶段
".
要很好地掌握该概念
,因为在整个自定义绘画过程
中使用它.因此,总结一下,在以下时间(或阶段)
收到通知
:
1,在画项
前
2,在画项
后
3,在擦除项
前
4,在擦除项
后
并非所有这些
都同样有用
,且实际上,还需要处理多个阶段
.
响应NM_CUSTOMDRAW
消息
从自定义绘画处理器
中返回的值
是一条至关重要的信息
,因为它告诉窗口
你已完成了多少绘画过程
,及间接
地告诉想让窗口
完成的工作.
可从自定义绘画
处理器中发送五个响应
:
1,我现在什么
都不想做;窗口
应绘画控件或项自身
,与没有自定义绘画处理器
一样.
2,我更改
了控件使用的字体
;窗口
必须重新计算
正在绘画的项
的矩
.
3,我绘画
了整个控件或项
;窗口
不应再处理控件或项
.
4,我想在列表
中每一项的绘画阶段
,收到额外
的NM_CUSTOMDRAW
消息.
5,我想在当前正在绘画的行
中,每个子项
的绘画阶段
接收其他NM_CUSTOMDRAW
消息.
注意,"控件或项"
经常出现.记住,我说过或会收到四条以上
的NM_CUSTOMDRAW
消息,就是这里.你收到
的第一个NM_CUSTOMDRAW
针对整个控件
.
如果返回
上面的响应4
(按每一项
请求通知),则在每一(行)项
经过绘画阶段
时,你都收到消息
.如果随后
返回响应5
,则在每个子项(列)
经过其绘画阶段
时,你将收到更多消息
.
在报告模式列表控件
中,你可根据想要实现的效果类型
,任意用这些响应
中的一个
.稍后提供一些如何响应NM_CUSTOMDRAW
消息的示例.
NM_CUSTOMDRAW
消息提供的信息
NM_CUSTOMDRAW
消息给处理器
传递包含以下信息
的NMLVCUSTOMDRAW
结构的指针
:
1,控件的窗口句柄
2,控件的ID
3,控件
当前所在的绘画阶段
4,绘画
时应使用的设环的句柄
5,正在绘画
的控件,项或子项
的矩
6,正在绘画
的项的项号(索引)
7,正在绘画
的子项的子项编号(索引)
8,正在绘画的项
的状态(已选择,灰显等)
的标志
9,正在绘画的项
的由CListCtrl::SetItemData
设置的长参
数据
根据想要的效果
,这些项中的一个
可能很重要,但你总是会使用绘画
阶段,一般还会使用设环
.项索引
和长参
一般也非常有用
.
简单示例
第一例
非常简单,只需更改控件
中文本的颜色,在红色,绿色和蓝色间旋转
.这涉及四个步骤
:
1,在控件的预画阶段
处理NM_CUSTOMDRAW
2,告诉窗口
想取每一项
的NM_CUSTOMDRAW
消息
3,处理为每一项
发送的后续NM_CUSTOMDRAW
消息.
4,设置每一项的文本色
.
这是处理器:
void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult )
{NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );//取默认处理,除非在下面按其他值设置它.*pResult = CDRF_DODEFAULT;//首先,检查绘画阶段.如果这是`控件的预绘画阶段`,则告诉`窗口`想让每一项都有消息.if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage ){*pResult = CDRF_NOTIFYITEMDRAW;else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage ){//这是项的预绘画阶段.这是设置项文本色的地方.返回值告诉`窗口`绘画项自身,但它使用在此处设置的新颜色.将在红色,绿色和浅蓝色间循环显示颜色.COLORREF crText;if ( (pLVCD->nmcd.dwItemSpec % 3) == 0 )crText = RGB(255,0,0);else if ( (pLVCD->nmcd.dwItemSpec % 3) == 1 )crText = RGB(0,255,0);elsecrText = RGB(128,128,255);//在`NMLVCUSTOMDRAW`结构中存储颜色.pLVCD->clrText = crText;//指示`窗口`绘画控件自身.*pResult = CDRF_DODEFAULT;}
}
看看每一行
如何有告诉窗口
使用Cool
的颜色,所有这些都只需要
几个如
语句!
记住,在执行其他操作
前,必须总是检查绘画
阶段,因为处理器
将收到许多消息
,而绘画
阶段决定了代码
干的活.
一个不简单的示例
下一例
演示如何处理子项(即列)
的自定义绘画
.处理器设置文本和单元格背景色
,但它不会比上个复杂多少;只有一个额外
的如
块.处理子项
时涉及的步骤包括:
1,在控件
的预画阶段
处理NM_CUSTOMDRAW
.
2,告诉窗口
想取每一项
的NM_CUSTOMDRAW
消息
3,当传入其中一条消息
时,告诉窗口
想在每个子项
的预绘画
阶段取NM_CUSTOMDRAW
消息.
4,每次子项的后续消息
到达时,设置文本和背景色
.
注意,按一个整体
,每一项
收到一条NM_CUSTOMDRAW
消息,并对0
子项(第一列)
收到另一条消息
.这是代码
:
void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult )
{NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );//除非在下面按其他值设置它,否则取默认处理.*pResult = CDRF_DODEFAULT;//首先-检查绘画阶段.如果这是控件的预绘画阶段,则告诉`窗口`想让每一项都有消息.if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage ){*pResult = CDRF_NOTIFYITEMDRAW;}else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage ){//这是项的通知消息.请求在每个子项的预绘画阶段前通知.*pResult = CDRF_NOTIFYSUBITEMDRAW;}else if ( (CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage ){//这是子项的预绘画阶段.在此,设置项的文本和背景色.返回值告诉`窗口`绘画子项自身,但它使用在此处设置的新颜色.文本色将在红色,绿色和浅蓝色间循环.第0列的背景色为浅蓝色,第1列的背景色为红色,第2列的背景色为黑色.COLORREF crText, crBkgnd;if ( 0 == pLVCD->iSubItem ){crText = RGB(255,0,0);crBkgnd = RGB(128,128,255);}else if ( 1 == pLVCD->iSubItem ){crText = RGB(0,255,0);crBkgnd = RGB(255,0,0);}else{crText = RGB(128,128,255);crBkgnd = RGB(0,0,0);}//在`NMLVCUSTOMDRAW`结构中存储颜色.pLVCD->clrText = crText;pLVCD->clrTextBk = crBkgnd;//指示`窗口`绘画控件自身.*pResult = CDRF_DODEFAULT;}
}
这里有几点注意:
1,仅在列
中绘画clrTextBk
颜色.最后一列右边和最后一行下方
的区域
仍会取得控件的背景色
.
2,查看文档时,我读了标题为"NM_CUSTOMDRAW(列视)
"的页,它说你可从第一条自定义绘画消息
中返回CDRF_NOTIFYSUBITEMDRAW
,而无需处理CDDS_ITEMPREPAINT
绘画阶段.
3,但是,测试了下,但它不管用
.实际上确实
需要处理CDDS_ITEMPREPAINT
阶段.
处理绘画后绘画阶段
当前,这些示例
已处理了预绘画阶段
,这样在窗口
绘画列表项
时,更改列表项的外观
.但是,在预绘画
阶段,你的选项
仅限于更改文本的颜色或外观
.
如果想更改图标的绘画方式
,可在预绘画阶段
(过度)绘画整个项
,或在绘画
后阶段自定义绘画
.当你在绘画
后阶段自定义绘画
时,在窗口
绘画整个项或子项
后,调用你的自定义绘画处理器
,可执行想要的其他绘画
.
在此例中,我创建一个列表控件
,其中不会更改所选项的图标
颜色.涉及
步骤是:
1,在控件
的预画阶段
处理NM_CUSTOMDRAW
2,告诉窗口
,想取每一项
的NM_CUSTOMDRAW
消息
3,传入其中一条消息
时,告诉窗口
,想在项的绘画后阶段
收到NM_CUSTOMDRAW
消息.
4,每次项
的后续消息
到达时,必要时重画图标
.
void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult )
{
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );*pResult = 0;//如果这是控件绘画周期的开始,对每一项请求通知.if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage ){*pResult = CDRF_NOTIFYITEMDRAW;}else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage ){//这是项的预绘画阶段.在`绘画后阶段`,需要再次请求通知.*pResult = CDRF_NOTIFYPOSTPAINT;}else if ( CDDS_ITEMPOSTPAINT == pLVCD->nmcd.dwDrawStage ){//如果选择了此项,则按正常颜色(不用高亮颜色混合)重画图标.LVITEM rItem;int nItem = static_cast<int>( pLVCD->nmcd.dwItemSpec );//取此项的`imageindex`和`状态`.注意,需要手动检查所选状态.文档_说_该项的状态在`pLVCD->nmcd.uItemState`中,但在测试时它总是等于`0x0201`,这没有意义,因为`commctrl.h`中的最大`CDIS_*`常是`0x0100`.ZeroMemory ( &rItem, sizeof(LVITEM) );rItem.mask = LVIF_IMAGE | LVIF_STATE;rItem.iItem = nItem;rItem.stateMask = LVIS_SELECTED;m_list.GetItem ( &rItem );//如果选中此项,则使用其正常颜色重画图标.if ( rItem.state & LVIS_SELECTED ){CDC* pDC = CDC::FromHandle ( pLVCD->nmcd.hdc );CRect rcIcon;//取包含项图标的`矩`.m_list.GetItemRect ( nItem, &rcIcon, LVIR_ICON );//绘画图标.m_imglist.Draw ( pDC, rItem.iImage, rcIcon.TopLeft(), ILD_TRANSPARENT );*pResult = CDRF_SKIPDEFAULT;}}
}
同样,自定义绘画
可尽量少地干活
.此例的作用
是让窗口
完成所有绘画
,然后覆盖
所选每一项的图标
.这样,用户只看到我们绘画的图标
.
注意,Stan
的图标与未选中项
的图标相同.
缺点是有时会看一点闪烁
,因为图标
是两次快速连续绘画
的.
使用自定义画
代替物主画
可用自定义画
做的另一件巧妙的事情
是,用来执行与物主画
相同操作.区别在,使用自定义绘画
时,更容易
编写和理解代码
.
另一个优点
是,如果只需要自画某些行
,则可这样并让窗口
绘画其他行
.在真正的自画控件
时,即使不需要"特效"
,也必须执行所有操作
.
使用自定义绘画自画
时,需要处理
在项的预绘画阶段
发送的NM_CUSTOMDRAW
消息,执行所有绘画
,并从处理器
返回CDRF_SKIPDEFAULT
.
这与迄今为止
不同.CDRF_SKIPDEFAULT
会告诉窗口
不要在该行
中绘画
,因为你已完成了所有操作
.
相关文章:
2012mfc,自绘列表控件
原文 使用常用控件版本4.70中的自定义绘画功能自定义列表控件的外观. 介绍 常见控件的4.70版引入了一项叫自定义绘画的功能. 可按轻量易用的自画版本对待自定义绘画.易用性来自,即只需处理一条消息(NM_CUSTOMDRAW),且你可让窗口为你干活,因此你不必完成物主绘画中的所有粗活…...
vue3运行时执行过程步骤
在 Vue 3 中,运行时的执行过程是一个复杂但高效的机制,主要包括初始化应用、渲染、响应式更新和销毁等阶段。以下是 Vue 3 运行时的执行过程的核心步骤和流程: 1. 应用初始化 1.1 创建 Vue 应用 调用 createApp 方法,创建一个 V…...
常用的AT命令,用于查看不同类型的网络信息
文章目录 1. ATCSQ:2. ATCREG:3. ATCOPS:4. ATCGATT:5. ATCGPADDR: 在AT命令集中,用于查看网络信息的命令有多种,具体取决于所使用的设备和模块。以下是一些常用的AT命令࿰…...
Vue3组件通讯——自定义事件(子->父)
需求如下: 1.在子组件中,当用户点击提交按钮后,更新数据库 2.数据更新成功后,子组件通知父组件getUserInfo函数,重新获取数据,同步更新 3.子组件等待getUserInfo函数执行完毕后,调用init函数…...
GLSL 着色器语言
GLSL 着色器语言 1. 着色器语言基础1.1 数据类型1.2 数据类型的基本使用1.3 运算符1.4 各个数据类型的构造函数1.5 类型转换1.6 存储限定符1.7 插值限定符1.8 一致块1.9 layout 限定符1.10 流程控制1.11 函数的声明和使用1.12 片元着色器中浮点及整型变量精度的指定1.13 程序的…...
如何创建一个 Vue.js 工程
创建一个 Vue.js 工程 可以分为以下几个步骤: 安装 Node.js 和 npm:Vue.js 依赖于 Node.js 和 npm,因此首先需要在计算机上安装 Node.js 和 npm。可以从 Node.js 的官方网站(https://nodejs.org/)下载并安装。 安装 V…...
Mysql 性能优化:覆盖索引
概述 覆盖索引(Covering Index)是一个 MySQL 查询优化技术,它指的是一个索引包含了查询所需的所有字段的数据,因此不需要回表(访问数据表的行)就可以完成查询。使用覆盖索引可以显著提高查询性能ÿ…...

vulnhub靶场【DC系列】之7
前言 靶机:DC-7,IP地址为192.168.10.13 攻击:kali,IP地址为192.168.10.2 都采用VMWare,网卡为桥接模式 对于文章中涉及到的靶场以及工具,我放置在网盘中,链接:https://pan.quark…...
iOS - 消息机制
1. 基本数据结构 // 方法结构 struct method_t {SEL name; // 方法名const char *types; // 类型编码IMP imp; // 方法实现 };// 类结构 struct objc_class {Class isa;Class superclass;cache_t cache; // 方法缓存class_data_bits_t bits; // 类的方法…...

Wireshark 学习笔记1
1.wireshark是什么 wireshark是一个可以进行数据包的捕获和分析的软件 2.基本使用过程 (1)选择合适的网卡 (2)开始捕获数据包 (3)过滤掉无用的数据包 (4)将捕获到的数据包保存为文件…...

Oracle OCP考试常见问题之线上考试流程
首先要注意的是:虽然Oracle官方在国际上取消了获得OCP认证需要培训记录的要求,但在中国区,考生仍然需要参加Oracle的官方或者其合作伙伴组织的培训,并且由Oracle授权培训中心向Oracle提交学员培训记录。考生只有在完成培训并通过考…...

微信小程序之历史上的今天
微信小程序之历史上的今天 需求描述 今天我们再来做一个小程序,主要是搜索历史上的今天发生了哪些大事,结果如下 当天的历史事件或者根据事件选择的历史事件的列表: 点击某个详细的历史事件以后看到详细信息: API申请和小程序…...

记一次k8s下容器启动失败,容器无日志问题排查
问题 背景 本地开发时,某应用增加logback-spring.xml配置文件,加入必要的依赖: <dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>8…...
【HarmonyOS】纯血鸿蒙真实项目开发---经验总结贴
项目场景: 将已有的Web网页接入到原生App。 涉及到一些网页回退、webviewController执行时机报错1710000001、位置定位数据获取、拉起呼叫页面、系统分享能力使用等。 问题描述 我们在选项卡组件中,在每个TabContent内容页中使用web组件加载网页。 在…...

kettle做增量同步,出现报错:Unrecognized VM option ‘MaxPermSize-256m‘
本文内容来自YashanDB官网,原文内容请见:https://yashandb.com/newsinfo/7863039.html?templateId1718516 问题现象 kettle在增量同步过程,出现报错:Unrecognized VM option ‘MaxPermSize256m’ 问题的风险及影响 无法使用ke…...
网络安全、Web安全、渗透测试之笔经面经总结(三)
本篇文章涉及的知识点有如下几方面: 1.什么是WebShell? 2.什么是网络钓鱼? 3.你获取网络安全知识途径有哪些? 4.什么是CC攻击? 5.Web服务器被入侵后,怎样进行排查? 6.dll文件是什么意思,有什么…...

计算机的错误计算(二百零五)
摘要 基于一位读者的问题,提出题目:能用数值计算证明 吗?请选用不同的点(即差别大的数)与不同的精度。实验表明,大模型理解了题意。但是,其推理能力值得商榷。 例1. 就摘要中问题࿰…...

Vue3(一)
1.Vue3概述 Vue3的API由Vue2的选项式API改为了组合式API。但是,也是Vue2中的选项式API也是兼容的。 2.创建Vue3项目 create-vue 是 Vue 官方新的脚手架工具,底层切换到了 vite。使用create-vue创建项目的步骤如下: 安装 create-vue npm i…...

【项目】修改远程仓库地址、报错jdk
一、修改远程仓库地址 进入你刚刚克隆到本地的仓库目录,执行以下命令来修改远程仓库的 URL,将其指向你自己的新仓库: cd 原仓库名 git remote set-url origin <你自己的新仓库的 Git 地址>补充: 错误分析: wa…...

实训云上搭建集群
文章目录 1. 登录实训云1.1 实训云网址1.2 登录实训云 2. 创建网络2.1 网络概述2.2 创建步骤 3. 创建路由器3.1 路由器名称3.1 创建路由器3.3 查看网络拓扑 4. 连接子网5. 创建虚拟网卡5.1 创建原因5.2 查看端口5.3 创建虚拟网卡 6. 管理安全组规则6.1 为什么要管理安全组规则6…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...