2012mfc,自绘列表控件

news2025/1/11 5:19:40

原文

使用常用控件版本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通知码时,想处理从列表控件(其IDIDC_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);
        else
            crText = 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会告诉窗口不要在该行绘画,因为你已完成了所有操作.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2274715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

太速科技-FMC141-四路 250Msps 16bits AD FMC子卡

FMC141-四路 250Msps 16bits AD FMC子卡 一、产品概述&#xff1a; 本板卡基于 FMC 标准板卡&#xff0c;实现 4 路 16-bit/250Msps ADC 功能。遵循 VITA 57 标准&#xff0c;板卡可以直接与xilinx公司或者本公司 FPGA 载板连接使用。板卡 ADC 器件采用 ADI 公司 AD9467 芯…

通义灵码在跨领域应用拓展之物联网篇

目录 一.引言 二.通义灵码简介 三.通义灵码在物联网领域的设备端应用 1.传感器数据采集 (1).不同类型传感器的数据读取 (2).数据转换与预处理 2.设备控制指令接收和执行 (1).指令解析与处理 (2).设备动作执行 四.通义灵码在物联网领域的云端平台应用 1.数据存储和管…

使用Kubernetes部署Spring Boot项目

目录 前提条件 新建Spring Boot项目并编写一个接口 新建Maven工程 导入 Spring Boot 相关的依赖 启动项目 编写Controller 测试接口 构建镜像 打jar包 新建Dockerfile文件 Linux目录准备 上传Dockerfile和target目录到Linux 制作镜像 查看镜像 测试镜像 上传镜…

C#基础之 继承类相关构造函数使用

类构造函数 作用是为 类中成员变量进行赋值操作 单个类的时候 一般不会有什么思路问题&#xff0c;主要说明一下 有继承关系类的时候 当存在继承关系的类 如 A&#xff1a;B 首先要注意第一点&#xff1a;顺序 那么在构造函数时 顺序是由 B先构造 然后 A在构造 注意第二点方法…

【leetcode刷题】:双指针篇(有效三角形的个数、和为s的两个数)

文章目录 一、有效三角形的个数题目解析算法原理代码编写 二、和为s的两个数题目解析算法原理代码编写 一、有效三角形的个数 题目解析 有效三角形的个数【点击跳转】 题目意思很好理解&#xff1a;就是在一堆非负整数的数组里&#xff0c;随机选三个数进行搭配&#xff0c;…

【Unity3D】apk加密(global-metadata.dat加密)

涉及&#xff1a;apk、aab、global-metadata.dat、jks密钥文件、APKTool、zipalign 使用7z打开apk文件观察发现有如下3个针对加密的文件。 xxx.apk\assets\bin\Data\Managed\Metadata\global-metadata.dat xxx.apk\lib\armeabi-v7a\libil2cpp.so xxx.apk\lib\arm64-v8a\libil…

机器学习之贝叶斯分类器和混淆矩阵可视化

贝叶斯分类器 目录 贝叶斯分类器1 贝叶斯分类器1.1 概念1.2算法理解1.3 算法导入1.4 函数 2 混淆矩阵可视化2.1 概念2.2 理解2.3 函数导入2.4 函数及参数2.5 绘制函数 3 实际预测3.1 数据及理解3.2 代码测试 1 贝叶斯分类器 1.1 概念 贝叶斯分类器是基于贝叶斯定理构建的分类…

前端报告 2024:全新数据,深度解析未来趋势

温馨提示: 此报告为国际版全球报告,其中所涉及的技术应用、工具偏好、开发者习惯等情况反映的是全球前端开发领域的综合态势。由于国内外技术发展环境、行业生态以及企业需求等存在差异,可能有些内容并不完全契合国内的实际情况,请大家理性阅读,批判性地吸收其中的观点与信…

科普CMOS传感器的工作原理及特点

在当今数字化成像的时代&#xff0c;图像传感器无疑是幕后的关键 “功臣”&#xff0c;它宛如一位神奇的 “光影魔法师”&#xff0c;通过光电效应这一奇妙的物理现象&#xff0c;将光子巧妙地转换成电荷&#xff0c;为图像的诞生奠定基础。而在众多类型的图像传感器中&#xf…

word论文排版常见问题汇总

word论文排版常见问题汇总 常用快捷键&#xff1a; Alt F9 正常模式与域代码模式切换 Ctrl F9 插入域代码 F9 刷新域代码显示&#xff0c;要注意选定后刷新才会有效果 word中在当前列表的基础上修改列表 在使用word时&#xff0c;我们会定义一个列表&#xff0c;并将其链接…

使用PVE快速创建虚拟机集群并搭建docker环境

安装Linux系统 这里以安装龙蜥操作系统AnolisOS8.9为例加以说明。 通过PVE后台上传操作系统ISO镜像。 然后在PVE上【创建虚拟机】&#xff0c;选定上传的龙蜥操作系统镜像进行系统安装。 注意&#xff1a;在安装过程中&#xff0c;要设定语言、时区、超管用户root的密码、普…

某音响制造公司发展战略转型项目成功案例纪实

面对产业结构变化、海外订单缩减、劳动力成本攀升、缺乏自主品牌等原因导致的利润空间急剧下降的挑战&#xff0c;面向海外市场的代工厂如何在严峻的经济形势下克服发展障碍&#xff0c;成功实现转型与发展&#xff1f; 某音响制造公司&#xff0c;面临着订单量减少、成本增高…

redis的学习(三)

6. set集合 集合&#xff1a;把一些有关联的数据放在一起。 1、集合中的元素是无序的&#xff0c;即数据存放顺序不重要&#xff0c;变化一下顺序&#xff0c;集合依旧是之前的集合。 2、集合中的元素是不能重复的&#xff08;唯一性&#xff09;与list类似的是集合中的每一个元…

点赞系统设计(微服务)

点赞业务是一个常见的社交功能&#xff0c;它允许用户对其他用户的内容&#xff08;如帖子、评论、图片等&#xff09;表示喜欢或支持。在设计点赞业务时&#xff0c;需要考虑以下几个方面&#xff1a; 一、业务需求 点赞业务需要满足以下特性&#xff1a; 通用&#xff1a;…

C#进阶-在Ubuntu上部署ASP.NET Core Web API应用

随着云计算和容器化技术的普及&#xff0c;Linux 服务器已成为部署 Web 应用程序的主流平台之一。ASP.NET Core 作为一个跨平台、高性能的框架&#xff0c;非常适合在 Linux 环境中运行。本篇博客将详细介绍如何在 Linux 服务器上部署 ASP.NET Core Web API 应用&#xff0c;包…

设计模式-结构型-桥接模式

1. 什么是桥接模式&#xff1f; 桥接模式&#xff08;Bridge Pattern&#xff09; 是一种结构型设计模式&#xff0c;它旨在将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。通过这种方式&#xff0c;系统可以在抽象和实现两方面进行扩展&#xff0c;而无需相互影响…

python学习笔记—16—数据容器之元组

1. 元组——tuple(元组是一个只读的list) (1) 元组的定义注意&#xff1a;定义单个元素的元组&#xff0c;在元素后面要加上 , (2) 元组也支持嵌套 (3) 下标索引取出元素 (4) 元组的相关操作 1. index——查看元组中某个元素在元组中的位置从左到右第一次出现的位置 t1 (&qu…

基础算法--查找

一、线性枚举 1、线性枚举定义 线性枚举指的就是遍历某个一维数组&#xff08;顺序表&#xff09;的所有元素&#xff0c;找到满足条件的那个元素并且返回&#xff0c;返回值可以是下标&#xff0c;也可以是元素本身。 由于是遍历的&#xff0c;穷举了所有情况&#xff0c;所…

G1垃圾回收器的FullGC

如何确定GarbageFirst回收器发生的是FullGC ? 必须出现FullGC字样才算是FUllGC&#xff0c;例如下图&#xff1a;因为内存分配失败&#xff08;Allocation Failure&#xff09;导致 如果不出现FullGC的字样说明它不是FUllGC&#xff0c;并不像Serial GC、ParallelGC的在老年代…

Golang的代码压缩技术应用案例分析与研究实践

Golang的代码压缩技术应用案例分析与研究实践 一、介绍 是一种具有强大性能和便捷开发特性的编程语言&#xff0c;除了其优秀的语法和标准库外&#xff0c;它还拥有很多高级特性&#xff0c;其中之一就是代码压缩技术。本文将从常见的Golang代码压缩技术应用案例出发&#xff0…