博客
关于我
Neat Stuff to Do in List Controls Using Custom Draw
阅读量:790 次
发布时间:2023-02-14

本文共 4247 字,大约阅读时间需要 14 分钟。

Windows 自定义绘制概述

Windows 自定义绘制(Custom Draw)是一种轻量级的、易于使用的替代方案,用于在列表控中实现个性化绘制。相较于传统的所有者绘制(Owner Draw),自定义绘制的优势在于只需处理一个消息(NM_CUSTOMDRAW),并且可以利用 Windows 的部分绘制功能,减少开发复杂度。

自定义绘制的基础知识

自定义绘制的核心在于通过响应 NM_CUSTOMDRAW 消息来实现个性化绘制。这种机制将绘制过程分为几个阶段,允许开发者根据需求选择何时参与绘制。

消息处理与响应

要使用自定义绘制,首先需要在对应的列表控上添加消息处理函数。以下是常见的消息处理方式:

  • ON_NOTIFY ( NM_CUSTOMDRAW, IDC_MY_LIST, OnCustomdrawMyList )

    该宏用于在对应的对话框或类中处理 NM_CUSTOMDRAW 消息。函数 prototype 如下:

    afx_msg void OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult );

    类似地,如果使用继承的方法,可以使用 ON_NOTIFY_REFLECT ( NM_CUSTOMDRAW, OnCustomdraw )

绘制阶段

自定义绘制将绘制过程分为几个阶段,具体如下:

  • 预绘制阶段 (Pre-paint stage):在整个控制器或单个项目开始绘制前通知开发者。
  • 项目预绘制阶段 (Item pre-paint stage):在单个项目开始绘制前通知开发者。
  • 项目绘制完成阶段 (Item post-paint stage):在单个项目绘制完成后通知开发者。
  • 项目擦除阶段 (Item erase stage):在单个项目擦除前和完成后通知开发者。
  • 响应类型与功能

    自定义绘制的响应类型决定了 Windows 如何处理绘制请求。共有五种响应类型:

  • 忽略绘制请求 (CDRF_DODEFAULT):让 Windows 使用默认绘制方式。
  • 通知项目绘制 (CDRF_NOTIFYITEMDRAW):要求 Windows 在每个项目绘制阶段通知开发者。
  • 通知子项目绘制 (CDRF_NOTIFYSUBITEMDRAW):要求 Windows 在每个子项目绘制阶段通知开发者。
  • 自行绘制 (CDRF_DODEFAULT):表明开发者已经完成绘制,不需要进一步处理。
  • 跳过默认绘制 (CDRF_SKIPDEFAULT):表示开发者已经完成绘制,Windows 不需要再执行绘制操作。
  • NM_CUSTOMDRAW 消息内容

    NM_CUSTOMDRAW 消息携带了一个 NMLVCUSTOMDRAW 结构体,提供了丰富的信息:

    • 控制器句柄 (hWnd):对应的窗口句柄。
    • 控制器 ID (idCtrl):控制器的标识符。
    • 绘制阶段 (dwDrawStage):当前绘制阶段。
    • 设备上下文 (hdc):用于绘制的设备上下文。
    • 项目区域 (rect):当前绘制区域。
    • 项目索引 (dwItemSpec):项目的索引。
    • 子项目索引 (iSubItem):子项目的索引。
    • 项目状态 (uItemState):项目的状态(如选中、灰色等)。
    • 项目数据 (lParam):项目的参数数据。

    实际应用示例

    以下是几个典型的自定义绘制应用示例:

    1. 更改项目文本颜色

    通过在项目预绘制阶段设置文本颜色,并在后续阶段通知 Windows 进行绘制。

    void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult ){    NMLVCUSTOMDRAW* pLVCD = reinterpret_cast
    (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); pLVCD->clrText = crText; *pResult = CDRF_DODEFAULT; }}
    2. 子项目绘制

    通过在子项目预绘制阶段设置文本颜色和背景颜色。

    void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult ){    NMLVCUSTOMDRAW* pLVCD = reinterpret_cast
    (pNMHDR); *pResult = 0; 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) { 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); } pLVCD->clrText = crText; pLVCD->clrTextBk = crBkgnd; *pResult = CDRF_DODEFAULT; }}
    3. 项目绘制完成后处理

    通过在项目绘制完成后重绘特定项目。

    void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult ){    NMLVCUSTOMDRAW* pLVCD = reinterpret_cast
    (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 = pLVCD->nmcd.dwItemSpec; 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; } }}

    其他可行性

    通过自定义绘制,可以实现多种效果,如:

    • 行内文本自动换行。
    • 个性化项目图标绘制。
    • 自定义背景和边框效果。

    Demo 项目展示

    以下是利用自定义绘制实现的列表控示例:

    通过上述方法,开发者可以根据需求灵活配置列表控的外观,使用户体验更加丰富个性化。

    转载地址:http://zfcfk.baihongyu.com/

    你可能感兴趣的文章
    nacos本地可以,上服务器报错
    查看>>
    Nacos注册Dubbo(2.7.x)以及namespace配置
    查看>>
    Nacos注册中心有几种调用方式?
    查看>>
    nacos注册失败,Feign调用失败,feign无法注入成我们的bean对象
    查看>>
    nacos源码 nacos注册中心1.4.x 源码 nacos源码如何下载 nacos 客户端源码下载地址 nacos discovery下载地址(一)
    查看>>
    nacos源码 nacos注册中心1.4.x 源码 spring cloud alibaba 的discovery做了什么 nacos客户端是如何启动的(二)
    查看>>
    nacos源码 nacos注册中心1.4.x 源码 如何注册服务 发送请求,nacos clinet客户端心跳 nacos 注册中心客户端如何发送的心跳 (三)
    查看>>
    Nacos源码分析:心跳机制、健康检查、服务发现、AP集群
    查看>>
    nacos看这一篇文章就够了
    查看>>
    Nacos简介、下载与配置持久化到Mysql
    查看>>
    Nacos简介和控制台服务安装
    查看>>
    Nacos管理界面详细介绍
    查看>>
    Nacos编译报错NacosException: endpoint is blank
    查看>>
    nacos自动刷新配置
    查看>>
    nacos运行报错问题之一
    查看>>
    Nacos部署中的一些常见问题汇总
    查看>>
    NACOS部署,微服务框架之NACOS-单机、集群方式部署
    查看>>
    Nacos配置Mysql数据库
    查看>>
    Nacos配置中心中配置文件的创建、微服务读取nacos配置中心
    查看>>
    Nacos配置中心集群原理及源码分析
    查看>>