改变ListCtrl某行的背景色或者字体颜色

时间:2022-07-29 14:50:06

大家也许熟悉WM_NOTIFY,控件通过WM_NOTIFY向父窗口发送消息。在WM_NOTIFY消息体中,部分控件会发送NM_CUSTOMDRAW告诉父窗口自己需要绘图。

也可以反射NM_CUSTOMDRAW消息,如:

ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)         //需要自己加进去
afx_msg void OnCustomDraw(NMHDR *pNMHDR, LRESULT *pResult);

参数:

pNMHDR 说到底只是一个指针,大多数情况下它指向一个NMHDR结构对象,NMHDR结构如下:

typedef struct tagNMHDR   
{    
    HWND hwndFrom;    
    UINT idFrom;    
    UINT code;    
} NMHDR; 

其中:

hwndFrom 发送方控件的窗口句柄

idFrom 发送方控件的ID

code 通知代码

对于某些控件来说,pNMHDR则会解释成其它内容更丰富的结构对象的指针,如:对于列表控件来说,pNMHDR常常指向一个NMCUSTOMDRAW对象,NMCUSTOMDRAW结构如下:

typedef struct tagNMCUSTOMDRAWINFO   
{   
    NMHDR  hdr;   
    DWORD  dwDrawStage;   
    HDC    hdc;   
    RECT   rc;   
    DWORD  dwItemSpec;   
    UINT   uItemState;   
    LPARAM lItemlParam;   
} NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;

其中:

hdr NMHDR对象

dwDrawStage 当前绘制状态,其取值如下:

 

CDDS_POSTERASE 擦除循环结束
CDDS_POSTPAINT  绘制循环结束
CDDS_PREERASE  准备开始擦除循环
CDDS_PREPAINT 准备开始绘制循环
CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam参数有效
CDDS_ITEMPOSTERASE 列表项擦除结束
CDDS_ITEMPOSTPAINT  列表项绘制结束
CDDS_ITEMPREERASE 准备开始列表项擦除
CDDS_ITEMPREPAINT 准备开始列表项绘制
CDDS_SUBITEM 指定列表子项

 

 

 

 

 

 

 

hdc指定了绘制操作所使用的设备环境。

rc指定了将被绘制的矩形区域。

dwItemSpec 列表项的索引

uItemState 当前列表项的状态,其取值如下:

CDIS_CHECKED 标记状态
CDIS_DEFAULT 默认状态
CDIS_DISABLED 禁止状态
CDIS_FOCUS 焦点状态
CDIS_GRAYED 灰化状态
CDIS_SELECTED 选中状态
CDIS_HOTLIGHT 热点状态
CDIS_INDETERMINATE 不定状态
CDIS_MARKED标注状态  

 

 

 

 

 

 

 

 

 

lItemlParam 当前列表项的绑定数据

pResult 指向状态值的指针,指定系统后续操作,依赖于dwDrawStage:

当dwDrawStage为CDDS_PREPAINT,pResult含义如下:

CDRF_DODEFAULT 默认操作,即系统在列表项绘制循环过程不再发送NM_CUSTOMDRAW
CDRF_NOTIFYITEMDRAW  指定列表项绘制前后发送消息
CDRF_NOTIFYPOSTERASE 列表项擦除结束时发送消息
CDRF_NOTIFYPOSTPAINT 列表项绘制结束时发送消息

 

 

 

 

 

 

当dwDrawStage为CDDS_ITEMPREPAINT,pResult含义如下:

CDRF_NEWFONT  指定后续操作采用应用中指定的新字体
CDRF_NOTIFYSUBITEMDRAW  列表子项绘制时发送消息
CDRF_SKIPDEFAULT  系统不必再绘制该子项

 

 

 

 

以下是一个利用NM_CUSTOMDRAW消息绘制出的多色列表框的例子:

改变ListCtrl某行的背景色或者字体颜色

对应代码如下:

void CCoolList::OnCustomDraw  //从CListCtrl派生(NMHDR *pNMHDR, LRESULT *pResult)   
{   
    //类型安全转换   
    NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR); *pResult = 0; //指定列表项绘制前后发送消息 if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { *pResult = CDRF_NOTIFYITEMDRAW; } else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { //奇数行 if(pLVCD->nmcd.dwItemSpec % 2) pLVCD->clrTextBk = RGB(255, 255, 128); //偶数行 else pLVCD->clrTextBk = RGB(128, 255, 255); //继续 *pResult = CDRF_DODEFAULT; } } 
注意到上例采取了3.1所推荐的第2种实现方法,派生了一个新类CCoolList。

总体步骤:

  1. 派生CCoolList类
  2. BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
     //{{AFX_MSG_MAP(CMyListCtrl)
      // NOTE - the ClassWizard will add and remove mapping macros here.
    ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)  //自己添加
     //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
  3. 定义CListCtrl  Control m_list变量,再将CListCtrl 改为CCoolList