CListCtrl 封裝 Windows List View 公共控件,支持四種視圖、圖標、多列報表、標籤編輯、自定義繪製、虛擬模式等豐富功能。
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
| 風格 | 外觀 | 適用場景 |
|---|---|---|
LVS_ICON | 大圖標 (32x32),自由排列 | 文件瀏覽器大圖標視圖 |
LVS_SMALLICON | 小圖標 (16x16),自由排列 | 緊湊視圖 |
LVS_LIST | 小圖標,列排列,單列文本 | 簡單列表 |
LVS_REPORT | 多列表格,表頭可點擊排序 | 數據網格、明細表、最常用 |
LVS_EDITLABELS:允許就地編輯標籤 (報表模式僅第一列)。LVS_SHOWSELALWAYS:失去焦點仍高亮選中項。LVS_SINGLESEL:單選模式。LVS_OWNERDATA:虛擬模式 (海量數據,按需提供)。
// 大圖標模式
m_list.SetImageList(&m_imgLarge, LVSIL_NORMAL);
// 小圖標/列表/報表模式
m_list.SetImageList(&m_imgSmall, LVSIL_SMALL);
// 狀態圖像 (覆蓋圖標、勾選框)
m_list.SetImageList(&m_imgState, LVSIL_STATE);
int InsertColumn(int nCol, LPCTSTR lpszColumnHeading,
int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1);
// nFormat: LVCFMT_LEFT/RIGHT/CENTER
// nSubItem: 列索引,通常等於 nCol
int InsertItem(int nItem, LPCTSTR lpszItem); // 僅第一列文本
int InsertItem(const LVITEM* pItem); // 完整控制
BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText);
// 初始化
m_list.InsertColumn(0, _T("姓名"), LVCFMT_LEFT, 120, 0);
m_list.InsertColumn(1, _T("年齡"), LVCFMT_CENTER, 60, 1);
m_list.InsertColumn(2, _T("城市"), LVCFMT_LEFT, 150, 2);
// 添加數據
int n = m_list.InsertItem(0, _T("張三"));
m_list.SetItemText(n, 1, _T("25"));
m_list.SetItemText(n, 2, _T("北京"));
n = m_list.InsertItem(1, _T("李四"));
m_list.SetItemText(n, 1, _T("30"));
m_list.SetItemText(n, 2, _T("上海"));
| 功能 | 獲取 | 設置 |
|---|---|---|
| 文本顏色 | GetTextColor() | SetTextColor(COLORREF) |
| 背景顏色 | GetTextBkColor() | SetTextBkColor(COLORREF) |
| 項數 | GetItemCount() | - |
| 刪除項 | - | DeleteItem(nItem) / DeleteAllItems() |
| 背景圖片 | - | SetBkImage(HBITMAP, BOOL fTile, ...) |
| 獲取文本 | GetItemText(nItem, nSubItem) | - |
ON_NOTIFY 機制列表控件通過 WM_NOTIFY 發送通知,父窗口用 ON_NOTIFY 映射:
ON_NOTIFY(LVN_ITEMCHANGED, IDC_MYLIST, OnItemChanged)
ON_NOTIFY(LVN_COLUMNCLICK, IDC_MYLIST, OnColumnClick)
// 處理函數原型
void OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult);
| 通知碼 | 觸發時機 | 結構 | 關鍵字段 |
|---|---|---|---|
LVN_ITEMCHANGED | 項狀態改變 (選中/焦點) | NMLISTVIEW | iItem, iSubItem, uChanged, uNewState |
LVN_COLUMNCLICK | 點擊列標題 | NMLISTVIEW | iSubItem (列索引) |
LVN_BEGINLABELEDIT | 開始編輯標籤 | NMLVDISPINFO | item.pszText (可修改取消) |
LVN_ENDLABELEDIT | 結束編輯 | NMLVDISPINFO | item.pszText (新文本,NULL=取消) |
LVN_GETDISPINFO | 虛擬模式/回調文本請求 | NMLVDISPINFO | item.iItem, iSubItem, pszText |
NM_CLICK / NM_DBLCLK | 單擊/雙擊 | NMITEMACTIVATE | iItem, iSubItem |
void CMyDlg::OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult) {
LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR);
if (pNMLV->uChanged & LVIF_STATE) {
if (pNMLV->uNewState & LVIS_SELECTED) {
// 項被選中
CString text = m_list.GetItemText(pNMLV->iItem, 0);
}
}
*pResult = 0;
}
LVS_OWNERDATA + LPSTR_TEXTCALLBACK)適用於海量數據 (萬級以上),不存儲文本,按需提供。
// 1. 創建時指定 LVS_OWNERDATA
// 2. 插入項時文本指針設為 LPSTR_TEXTCALLBACK
m_list.InsertItem(LVIF_TEXT | LVIF_PARAM, 0, LPSTR_TEXTCALLBACK, 0, 0, 0, 0);
// 3. 處理 LVN_GETDISPINFO
void CMyDlg::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = reinterpret_cast(pNMHDR);
LVITEM& item = pDispInfo->item;
if (item.mask & LVIF_TEXT) {
// 根據 item.iItem, item.iSubItem 提供文本
static CString data[100][3]; // 假設數據源
item.pszText = data[item.iItem][item.iSubItem].GetBuffer();
}
*pResult = 0;
}
LVS_EDITLABELS)
// 1. 創建風格包含 LVS_EDITLABELS
// 2. 處理 LVN_BEGINLABELEDIT:返回 TRUE 取消編輯,FALSE 允許
void CMyDlg::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = (NMLVDISPINFO*)pNMHDR;
if (pDispInfo->item.iItem == 0) // 禁止編輯第一行
*pResult = 1; // TRUE = 取消
else
*pResult = 0; // FALSE = 允許
}
// 3. 處理 LVN_ENDLABELEDIT:獲取新文本並更新
void CMyDlg::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = (NMLVDISPINFO*)pNMHDR;
if (pDispInfo->item.pszText != NULL) {
m_list.SetItemText(pDispInfo->item.iItem, 0, pDispInfo->item.pszText);
}
*pResult = 0;
}
InsertItem → 顯示異常/崩潰。SetItemText 索引越界 → 靜默失敗/崩潰。LVN_GETDISPINFO → 空白/崩潰。pszText == NULL (用戶取消) → 空指針。InsertItem → 卡頓。用 SetItemCountEx + 虛擬模式或 LockWindowUpdate 批量插入。CListCtrl 是 MFC 數據展示的核心控件。掌握四種視圖風格選擇、報表模式列/項構建、圖像列表綁定、ON_NOTIFY 消息映射、虛擬模式回調文本、標籤編輯流程,能構建從簡單列表到複雜數據網格的各類界面。虛擬模式 (LVS_OWNERDATA) 是海量數據的唯一正解。