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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面向对象分析与设计Python版 面向对象分析方法

文章目录 前言一、名词法二、名词法-案例三、CRC卡片法四、分析模型法&#xff08;了解&#xff09; 前言 面向对象分析的目标&#xff1a;发现对象、定义对象之间的关系和属性。常用的面向对象分析方法有三种&#xff1a; 名词法CRC卡片法分析模型法 一、名词法 大型复杂系…

python基础和redis

1. Map函数 2. filter函数 numbers generate_numbers() filtered_numbers filter(lambda x: x % 2 0, numbers) for _ in range(5):print(next(filtered_numbers)) # 输出: 0 2 4 6 83. filter map 和 reduce 4. picking and unpicking 5. python 没有函数的重载&#xff0…

Vue2:el-table中的文字根据内容改变颜色

想要实现的效果如图,【级别】和【P】列的颜色根据文字内容变化 1、正常创建表格 <template><el-table:data="tableData"style="width: 100%"><el-table-column prop="id" label="ID"/> <el-table-column …

git提交

基本流程&#xff1a;新建分支 → 分支上开发(写代码) → 提交 → 合并到主分支 拉取最新代码因为当前在 master 分支下&#xff0c;你必须拉取最新代码&#xff0c;保证当前代码与线上同步&#xff08;最新&#xff09;&#xff0c;执行以下命令&#xff1a;bashgit pull orig…

Airflow:TimeSensor感知时间条件

在数据管道工作流中&#xff0c;任务可能需要在特定的时间执行&#xff0c;或者在继续之前等待一定的时间。为了满足这些需求&#xff0c;Apache Airflow提供了TimeSensor&#xff0c;这是一种内置Sensor&#xff0c;可以监控当前时间&#xff0c;并在达到指定时间时触发后续任…

JS爬虫实战演练

在这个小红书私信通里面进行一个js的爬虫 文字发送 async function sendChatMessage(content) {const url https://pro.xiaohongshu.com/api/edith/ads/pro/chat/chatline/msg;const params new URLSearchParams({porch_user_id: 677e116404ee000000000001});const messageD…

Center Loss 和 ArcFace Loss 笔记

一、Center Loss 1. 定义 Center Loss 旨在最小化类内特征的离散程度&#xff0c;通过约束样本特征与其类别中心之间的距离&#xff0c;提高类内特征的聚合性。 2. 公式 对于样本 xi​ 和其类别yi​&#xff0c;Center Loss 的公式为&#xff1a; xi​: 当前样本的特征向量&…

【Maui】动态菜单实现(绑定数据视图)

前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移动和桌面应用。 使用 .NET MAUI&#xff0c;可从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。 .NET MAUI 是一款开放源代码应用&#xff0c;是 X…

【json】

JSON JSON是一种轻量级的,按照指定的格式去组织和封装数据的数据交互格式。 本质上是一个带有特定格式的字符串(py打印json时认定为str类型) 在各个编程语言中流通的数据格式&#xff0c;负责不同编程语言中的数据传递和交互,类似于计算机普通话 python与json关系及相互转换…

51单片机——中断(重点)

学习51单片机的重点及难点主要有中断、定时器、串口等内容&#xff0c;这部分内容一定要认真掌握&#xff0c;这部分没有学好就不能说学会了51单片机 1、中断系统 1.1 概念 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的&#xff0c;中断功能的存在&#…

易支付二次元网站源码及部署教程

易支付二次元网站源码及部署教程 引言 在当今数字化时代&#xff0c;二次元文化逐渐成为年轻人生活中不可或缺的一部分。为了满足这一庞大用户群体的需求&#xff0c;搭建一个二次元主题网站显得尤为重要。本文将为您详细介绍易支付二次元网站源码的特点及其部署教程&#xf…

开源生成式物理引擎Genesis,可模拟世界万物

这是生成大模型时代 —— 它们能生成文本、图像、音频、视频、3D 对象…… 而如果将所有这些组合到一起&#xff0c;我们可能会得到一个世界&#xff01; 现在&#xff0c;不管是 LeCun 正在探索的世界模型&#xff0c;还是李飞飞想要攻克的空间智能&#xff0c;又或是其他研究…

【fly-iot飞凡物联】(19):开源飞凡物联项目重启,使用go重写后端代码,感兴趣的小伙伴可以一起参加,使用apache协议开源,招募感兴趣的小伙伴!!

目录 前言fly-iot飞凡物联&#xff0c;感兴趣的小伙伴可以一起参加&#xff0c;使用apache协议开源使用go重写后端代码 前言 fly-iot飞凡物联专栏&#xff1a; https://blog.csdn.net/freewebsys/category_12219758.html fly-iot飞凡物联&#xff0c;感兴趣的小伙伴可以一起参…

用于与多个数据库聊天的智能 SQL 代理问答和 RAG 系统(3) —— 基于 LangChain 框架的文档检索与问答功能以及RAG Tool的使用

介绍基于 LangChain 框架的文档检索与问答功能&#xff0c;目标是通过查询存储的向量数据库&#xff08;VectorDB&#xff09;&#xff0c;为用户的问题检索相关内容&#xff0c;并生成自然语言的答案。以下是代码逻辑的详细解析&#xff1a; 代码结构与功能 初始化环境与加载…

消息中间件类型介绍

消息中间件是一种在分布式系统中用于实现消息传递的软件架构模式。它能够在不同的系统或应用之间异步地传输数据&#xff0c;实现系统的解耦、提高系统的可扩展性和可靠性。以下是几种常见的消息中间件类型及其介绍&#xff1a; 1.RabbitMQ 特点&#xff1a; • 基于AMQP&#…

uniapp使用scss mixin抽离css常用的公共样式

1、编写通用scss样式文件 // 通用 Flex Mixin mixin flex($direction: row, $justify: flex-start, $align: stretch, $wrap: nowrap) {display: flex;flex-direction: $direction;justify-content: $justify;align-items: $align;flex-wrap: $wrap; }// 水平居中 mixin flex-…

Matlab Steger算法提取条纹中心线(亚像素位置)

文章目录 一、简介二、实现代码三、实现效果参考文献一、简介 Steger 算法是一种常用的图像边缘检测算法,可以用于提取图像中的中心线或边缘信息。它的理论假设是:条纹的亮度是按照高斯分布呈现的,即中心亮两侧渐暗。 其计算过程如下所述: 1、首先,我们需要计算每个点Hess…

PySide6 Qt for Python Qt Quick参考网址

Qt QML BOOK&#xff1a; 《Qt for Python》 -Building an Application https://www.qt.io/product/qt6/qml-book/ch19-python-build-app#signals-and-slots Qt for Python&#xff1a;与C版本的差异即BUG处理&#xff08;常见的DLL文件确实的问题等&#xff09; Qt for Pyt…

【大数据】Apache Superset:可视化开源架构

Apache Superset是什么 Apache Superset 是一个开源的现代化数据可视化和数据探索平台&#xff0c;主要用于帮助用户以交互式的方式分析和展示数据。有不少丰富的可视化组件&#xff0c;可以将数据从多种数据源&#xff08;如 SQL 数据库、数据仓库、NoSQL 数据库等&#xff0…

ELK实战(最详细)

一、什么是ELK ELK是三个产品的简称&#xff1a;ElasticSearch(简称ES) 、Logstash 、Kibana 。其中&#xff1a; ElasticSearch&#xff1a;是一个开源分布式搜索引擎Logstash &#xff1a;是一个数据收集引擎&#xff0c;支持日志搜集、分析、过滤&#xff0c;支持大量数据…