列表控件是功能增強版 ListBox,提供四種顯示風格並支持多屬性列顯示。MFC 通過 CListCtrl 封裝所有操作,本文系統講解創建、風格選擇、圖標列表綁定、報表模式多列數據填充、狀態屬性控制、消息映射及動態文本回調機制。
BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
| 風格 | 顯示模式 | 適用場景 |
|---|---|---|
LVS_ICON | 大圖標 | 文件管理器大圖標視圖 |
LVS_SMALLICON | 小圖標 | 緊湊列表 |
LVS_LIST | 列表 | 單列多行,自動換行 |
LVS_REPORT | 詳細報表 | 多列表格,最常用 |
LVS_EDITLABELS:標籤可編輯(報表模式僅第一列)LVS_SHOWSELALWAYS:失去焦點仍顯示選中項LVS_SINGLESEL:單選模式// 大圖標模式
m_list.SetImageList(&m_imageListLarge, LVSIL_NORMAL);
// 小圖標/列表/報表模式
m_list.SetImageList(&m_imageListSmall, LVSIL_SMALL);
// 狀態圖標(覆蓋圖標、勾選框等)
m_list.SetImageList(&m_imageListState, LVSIL_STATE);
int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat, int nWidth, int nSubItem);
nFormat:LVCFMT_LEFT/CENTER/RIGHTnSubItem:列索引,通常與 nCol 一致// 插入第一列(行標識)
int nItem = m_list.InsertItem(0, _T("Item 1_1"));
// 設置後續列文本
m_list.SetItemText(nItem, 1, _T("Item 1_2")); // 第2列
m_list.SetItemText(nItem, 2, _T("Item 1_3")); // 第3列
// 綁定小圖標列表
m_list.SetImageList(&m_listSmall, LVSIL_SMALL);
// 插入三列
m_list.InsertColumn(0, _T("Col 1"), LVCFMT_LEFT, 300, 0);
m_list.InsertColumn(1, _T("Col 2"), LVCFMT_LEFT, 300, 1);
m_list.InsertColumn(2, _T("Col 3"), LVCFMT_LEFT, 300, 2);
// 插入數據行
m_list.InsertItem(0, _T("Item 1_1"));
m_list.SetItemText(0, 1, _T("Item 1_2"));
m_list.SetItemText(0, 2, _T("Item 1_3"));
| 功能 | 獲取 | 設置 |
|---|---|---|
| 文本顏色 | GetTextColor() | SetTextColor(COLORREF) |
| 背景顏色 | GetTextBkColor() | SetTextBkColor(COLORREF) |
| 項數量 | GetItemCount() | - |
| 刪除項 | - | DeleteItem(int) / DeleteAllItems() |
| 背景圖片 | - | SetBkImage(HBITMAP, BOOL, int, int) |
| 獲取單元格文本 | GetItemText(int, int) | - |
使用 ON_NOTIFY 宏,處理函數原型:
void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult);
| 通知代碼 | 觸發時機 | 結構類型 |
|---|---|---|
LVN_BEGINLABELEDIT | 開始編輯標籤 | NMLVDISPINFO |
LVN_ENDLABELEDIT | 結束編輯標籤 | NMLVDISPINFO |
LVN_GETDISPINFO | 需要顯示信息(動態回調) | NMLVDISPINFO |
LVN_ITEMCHANGED | 項狀態改變(選中、勾選) | NMLISTVIEW |
NM_CLICK/NM_DBLCLK | 單擊/雙擊 | NMITEMACTIVATE |
LVN_COLUMNCLICK | 點擊列標題(排序) | NMLISTVIEW |
void CMyDialog::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = (NMLVDISPINFO*)pNMHDR;
LV_ITEM& item = pDispInfo->item;
if (item.mask & LVIF_TEXT) {
// 根據 item.iItem (行) 和 item.iSubItem (列) 提供文本
static char szData[100][3][20] = { ... }; // 數據源
item.pszText = szData[item.iItem][item.iSubItem];
}
*pResult = 0;
}
LPSTR_TEXTCALLBACK 作為文本指針LVN_GETDISPINFO 請求文本iItem/iSubItem 填充 item.pszText// 1. 插入項(不提供實際文本)
m_list.InsertItem(LVIF_TEXT | LVIF_PARAM, 0, LPSTR_TEXTCALLBACK, 0, 0, 0, 0);
m_list.InsertItem(LVIF_TEXT | LVIF_PARAM, 1, LPSTR_TEXTCALLBACK, 0, 0, 0, 1);
// 2. 消息映射
ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST_CTRL, OnGetDispInfoList)
// 3. 處理函數
void CMyDialog::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = (NMLVDISPINFO*)pNMHDR;
static const char* cols[][3] = {
{"Row1-Col1", "Row1-Col2", "Row1-Col3"},
{"Row2-Col1", "Row2-Col2", "Row2-Col3"}
};
if (pDispInfo->item.mask & LVIF_TEXT) {
int row = pDispInfo->item.iItem;
int col = pDispInfo->item.iSubItem;
if (row < 2 && col < 3) {
pDispInfo->item.pszText = (LPSTR)cols[row][col];
}
}
*pResult = 0;
}
SetItemState(i, LVIS_SELECTED, LVIS_SELECTED)SortItems(PFNLVCOMPARE, LPARAM) 實現自定義比較函數LVS_OWNERDRAWFIXED + NM_CUSTOMDRAW 實現漸變行、條件高亮LVS_OWNERDATA 配合 LVN_GETDISPINFO 處理百萬級數據SetExtendedStyle(LVS_EX_CHECKBOXES) 自動在第一列顯示勾選框本文整理自 MFC 經典技術文檔,適用於 VC6~VS2022 所有版本。