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

MFC 對話框訊息映射與控件初始化實戰

     編輯:關於C語言

為什麼需要訊息映射?

對話框上的每個控件(按鈕、編輯框、樹狀控件等)在使用者操作時會發送 Windows 訊息(WM_COMMAND、WM_NOTIFY 等)。MFC 透過訊息映射將這些訊息路由至對應的成員函式,實現「事件驅動」程式設計。ClassWizard 能自動列出控件支援的訊息並產生樣板碼,大幅降低手寫映射表的錯誤率。

範例對話框佈局與控件清單

範例對話框佈局

控件 ID類型說明
IDC_RADIO_TEST_1Radio Button單選按鈕群組首項(需設 Group 屬性)
IDC_RADIO_TEST_2Radio Button單選按鈕群組次項
IDC_BUTTON_TESTPush Button一般按鈕
IDC_CHECK_TESTCheck Box核取方塊
IDC_TREE_TESTTree Control樹狀控件
IDC_LIST_CTRLList Control列表控件(報表模式)
IDC_TAB_CTRLTab Control分頁籤控件
IDC_LIST_TESTList Box列表方塊
IDC_COMBO_TESTCombo Box下拉式方塊
IDC_EDIT_TESTEdit Control編輯框

關鍵步驟:OnInitDialog() 初始化控件

對話框建立後、顯示前會呼叫 OnInitDialog(),此處適合:

  • 設定編輯框預設文字
  • 填充 Combo Box / List Box 項目
  • 初始化 Tree Control 節點
  • 設定 List Control 欄位與樣式
  • 調整 Tab Control 頁籤
BOOL CMy54_s1Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();  // 必須先呼叫基類

    // 1. 編輯框預設文字
    ((CEdit*)GetDlgItem(IDC_EDIT_TEST))->SetWindowText(_T("this is a edit box"));

    // 2. Combo Box 填充項目
    CComboBox* pCombo = (CComboBox*)GetDlgItem(IDC_COMBO_TEST);
    pCombo->AddString(_T("選項一"));
    pCombo->AddString(_T("選項二"));
    pCombo->SetCurSel(0);  // 預設選第一項

    // 3. List Box 填充
    CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST_TEST);
    pList->AddString(_T("專案 A"));
    pList->AddString(_T("專案 B"));

    // 4. Tree Control 建立根節點與子節點
    CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem(IDC_TREE_TEST);
    HTREEITEM hRoot = pTree->InsertItem(_T("根節點"), TVI_ROOT);
    pTree->InsertItem(_T("子節點 1"), hRoot);
    pTree->InsertItem(_T("子節點 2"), hRoot);
    pTree->Expand(hRoot, TVE_EXPAND);

    // 5. List Control 報表模式欄位設定
    CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_CTRL);
    pListCtrl->InsertColumn(0, _T("名稱"), LVCFMT_LEFT, 120);
    pListCtrl->InsertColumn(1, _T("數值"), LVCFMT_RIGHT, 80);
    pListCtrl->InsertItem(0, _T("項目一"));
    pListCtrl->SetItemText(0, 1, _T("100"));

    return TRUE;  // 傳回 TRUE 除非你手動設定焦點
}

訊息映射實作:ClassWizard 操作流程

  1. 開啟 ClassWizard → Message Maps 頁籤。
  2. Class name 選擇對話框類,Object IDs 列表會顯示所有控件 ID。
  3. 選中某 ID(如 IDC_BUTTON_TEST),Messages 列表顯示可用訊息(BN_CLICKED、BN_DISABLE 等)。
  4. 雙擊 BN_CLICKED → Add Function → 命名為 OnButtonTest。
  5. 對 IDC_CHECK_TEST 加入 BN_CLICKED → OnCheckTest。
  6. 對 IDC_TREE_TEST 加入 TVN_SELCHANGED (NM_TREEVIEW) → OnSelchangedTreeTest。

ClassWizard 自動產生的映射表片段:

BEGIN_MESSAGE_MAP(CMy54_s1Dlg, CDialog)
    //{{AFX_MSG_MAP(CMy54_s1Dlg)
    ON_BN_CLICKED(IDC_BUTTON_TEST, OnButtonTest)
    ON_BN_CLICKED(IDC_CHECK_TEST, OnCheckTest)
    ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_TEST, OnSelchangedTreeTest)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_CTRL, OnItemchangedListCtrl)
    ON_CBN_SELCHANGE(IDC_COMBO_TEST, OnSelchangeComboTest)
    ON_LBN_SELCHANGE(IDC_LIST_TEST, OnSelchangeListTest)
    ON_EN_CHANGE(IDC_EDIT_TEST, OnChangeEditTest)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

處理函式實作範例

// 按鈕點擊:切換 Check Box 狀態
void CMy54_s1Dlg::OnButtonTest()
{
    CButton* pCheck = (CButton*)GetDlgItem(IDC_CHECK_TEST);
    pCheck->SetCheck(!pCheck->GetCheck());  // 切換勾選
}

// Check Box 點擊:啟用/禁用編輯框
void CMy54_s1Dlg::OnCheckTest()
{
    CButton* pCheck = (CButton*)GetDlgItem(IDC_CHECK_TEST);
    GetDlgItem(IDC_EDIT_TEST)->EnableWindow(pCheck->GetCheck() == BST_CHECKED);
}

// Tree Control 選擇變更:顯示節點文字
void CMy54_s1Dlg::OnSelchangedTreeTest(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem(IDC_TREE_TEST);
    HTREEITEM hSel = pTree->GetSelectedItem();
    if (hSel)
    {
        CString str = pTree->GetItemText(hSel);
        TRACE(_T("選中節點: %s\n"), str);
    }
    *pResult = 0;
}

// List Control 項目變更:取得整列資料
void CMy54_s1Dlg::OnItemchangedListCtrl(NMHDR* pNMHDR, LRESULT* pResult)
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    if (pNMListView->uChanged & LVIF_STATE &&
        (pNMListView->uNewState & LVIS_SELECTED))
    {
        int nItem = pNMListView->iItem;
        CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST_CTRL);
        CString strCol0 = pList->GetItemText(nItem, 0);
        CString strCol1 = pList->GetItemText(nItem, 1);
        AfxMessageBox(_T("選中: ") + strCol0 + _T(" = ") + strCol1);
    }
    *pResult = 0;
}

進階技巧:ON_UPDATE_COMMAND_UI 動態啟用/檢查

若希望按鈕、選單項目依據程式狀態自動啟用/禁用或打勾,可為同一 ID 加入 ON_UPDATE_COMMAND_UI:

// 映射表
ON_UPDATE_COMMAND_UI(IDC_BUTTON_TEST, OnUpdateButtonTest)

// 實作
void CMy54_s1Dlg::OnUpdateButtonTest(CCmdUI* pCmdUI)
{
    // 假設 m_bDataReady 為成員變量
    pCmdUI->Enable(m_bDataReady);           // 啟用/禁用
    pCmdUI->SetCheck(m_bDataReady ? 1 : 0); // 按鈕外觀按下/彈起
}

MFC 會在閒置週期自動呼叫此函式,確保 UI 與資料同步。

常見錯誤與除錯提示

  • 忘記呼叫基類 OnInitDialog():導致 Tab 鍵巡焦、預設按鈕等失效。
  • 訊息映射宏拼寫錯誤:ClassWizard 產生的代碼勿手動修改 ID 拼寫。
  • GetDlgItem 傳回 NULL:控件 ID 拼寫錯誤、或對話框模板未包含該控件。
  • Tree/List 控件未設樣式:資源編輯器中必須勾選 TVS_HASLINES、LVS_REPORT 等。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved