首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MFC CListCtrl 完全指南:四種視圖模式、報表模式列操作、自繪與編輯、消息處理實戰

     編輯:關於C語言

CListCtrl:功能增強的列表控件

CListCtrl 封裝 Windows List View 公共控件,支持四種視圖、圖標、多列報表、標籤編輯、自定義繪製、虛擬模式等豐富功能。

一、創建與視圖風格

1. 創建控件


BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);

2. 四大互斥視圖風格 (二選一)

風格外觀適用場景
LVS_ICON大圖標 (32x32),自由排列文件瀏覽器大圖標視圖
LVS_SMALLICON小圖標 (16x16),自由排列緊湊視圖
LVS_LIST小圖標,列排列,單列文本簡單列表
LVS_REPORT多列表格,表頭可點擊排序數據網格、明細表、最常用

3. 輔助風格 (可組合)

  • 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);

三、報表模式核心:列與項操作

1. 插入列


int InsertColumn(int nCol, LPCTSTR lpszColumnHeading,
                 int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1);
// nFormat: LVCFMT_LEFT/RIGHT/CENTER
// nSubItem: 列索引,通常等於 nCol

2. 插入項 (行)


int InsertItem(int nItem, LPCTSTR lpszItem); // 僅第一列文本
int InsertItem(const LVITEM* pItem);         // 完整控制

3. 設置子項文本 (多列關鍵)


BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText);

4. 完整示例:構建三列表格


// 初始化
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項狀態改變 (選中/焦點)NMLISTVIEWiItem, iSubItem, uChanged, uNewState
LVN_COLUMNCLICK點擊列標題NMLISTVIEWiSubItem (列索引)
LVN_BEGINLABELEDIT開始編輯標籤NMLVDISPINFOitem.pszText (可修改取消)
LVN_ENDLABELEDIT結束編輯NMLVDISPINFOitem.pszText (新文本,NULL=取消)
LVN_GETDISPINFO虛擬模式/回調文本請求NMLVDISPINFOitem.iItem, iSubItem, pszText
NM_CLICK / NM_DBLCLK單擊/雙擊NMITEMACTIVATEiItem, 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) 是海量數據的唯一正解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved