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

MFC CCheckListBox 使用必讀:Owner-Draw 模式與樣式設定避坑指南

     編輯:關於VC++

快速上手

  1. 對話框拖入 List Box 控制項,ID 設為 IDC_LIST1
  2. 類別向導新增控制變數 m_List,類型 CListBox
  3. 手動修改標頭檔:CCheckListBox m_List;
  4. 關鍵:資源檔 (.rc) 中加入 Owner-Draw 樣式
    
    LISTBOX IDC_LIST1, 160, 133, 153, 84,
        LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT |
        NOT WS_BORDER | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE
        
    必須包含 LBS_OWNERDRAWFIXED 或 LBS_OWNERDRAWVARIABLE,否則執行時 ASSERT 失敗崩潰!

為什麼需要 Owner-Draw?

CCheckListBox 繼承自 CListBox,核心繪製邏輯在 DrawItem 中自繪核取方塊與文字。MFC 要求 Owner-Draw 模式下由應用程式負責繪製,因此資源定義必須宣告 Owner-Draw 樣式。

常見錯誤與解法

替代方案:動態修改樣式 (無需改 .rc)


void CMyDlg::DoDataExchange(CDataExchange* pDX) {
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST1, m_List);
}

BOOL CMyDlg::OnInitDialog() {
    CDialog::OnInitDialog();
    // 在子類別化後、視窗建立前修改樣式
    m_List.ModifyStyle(0, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS);
    return TRUE;
}

注意:ModifyStyle 必須在 SubclassDlgItem (由 DDX_Control 內部呼叫) 之後、視窗實際建立 (Create) 之前生效。若已建立視窗需呼叫 SetWindowLong(GWL_STYLE, ...) 並 SetWindowPos(..., SWP_FRAMECHANGED) 重繪。

完整範例:加入項目與取得勾選狀態


void CMyDlg::OnBtnAdd() {
    int idx = m_List.AddString(_T("項目 1"));
    m_List.SetCheck(idx, BST_UNCHECKED); // 0=未勾, 1=勾選, 2=不確定
}

void CMyDlg::OnBtnGet() {
    CString str;
    for (int i = 0; i < m_List.GetCount(); ++i) {
        str.Format(_T("項目 %d: %s"), i, m_List.GetCheck(i) ? _T("☑") : _T("☐"));
        AfxMessageBox(str);
    }
}

總結

  • CCheckListBox = CListBox + 自繪核取方塊
  • 必要條件:資源或執行期樣式含 LBS_OWNERDRAWFIXED 或 LBS_OWNERDRAWVARIABLE
  • 視覺設計器不支援直接拖放,需「先建 CListBox 變數 → 手動改型別」
  • 動態修改樣式用 ModifyStyle (OnInitDialog) 或 SetWindowLong (已建立視窗)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
現象原因解法
執行即崩潰,Call Stack 指向 ASSERT 檢查樣式未設定 LBS_OWNERDRAWFIXED/VARIABLE修改 .rc 檔手動加入樣式
類別向導無法直接建立 CCheckListBox 變數MFC 不支援資源編輯器拖放 CCheckListBox先建 CListBox 變數,再手動改型別
無 SetStyle 方法可動態設定CListBox 未提供 SetStyle只能在 .rc 或 PreSubclassWindow 中 ModifyStyle