如何根据列表控件指定列文本修改特定行颜色?MFC OnCustomDraw异常
问题分析与解决
你的代码存在两个核心问题:
- 遍历所有行判断,只要存在任意一行是"No",就将
crText设为红色,后续所有行绘制都会复用这个红色值 - 未初始化
crText,若没有行匹配"No",会使用垃圾值导致颜色异常
要实现仅目标行变色,只需针对当前正在绘制的行做判断,无需遍历整个列表:
修正后的代码
void CMyListClass::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) { // 获取当前正在绘制的行索引 int nRow = static_cast<int>(pLVCD->nmcd.dwItemSpec); const int nPassportCol = 6; // 护照信息列索引 const CString strTarget = _T("No"); // 获取当前行目标列的文本 CString szText = m_list.GetItemText(nRow, nPassportCol); // 初始化文本颜色为系统默认值 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); if (szText == strTarget) { // 目标行设置红色文本 crText = RGB(255, 0, 0); } // 应用文本颜色 pLVCD->clrText = crText; *pResult = CDRF_DODEFAULT; } }
关键说明
- 获取当前绘制行:
pLVCD->nmcd.dwItemSpec存储了当前正在处理的行索引,直接用它获取对应行的列文本即可 - 默认颜色初始化:先将文本颜色设为系统默认的窗口文本色,避免未匹配时出现异常颜色
- 精准判断:只对当前行的目标列做判断,确保只有符合条件的行才会变成红色
如果需要单独给第6列(而非整行)设置红色,可监听CDDS_SUBITEMPREPAINT阶段,判断pLVCD->iSubItem是否为6后再设置颜色:
else if (CDDS_ITEMPREPAINT | CDDS_SUBITEM == pLVCD->nmcd.dwDrawStage) { int nRow = static_cast<int>(pLVCD->nmcd.dwItemSpec); int nSubItem = pLVCD->iSubItem; const int nPassportCol = 6; const CString strTarget = _T("No"); COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); if (nSubItem == nPassportCol) { CString szText = m_list.GetItemText(nRow, nSubItem); if (szText == strTarget) { crText = RGB(255, 0, 0); } } pLVCD->clrText = crText; *pResult = CDRF_DODEFAULT; }
内容的提问来源于stack exchange,提问作者Abhishek Chavhan
相关产品推荐
相关产品推荐

