If you do not want to go through the hassle implementing OwnerDraw list
controls, where you got to code a bunch of stuff inside the DrawItem override, then
you can use the CustomDraw handler. With version 4.70 of the Comctrl.dll, you can
handle row data, but with the 4.72+ version of the Dll, you can handle cell data.
Which opens a lot of possibilities.
Here I present some examples on how to use the CustomDraw message.
Note: Similar handling is also possible for the other common controls.
Add the following to your CListCtrl derived class header file:
afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); // add the following to your message map in the cpp file. ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw) // add the following function to the cpp file. // for specialized row handling. // modify to suit. (in this sample function, I color every alternate row). void CListCtrlEx::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { //for this notification, the structure is actually a // NMLVCUSTOMDRAW that tells you what's going on with the custom // draw action. So, we'll need to cast the generic pNMHDR pointer. LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR; switch(lplvcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: *pResult = CDRF_NOTIFYITEMDRAW; // ask for item notifications. break; case CDDS_ITEMPREPAINT: *pResult = CDRF_DODEFAULT; int iRow = lplvcd->nmcd.dwItemSpec; if(iRow & 1) { lplvcd->clrTextBk = RGB(255, 0, 0); lplvcd->clrText = RGB(255, 255, 0); *pResult = CDRF_NEWFONT; } break; default: *pResult = CDRF_DODEFAULT; } } // add the following function to the cpp file. // for specialized cell handling. // modify to suit. (in this sample function, I color every alternate cell). void CListCtrlEx::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { //for this notification, the structure is actually a // NMLVCUSTOMDRAW that tells you what's going on with the custom // draw action. So, we'll need to cast the generic pNMHDR pointer. LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR; switch(lplvcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; // ask for subitem notifications. break; case CDDS_ITEMPREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; // ask for subitem notifications. break; case CDDS_ITEMPREPAINT|CDDS_SUBITEM: // recd when CDRF_NOTIFYSUBITEMDRAW is returned in { // response to CDDS_ITEMPREPAINT. *pResult = CDRF_DODEFAULT; int iCol = lplvcd->iSubItem; int iRow = lplvcd->nmcd.dwItemSpec; if((iRow & 1) && (iCol & 1)) { lplvcd->clrTextBk = RGB(255, 0, 0); lplvcd->clrText = RGB(255, 255, 0); *pResult = CDRF_NEWFONT; } break; } default:// it wasn't a notification that was interesting to us. *pResult = CDRF_DODEFAULT; } } // add the following function to the cpp file. // for specialized cell handling. // modify to suit. // (in this sample function, I color every alternate cell, // if the checkbox style is not present, otherwise, I color all checked rows). void CListCtrlEx::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { //for this notification, the structure is actually a // NMLVCUSTOMDRAW that tells you what's going on with the custom // draw action. So, we'll need to cast the generic pNMHDR pointer. LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR; switch(lplvcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; // ask for subitem notifications. break; case CDDS_ITEMPREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; // ask for subitem notifications. if(GetExtendedStyle() & LVS_EX_CHECKBOXES) // if we have a checkbox style, { // forget about subitem notifications. *pResult = CDRF_DODEFAULT; int iRow = lplvcd->nmcd.dwItemSpec; if(GetCheck(iRow)) // highlight checked rows { lplvcd->clrTextBk = RGB(255, 0, 0); lplvcd->clrText = RGB(255, 255, 0); *pResult = CDRF_NEWFONT; } } break; case CDDS_ITEMPREPAINT|CDDS_SUBITEM: // recd when CDRF_NOTIFYSUBITEMDRAW is returned in { // response to CDDS_ITEMPREPAINT. *pResult = CDRF_DODEFAULT; int iCol = lplvcd->iSubItem; int iRow = lplvcd->nmcd.dwItemSpec; if((iRow & 1) && (iCol & 1)) { lplvcd->clrTextBk = RGB(255, 0, 0); lplvcd->clrText = RGB(255, 255, 0); *pResult = CDRF_NEWFONT; } break; } default:// it wasn't a notification that was interesting to us. *pResult = CDRF_DODEFAULT; } } // add the following function to the cpp file. // for specialized cell handling. // modify to suit. // (in this sample function, I display the text centered). void CListCtrlEx::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) { //for this notification, the structure is actually a // NMLVCUSTOMDRAW that tells you what's going on with the custom // draw action. So, we'll need to cast the generic pNMHDR pointer. LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR; switch(lplvcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; // ask for subitem notifications. break; case CDDS_ITEMPREPAINT: *pResult = CDRF_NOTIFYSUBITEMDRAW; break; case CDDS_ITEMPREPAINT|CDDS_SUBITEM: { int iCol = lplvcd->iSubItem; int iRow = lplvcd->nmcd.dwItemSpec; CString sItem = GetItemText(iRow, iCol); CRect rc; GetCellRect(iRow, iCol, LVIR_BOUNDS, rc); // get the device context. CDC *pDC= CDC::FromHandle(lplvcd->nmcd.hdc); // paint the text centered. pDC->DrawText(sItem , rc, DT_CENTER); *pResult= CDRF_SKIPDEFAULT; break; } default:// it wasn't a notification that was interesting to us. *pResult = CDRF_DODEFAULT; } }
Where GetCellRect is defined as follows:
BOOL CListCtrlEx::GetCellRect(int iRow, int iCol, int nArea, CRect &rect) { if(iCol) return GetSubItemRect(iRow, iCol, nArea, rect); if(GetColumnCount()== 1) return GetItemRect(iRow, rect, nArea); iCol = 1; CRect rCol1; if(!GetSubItemRect(iRow, iCol, nArea, rCol1)) return FALSE; if(!GetItemRect(iRow, rect, nArea)) return FALSE; rect.right = rCol1.left; return TRUE; }
History