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

MFC 列表控件 CListCtrl 完整開發指南:四種視圖模式、圖標綁定、多列報表與動態回調

     編輯:關於C語言

列表控件是功能增強版 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);

三、 報表模式完整構建流程

1. 插入列(必須先於插入行)

int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat, int nWidth, int nSubItem);
  • nFormat:LVCFMT_LEFT/CENTER/RIGHT
  • nSubItem:列索引,通常與 nCol 一致

2. 插入行與設置單元格文本

// 插入第一列(行標識)
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;
}

六、 動態文本回調機制(大數據/虛擬列表核心)

原理

  1. 插入項時指定 LPSTR_TEXTCALLBACK 作為文本指針
  2. 控件繪製時發送 LVN_GETDISPINFO 請求文本
  3. 處理函數中根據 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 所有版本。

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