大家也許熟悉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 目前繪制狀态,其取值如表7所示:
類型值 含義
CDDS_POSTERASE 擦除循環結束
CDDS_POSTPAINT 繪制循環結束
CDDS_PREERASE 準備開始擦除循環
CDDS_PREPAINT 準備開始繪制循環
CDDS_ITEM 指定dwItemSpec, uItemState, lItemlParam參數有效
CDDS_ITEMPOSTERASE 清單項擦除結束
CDDS_ITEMPOSTPAINT 清單項繪制結束
CDDS_ITEMPREERASE 準備開始清單項擦除
CDDS_ITEMPREPAINT 準備開始清單項繪制
CDDS_SUBITEM 指定清單子項
表7 dwDrawStage的類型值與含義
hdc指定了繪制操作所使用的裝置環境。
rc指定了将被繪制的矩形區域。
dwItemSpec 清單項的索引
uItemState 目前清單項的狀态,其取值如表8所示:
類型值 含義
CDIS_CHECKED 标記狀态。
CDIS_DEFAULT 預設狀态。
CDIS_DISABLED 禁止狀态。
CDIS_FOCUS 焦點狀态。
CDIS_GRAYED 灰化狀态。
CDIS_SELECTED 選中狀态。
CDIS_HOTLIGHT 熱點狀态。
CDIS_INDETERMINATE 不定狀态。
CDIS_MARKED 标注狀态。
表8 uItemState的類型值與含義
lItemlParam 目前清單項的綁定資料
pResult 指向狀态值的指針,指定系統後續操作,依賴于dwDrawStage:
當dwDrawStage為CDDS_PREPAINT,pResult含義如表9所示:
類型值 含義
CDRF_DODEFAULT 預設操作,即系統在清單項繪制循環過程不再發送NM_CUSTOMDRAW。
CDRF_NOTIFYITEMDRAW 指定清單項繪制前後發送消息。
CDRF_NOTIFYPOSTERASE 清單項擦除結束時發送消息。
CDRF_NOTIFYPOSTPAINT 清單項繪制結束時發送消息。
表9 pResult的類型值與含義(一)
當dwDrawStage為CDDS_ITEMPREPAINT,pResult含義如表10所示:
類型值 含義
CDRF_NEWFONT 指定後續操作采用應用中指定的新字型。
CDRF_NOTIFYSUBITEMDRAW 清單子項繪制時發送消息。
CDRF_SKIPDEFAULT 系統不必再繪制該子項。
表10 pResult的類型值與含義(二)
以下是一個利用NM_CUSTOMDRAW消息繪制出的多色清單框的例子:
圖12 利用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