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

    你可能感兴趣的文章
    Nat、端口映射、内网穿透有什么区别?
    查看>>
    nat打洞原理和实现
    查看>>
    NAT技术
    查看>>
    NAT模式/路由模式/全路由模式 (转)
    查看>>
    NAT模式下虚拟机centOs和主机ping不通解决方法
    查看>>
    NAT的两种模式SNAT和DNAT,到底有啥区别?
    查看>>
    NAT的全然分析及其UDP穿透的全然解决方式
    查看>>
    NAT类型与NAT模型详解
    查看>>
    NAT网络地址转换配置实战
    查看>>
    NAT网络地址转换配置详解
    查看>>
    navbar navbar-inverse 导航条设置颜色
    查看>>
    Navicat for MySQL 命令列 执行SQL语句 历史日志
    查看>>
    Navicat for MySQL 查看BLOB字段内容
    查看>>
    Navicat for MySQL笔记1
    查看>>
    Navicat for MySQL(Ubuntu)过期解决方法
    查看>>
    Navicat Premium 12 卸载和注册表的删除
    查看>>
    Navicat 导入sql文件
    查看>>
    navicat 添加外键1215错误
    查看>>
    navicat 系列软件一点击菜单栏就闪退
    查看>>
    navicat 自动关闭_干掉Navicat!MySQL官方客户端到底行不行?
    查看>>