列表框是單列文本展示的基礎控件,支持單選、多選、排序。MFC CListBox 封裝完整操作,CCheckListBox (MFC 4.2+) 在此基礎上添加每行複選框功能。本文系統講解創建風格、項管理、選擇處理、查找匹配、複選框狀態控制及消息映射。
一、 CListBox 創建與風格
BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff);
選擇模式風格(互斥或組合)
| 風格 | 選擇行為 | 獲取選中方式 |
| (無特殊風格) | 單選 | GetCurSel()/SetCurSel() |
LBS_MULTIPLESEL | 點擊即切換選中狀態 | GetSelCount() + GetSelItems() |
LBS_EXTENDEDSEL | Shift/Ctrl + 點擊 範圍/離散選擇 | GetSelCount() + GetSelItems() |
輔助風格
LBS_SORT:自動按字母排序
LBS_HASSTRINGS:項包含字符串(默認)
LBS_OWNERDRAWFIXED/VARIABLE:自繪模式
LBS_NOINTEGRALHEIGHT:不調整高度適應整行
WS_VSCROLL/WS_HSCROLL:滾動條
二、 項管理核心函數
| 操作 | 函數 | 返回值 |
| 添加項(末尾) | AddString(LPCTSTR) | 索引 (0-based) |
| 插入項(指定位置) | InsertString(int, LPCTSTR) | 索引 |
| 刪除項 | DeleteString(UINT) | 剩餘項數 |
| 清空所有 | ResetContent() | 無 |
| 獲取項數 | GetCount() | 項總數 |
| 獲取項文本 | GetLBText(int, LPTSTR) / GetText(int, CString&) | 字符長度 |
| 查找字符串 | FindString(int nStartAfter, LPCTSTR) | 索引 (CB_ERR=未找到) |
| 選中匹配項 | SelectString(int nStartAfter, LPCTSTR) | 索引 |
三、 選擇狀態處理
單選模式
int idx = list.GetCurSel(); // 獲取
list.SetCurSel(idx); // 設置
多選模式 (LBS_MULTIPLESEL / LBS_EXTENDEDSEL)
// 1. 獲取選中項數
int count = list.GetSelCount();
// 2. 分配數組接收索引
int* indices = new int[count];
list.GetSelItems(count, indices);
// 3. 遍歷處理
for (int i = 0; i < count; ++i) {
CString text;
list.GetText(indices[i], text);
// 處理選中項...
}
delete[] indices;
設置多選狀態
list.SetSel(index, TRUE); // 選中
list.SetSel(index, FALSE); // 取消選中
list.SelItemRange(TRUE, 0, 9); // 批量選中 0-9
四、 CCheckListBox 檢查列表框
繼承自 CListBox,擁有所有基類功能,額外提供每行複選框
創建關鍵要求
// 必須指定自繪風格之一
dwStyle |= LBS_OWNERDRAWFIXED; // 或 LBS_OWNERDRAWVARIABLE
m_checkList.Create(dwStyle, rect, pParent, nID);
複選框樣式控制
// 設置/獲取複選框樣式 (參考 Button 控件 BS_* 風格)
void SetCheckStyle(UINT nStyle);
UINT GetCheckStyle();
複選狀態核心操作
| 操作 | 函數 | 狀態值 |
| 設置檢查狀態 | SetCheck(int nIndex, int nCheck) | 0=未選, 1=選中, 2=不確定(三態) |
| 獲取檢查狀態 | GetCheck(int nIndex) | 同上 |
| 批量設置 | 循環調用 SetCheck | - |
三態複選框邏輯
BS_AUTO3STATE / BS_3STATE:支持 0/1/2 三態
- 狀態 2(不確定/灰色)通常表示「部分選中」或「禁用」
- 父子節點關聯時:父節點狀態 = 子節點全選(1)/全不選(0)/混合(2)
五、 常用消息映射
ON_LBN_XXX(IDC_LIST, OnXxxList)
// 處理函數:afx_msg void OnXxxList();
| 宏 | 觸發條件 |
ON_LBN_SELCHANGE | 選擇項改變(單選/多選) |
ON_LBN_DBLCLK | 雙擊項 |
ON_LBN_SELCANCEL | 取消選擇(再次點擊已選項,僅多選模式) |
ON_LBN_SETFOCUS/KILLFOCUS | 獲得/失去焦點 |
ON_LBN_ERRSPACE | 內存分配失敗 |
六、 實戰代碼模板
1. 初始化檢查列表框
void CMyDialog::InitCheckList() {
// 風格必須包含 LBS_OWNERDRAWFIXED
DWORD style = WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS;
m_checkList.Create(style, rect, this, IDC_CHECKLIST);
// 添加項
m_checkList.AddString(_T("選項一"));
m_checkList.AddString(_T("選項二"));
m_checkList.AddString(_T("選項三"));
// 設置默認勾選
m_checkList.SetCheck(0, 1); // 選中第一項
m_checkList.SetCheck(2, 2); // 第三項不確定狀態
// 設置複選框樣式 (可選)
m_checkList.SetCheckStyle(BS_AUTOCHECKBOX | BS_LEFTTEXT); // 文字在左
}
2. 獲取所有勾選項
void CMyDialog::OnGetChecked() {
CString result;
for (int i = 0; i < m_checkList.GetCount(); ++i) {
if (m_checkList.GetCheck(i)) { // 1或2視為勾選
CString text;
m_checkList.GetText(i, text);
result += text + _T("; ");
}
}
AfxMessageBox(_T("已勾選: ") + result);
}
3. 父子聯動邏輯(樹形結構扁平化)
void CMyDialog::OnSelchangeChecklist() {
// 簡單示例:項0為父,項1-3為子
int parentCheck = m_checkList.GetCheck(0);
if (parentCheck == 1) { // 父選中 → 全選子
for (int i = 1; i < 4; ++i) m_checkList.SetCheck(i, 1);
} else if (parentCheck == 0) { // 父未選 → 全不選子
for (int i = 1; i < 4; ++i) m_checkList.SetCheck(i, 0);
}
// 父為不確定態(2)時保持子項現狀
}
七、 避坑指南
- 忘記 LBS_OWNERDRAWFIXED:
CCheckListBox 不顯示複選框、SetCheck 無效
- 多選模式下 GetCurSel 失效:必須用
GetSelCount + GetSelItems
FindString 前綴匹配不區分大小寫:需精確匹配請自行遍歷比較
- 大量項操作閃爍:用
SetRedraw(FALSE) 批量操作後 SetRedraw(TRUE) + Invalidate()
- 三態邏輯混淆:明確業務含義:0=無、1=有、2=部分/不確定,UI與數據模型同步
本文整理自 MFC 經典技術文檔,適用於 VC6~VS2022 所有版本。