大家也許熟悉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消息繪制出的多色列表框的例子:
對應代碼如下:
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。
總體步驟:
- 派生CCoolList類
- 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() - 定義CListCtrl Control m_list變量,再將CListCtrl 改為CCoolList