博客
关于我
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/

    你可能感兴趣的文章
    Mysql死锁问题Deadlock found when trying to get lock;try restarting transaction
    查看>>
    MySQL添加用户、删除用户与授权
    查看>>
    Mysql添加用户并授予只能查询权限
    查看>>
    mysql添加表注释、字段注释、查看与修改注释
    查看>>
    MySQL灵魂16问,你能撑到第几问?
    查看>>
    mysql状态分析之show global status
    查看>>
    mysql状态查看 QPS/TPS/缓存命中率查看
    查看>>
    mysql生成树形数据_mysql 实现树形的遍历
    查看>>
    mysql用于检索的关键字_Mysql全文搜索match...against的用法
    查看>>
    MySql用户以及权限的管理。
    查看>>
    MySQL用户权限配置:精细控制和远程访问的艺术!------文章最后有惊喜哦。
    查看>>
    mysql用户管理、常用语句、数据分备份恢复
    查看>>
    MySQL留疑问:left join时选on还是where?
    查看>>
    mysql登陆慢问题解决
    查看>>
    MySQL的 DDL和DML和DQL的基本语法
    查看>>
    mysql的 if else , case when then, IFNULL
    查看>>
    MySQL的10种常用数据类型
    查看>>
    mysql的cast函数
    查看>>
    MySql的CRUD(增、删、改、查)操作
    查看>>
    MySQL的DATE_FORMAT()函数将Date转为字符串
    查看>>