本文共 4247 字,大约阅读时间需要 14 分钟。
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 )。
自定义绘制将绘制过程分为几个阶段,具体如下:
自定义绘制的响应类型决定了 Windows 如何处理绘制请求。共有五种响应类型:
NM_CUSTOMDRAW 消息携带了一个 NMLVCUSTOMDRAW 结构体,提供了丰富的信息:
以下是几个典型的自定义绘制应用示例:
通过在项目预绘制阶段设置文本颜色,并在后续阶段通知 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; }} 通过在子项目预绘制阶段设置文本颜色和背景颜色。
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; }} 通过在项目绘制完成后重绘特定项目。
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; } }} 通过自定义绘制,可以实现多种效果,如:
以下是利用自定义绘制实现的列表控示例:
通过上述方法,开发者可以根据需求灵活配置列表控的外观,使用户体验更加丰富个性化。
转载地址:http://zfcfk.baihongyu.com/