組合框融合編輯框與列表框雙重功能,是數據輸入與選擇的常用控件。MFC CComboBox 封裝了風格創建、字符串管理、選擇控制、查找匹配、剪貼板操作及完整消息映射。本文系統講解三種核心風格差異、雙重功能調用、編輯框限制與常用消息處理。
一、 創建與三大核心風格
BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff);
風格對比(三選一)
| 風格 | 顯示形式 | 編輯框可輸入 | 典型用途 |
CBS_DROPDOWN | 下拉式,平時只顯示編輯框 | 是 | 用戶可輸入或選擇 |
CBS_DROPDOWNLIST | 下拉式,平時只顯示編輯框 | 否(只讀) | 強制從列表選擇 |
CBS_SIMPLE | 編輯框+列表框始終顯示 | 是 | 固定顯示所有選項 |
輔助風格
LBS_SORT:列表項按字母自動排序
WS_VSCROLL:列表過長時顯示垂直滾動條
CBS_OWNERDRAWFIXED/VARIABLE:自繪模式
二、 列表框功能(繼承自 CListBox)
| 操作 | 函數 | 說明 |
| 添加項 | AddString(LPCTSTR) | 返回索引,LBS_SORT 時自動排序 |
| 插入項 | InsertString(int, LPCTSTR) | 指定位置插入 |
| 刪除項 | DeleteString(UINT) | 按索引刪除 |
| 清空 | ResetContent() | 刪除所有項 |
| 項數 | GetCount() | 返回項總數 |
| 獲取文本 | GetLBText(int, LPTSTR) | 複製指定項文本 |
| 查找字符串 | FindString(int nStartAfter, LPCTSTR) | 從指定項後查找,返回索引 |
| 選中匹配項 | SelectString(int nStartAfter, LPCTSTR) | 查找並選中首個匹配項 |
三、 選擇狀態控制
| 操作 | 函數 |
| 獲取當前選中索引 | GetCurSel() (無選中返回 CB_ERR) |
| 設置選中索引 | SetCurSel(int) |
| 獲取編輯框文本 | GetWindowText(CString&) 或 GetLBText(GetCurSel(), ...) |
四、 編輯框功能(內嵌 CEdit 功能)
| 功能 | 函數 |
| 獲取/設置選中文本範圍 | GetEditSel() / SetEditSel(int nStart, int nEnd) |
| 限制最大輸入字符數 | LimitText(int nMaxChars) |
| 剪貼板操作 | Copy(), Cut(), Paste(), Clear() |
| 撤銷 | Undo() |
五、 常用消息映射宏
對話框中 ClassWizard 自動生成,手動映射格式:
ON_CBN_XXX(IDC_COMBO, OnXxxCombo)
// 處理函數原型:afx_msg void OnXxxCombo();
| 宏 | 觸發條件 | 典型用途 |
ON_CBN_SELCHANGE | 列表選擇改變 | 聯動更新其他控件、載入數據 |
ON_CBN_DBLCLK | 雙擊列表項 | 確認選擇、打開詳情 |
ON_CBN_DROPDOWN | 列表彈出 | 動態填充列表、刷新數據 |
ON_CBN_CLOSEUP | 列表關閉 | 驗證選擇、保存狀態 |
ON_CBN_EDITUPDATE | 編輯框文本更新 | 實時過濾、自動完成 |
ON_CBN_EDITCHANGE | 編輯框文本改變(含程序設置) | 同步數據模型 |
ON_CBN_SETFOCUS/KILLFOCUS | 編輯框獲得/失去焦點 | 輸入法控制、驗證提示 |
ON_CBN_SELENDOK | 用戶確認選擇(關閉列表) | 最終提交數據 |
ON_CBN_SELENDCANCEL | 用戶取消選擇(關閉列表) | 恢復原選擇 |
六、 實戰代碼模板
1. 初始化填充
void CMyDialog::InitCombo() {
m_combo.ResetContent();
m_combo.AddString(_T("選項一"));
m_combo.AddString(_T("選項二"));
m_combo.AddString(_T("選項三"));
m_combo.SetCurSel(0); // 默認選中第一項
m_combo.LimitText(50); // 限制輸入長度
}
2. 選擇改變響應
void CMyDialog::OnCbnSelchangeCombo() {
int idx = m_combo.GetCurSel();
if (idx != CB_ERR) {
CString text;
m_combo.GetLBText(idx, text);
// 聯動邏輯...
TRACE(_T("選中: %s (索引%d)\n"), text, idx);
}
}
3. 動態過濾(編輯更新時)
void CMyDialog::OnCbnEditupdateCombo() {
CString input;
m_combo.GetWindowText(input);
// 保存當前光標位置
DWORD sel = m_combo.GetEditSel();
// 重新填充匹配項
m_combo.ResetContent();
for (auto& item : allItems) {
if (item.Find(input) >= 0) m_combo.AddString(item);
}
// 恢復光標並重新展開
m_combo.SetEditSel(LOWORD(sel), HIWORD(sel));
m_combo.ShowDropDown();
}
4. 獲取用戶最終輸入(含手動輸入)
CString GetComboValue() {
CString text;
m_combo.GetWindowText(text); // 兼容 CBS_DROPDOWN 手動輸入
return text;
}
七、 避坑指南
- CBS_DROPDOWNLIST 無法獲取編輯框文本:該風格編輯框只讀,
GetWindowText 返回空,必須用 GetLBText(GetCurSel())
FindString 不區分大小寫,且匹配前綴(從開頭匹配)
- 動態添加項後索引變化:若啟用
LBS_SORT,新項會自動排序,原索引失效
- 編輯框文本變更不觸發 SELCHANGE:手動輸入需監聽
EDITUPDATE 或 EDITCHANGE
- 大數據量性能:超過千項建議使用虛擬列表或按需加載(
CBN_DROPDOWN 時填充)
本文整理自 MFC 經典技術文檔,適用於 VC6~VS2022 所有版本。