Custom Draw items inside a ListView Control

来源:互联网 发布:淘宝网页版电脑版卖家 编辑:程序博客网 时间:2024/06/13 22:50

Custom   Draw   items   inside   a   ListView   Control   

-------------------------------------------------------------------------------- 

This   article   was   contributed   by   Navi   Singh. 

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;