標準 MFC CListCtrl 報表模式下,表頭高度、行高、字體、前景/背景色皆無法直接設定。本文實作 CHeaderCtrlEx 與 CListCtrlEx 兩個繼承類別,透過 Owner Draw 機制實現完整視覺客製化。
CHeaderCtrlEx : public CHeaderCtrl // 自繪表頭
CListCtrlEx : public CListCtrl // 自繪列表項目 + 子類化表頭
class CHeaderCtrlEx : public CHeaderCtrl {
double m_HeightRatio = 1.0; // 高度倍數
// ... 字體、顏色等成員
afx_msg LRESULT OnLayout(WPARAM, LPARAM lParam) {
LRESULT lr = DefWindowProc(HDM_LAYOUT, 0, lParam);
HD_LAYOUT& hdl = *(HD_LAYOUT*)lParam;
int newHeight = (int)(hdl.pwpos->cy * m_HeightRatio);
hdl.pwpos->cy = newHeight;
hdl.prc->top = newHeight; // 通知列表控制項新表頭高度
return lr;
}
// 訊息對應
ON_MESSAGE(HDM_LAYOUT, OnLayout)
};
void CListCtrlEx::PreSubclassWindow() {
ModifyStyle(0, LVS_OWNERDRAWFIXED); // 固定高度自繪
CListCtrl::PreSubclassWindow();
CHeaderCtrl* pHeader = GetHeaderCtrl();
m_Header.SubclassWindow(pHeader->GetSafeHwnd()); // 替換為自訂表頭
}
void CListCtrlEx::MeasureItem(LPMEASUREITEMSTRUCT lpMIS) {
if (m_RowHeight > 0)
lpMIS->itemHeight = m_RowHeight;
}
ON_WM_MEASUREITEM_REFLECT()
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDIS) {
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CRect rcItem(lpDIS->rcItem);
int nItem = lpDIS->itemID;
UINT nState = lpDIS->itemState;
// 1. 取得列數與欄寬
CHeaderCtrl* pHeader = GetHeaderCtrl();
int nCols = pHeader->GetItemCount();
// 2. 計算背景色 (依優先序:單元格 > 列 > 欄 > 整體)
COLORREF bgColor = GetItemBkColor(nItem, subItem); // 查詢各層級設定
// 3. 填充背景
CBrush brush(bgColor);
pDC->FillRect(&rcItem, &brush);
// 4. 繪製每欄文字
for (int col = 0; col < nCols; col++) {
LV_COLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH;
pHeader->GetItem(col, &lvc);
CRect rcCol = rcItem;
// 計算欄位矩形...
CString text = GetItemText(nItem, col);
COLORREF textColor = GetItemTextColor(nItem, col);
pDC->SetTextColor(textColor);
pDC->SetBkMode(TRANSPARENT);
UINT fmt = (lvc.fmt & LVCFMT_JUSTIFYMASK);
pDC->DrawText(text, &rcCol, fmt | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
}
// 5. 焦點框
if (nState & ODS_FOCUS)
pDC->DrawFocusRect(&rcItem);
}
void CHeaderCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDIS) {
// 類似邏輯,支援:
// - 自訂字體 (SetHeaderFontHW)
// - 文字顏色 (SetHeaderTextColor)
// - 背景色/漸層 (SetHeaderBKColor)
// - 排序箭頭繪製
// - 圖示支援 (m_HChar 陣列儲存標題文字)
}
class CListCtrlEx : public CListCtrl {
public:
// 整體設定
void SetBkColor(COLORREF clr);
void SetTextColor(COLORREF clr);
void SetFontHW(int height, int width = 0);
void SetRowHeight(int h);
void SetHeaderHeight(double ratio); // 1.0=預設, 1.5=1.5倍
// 表頭專屬
void SetHeaderFontHW(int h, int w);
void SetHeaderTextColor(COLORREF clr);
void SetHeaderBkColor(COLORREF clr); // 或漸層參數
// 欄級別
void SetColColor(int col, COLORREF bkClr);
void SetColTextColor(int col, COLORREF txtClr);
// 列級別
void SetRowColor(int row, COLORREF bkClr);
void SetRowTextColor(int row, COLORREF txtClr);
// 單元格級別 (最高優先權)
void SetItemColor(int row, int col, COLORREF bkClr);
void SetItemTextColor(int row, int col, COLORREF txtClr);
};
// OnInitDialog 中
m_List.SetColColor(0, RGB(10,150,20)); // 第 0 欄背景綠系
m_List.SetColColor(2, RGB(30,100,90)); // 第 2 欄背景青系
m_List.SetBkColor(RGB(50,10,10)); // 整體深紅背景
m_List.SetItemColor(1, 1, RGB(100,100,10)); // 第 1 列第 1 欄特殊色
m_List.SetRowHeight(25); // 行高 25 像素
m_List.SetHeaderHeight(1.5); // 表頭 1.5 倍高
m_List.SetHeaderFontHW(16, 0); // 表頭字體 16pt
m_List.SetHeaderTextColor(RGB(255,200,100));
m_List.SetHeaderBkColor(RGB(100,255,100)); // 表頭背景
m_List.SetFontHW(15, 0); // 內容字體 15pt
m_List.SetTextColor(RGB(0,255,255)); // 內容青色文字
m_List.SetColTextColor(2, RGB(255,255,100)); // 第 2 欄黃色文字
m_List.SetItemTextColor(3, 1, RGB(255,0,0)); // 第 3 列第 1 欄紅字
DrawItem,大量資料時建議:
LVS_OWNERDATA (虛擬清單) 僅繪製可見項目WS_EX_COMPOSITED 或記憶體 DC) 減少閃爍透過繼承 CHeaderCtrl/CListCtrl 並攔截 HDM_LAYOUT/WM_MEASUREITEM/WM_DRAWITEM,配合多層級色彩/字體優先權設計,可實現企業級報表的完整視覺客製化。附帶原始碼提供完整可編譯專案。