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

《VC++技術內幕》學習筆記(十):模態對話框與通用控件實戰 (下) — 攔截關閉、自定義顏色、進度條

     編輯:VC++

Day 10 核心主題:模態對話框與通用控件 (下) — 進階改進

承接上篇「體育彩票選號器」,本篇實現三項關鍵改進:

  1. 攔截 ESC/Enter 關閉對話框,掌握退出控制權。
  2. 自定義對話框背景色與 Edit 控件文字背景色 (WM_CTLCOLOR)。
  3. 添加進度條 (CProgressCtrl) 即時顯示選號進度。

改進一:攔截退出控制權 — 「啞函數」法

問題

  • 焦點在 Edit 控件時按 Enter → 系統尋找預設按鈕 (IDOK) → 找不到 → 調用 OnOK → 對話框關閉。
  • 按 ESC → 系統調用 OnCancel → 對話框關閉。
  • 我們刪除了預設 OK/Cancel 按鈕,導致無法正常關閉,只能靠任務管理器強殺。

解決:重寫虛函數為空實現 (啞函數)

// GuessDlg.h
class CGuessDlg : public CDialog {
    // ...
    virtual void OnOK();   // 重寫
    virtual void OnCancel(); // 重寫
};

// GuessDlg.cpp
void CGuessDlg::OnOK() { }     // 空實現:吞掉 Enter 關閉
void CGuessDlg::OnCancel() { } // 空實現:吞掉 ESC 關閉

恢復正常關閉:添加「退出」按鈕

  1. 資源編輯器添加 Button「退出」(IDC_BUTTON2)。
  2. ClassWizard 添加 BN_CLICKED → OnButton2。
  3. 實現:void CGuessDlg::OnButton2() { CDialog::OnOK(); } — 顯式調用基類 OnOK 正常關閉並返回 IDOK。

**原理**:OnOK/OnCancel 是 CDialog 虛函數,重寫即可攔截預設行為;基類實現包含 EndDialog(IDOK/IDCANCEL)。

改進二:自定義對話框顏色 — WM_CTLCOLOR

機制

每個控件繪製前發送 WM_CTLCOLOR (反映為 OnCtlColor) 給父對話框。父窗口可在處理函數中:

  • 設定文字前景色:pDC->SetTextColor(...)
  • 設定文字背景色:pDC->SetBkColor(...)
  • 返回刷子句柄 (HBRUSH) 用於繪製控件**非文字區域**背景。

實現:Edit 控件文字背景設為黃色

// 1. 成員變數保存刷子 (避免重複創建)
HBRUSH m_hBrush;

// 2. OnInitDialog 初始化刷子
BOOL CGuessDlg::OnInitDialog() {
    CDialog::OnInitDialog();
    m_hBrush = CreateSolidBrush(RGB(255, 255, 0)); // 黃色實心刷子
    return TRUE;
}

// 3. ClassWizard 添加 WM_CTLCOLOR → OnCtlColor
HBRUSH CGuessDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {
    if (nCtlColor == CTLCOLOR_EDIT) { // 僅處理 Edit 控件
        pDC->SetBkColor(RGB(255, 255, 0)); // 文字背景黃色
        return m_hBrush;                   // 非文字區域也用黃色刷子
    }
    return CDialog::OnCtlColor(pDC, pWnd, nCtlColor); // 其他控件走預設
}

// 4. 析構函數釋放刷子
CGuessDlg::~CGuessDlg() {
    if (m_hBrush) DeleteObject(m_hBrush);
}

nCtlColor 可取值表

常數控件類型
CTLCOLOR_BTN按鈕
CTLCOLOR_DLG對話框本身 (非客戶區背景)
CTLCOLOR_EDIT編輯框
CTLCOLOR_LISTBOX列表框
CTLCOLOR_MSGBOX訊息框
CTLCOLOR_SCROLLBAR滾動條
CTLCOLOR_STATIC靜態文字、框架、矩形

改進三:添加進度條 — CProgressCtrl

資源編輯器

  • 添加 Progress Control (IDC_PROGRESS1),屬性設為 **Smooth** (平滑漸變)。
  • ClassWizard 綁定成員變數:CProgressCtrl m_wndProgress (控件型變數,直接操作控件)。

OnButton1 完整升級版

void CGuessDlg::OnButton1() {
    // 1. 初始化進度條
    m_wndProgress.SetRange(0, 70); // 總步長 70 (7 號碼 × 10)
    m_wndProgress.SetPos(0);
    m_wndProgress.SetStep(10);     // 每步 +10

    int pnum[36];
    for (int i = 0; i < 36; ++i) pnum[i] = i + 1;
    int num[7] = {0};
    int temp;

    // 2. 選號循環 (帶進度更新)
    for (int i = 0; i < 7; ++i) {
        srand((unsigned)time(NULL));
        temp = rand() % 36;
        while (pnum[temp] == 0) {
            srand((unsigned)time(NULL));
            temp = rand() % 36;
        }
        num[i] = pnum[temp];
        pnum[temp] = 0;

        m_wndProgress.StepIt(); // 進度 +10
        UpdateData(TRUE);       // 刷新進度條顯示 (控件 → 變數無實際作用,但觸發重繪)
        // 或直接 m_wndProgress.RedrawWindow();
    }

    // 3. 排序 (同前)
    for (int pass = 1; pass < 7; ++pass)
        for (int i = 0; i < 7 - pass; ++i)
            if (num[i] > num[i+1]) { temp = num[i]; num[i] = num[i+1]; num[i+1] = temp; }

    // 4. 賦值並更新界面
    m_num1 = num[0]; m_num2 = num[1]; m_num3 = num[2];
    m_num4 = num[3]; m_num5 = num[4]; m_num6 = num[5];
    m_num7 = num[6];
    UpdateData(FALSE); // 變數 → 控件
}

進度條關鍵 API

對話框改進模式總結

函數用途
SetRange(min, max)設定範圍 (預設 0-100)
SetPos(pos)設定當前位置
SetStep(step)設定 StepIt 增量
StepIt()按 Step 增量前進並重繪
OffsetPos(offset)相對當前位置偏移
GetPos()獲取當前位置

雷神心法:對話框開發「三板斧」

  1. **資源編輯器佈局** — 所見即所得,ID 命名規範 (IDC_前綴 + 語義名)。
  2. **ClassWizard 綁定** — 變數 (值/控件)、消息、DDX/DDV — **不寫手工綁定代碼**。
  3. **核心邏輯集中在消息處理函數** — OnInitDialog 初始化、OnXxx 事件響應、OnOK/OnCancel 關閉控制 — **不在視圖/主框架塞入對話框邏輯**。

本系列《VC++技術內幕》學習筆記 (Day 1-10) 完結

涵蓋:MFC 架構、消息映射、文檔/視圖、映射模式、GDI、色彩字體、對話框控件 — **Windows 桌面開發核心技能樹**。
後續可深入:
- CFormView / CDaoRecordset / COleDocument 等進階文檔/視圖變體。
- 多執行緒 (CWinThread, CCriticalSection, CEvent) 與異步 I/O。
- ActiveX 控件開發、OLE 自動化、資料庫編程 (ODBC/DAO/ADO)。
- 現代化遷移:MFC + D2D/DirectWrite、高 DPI 感知、UWP Bridge、C++20 模組化。
**唯有動手、查閱 MSDN、重構、重寫,才能內化為武功。**

  1. 上一篇文章:
  2. 下一篇文章: No
Copyright © 程式碼之家 All Rights Reserved
需求核心技術關鍵代碼位置
攔截關閉重寫 OnOK/OnCancel 為空 + 專用按鈕調用基類頭文件聲明 + cpp 空實現 + 按鈕處理
自定義顏色WM_CTLCOLOR (OnCtlColor) + CreateSolidBrush/SetBkColorOnInitDialog 創建刷子 + OnCtlColor 返回刷子 + 析構刪除
進度顯示CProgressCtrl + SetRange/StepIt資源編輯器添加 + 綁定控件變數 + 長時間循環中調用 StepIt
沙漏游標CWaitCursor (RAII)長時間操作函數開頭 CWaitCursor wait;
工具提示CToolTipCtrl + AddTool + Activate(TRUE)OnInitDialog 初始化
輸入驗證DDV_MinMaxInt / DDV_MaxChars / 自定義 DDVDoDataExchange 中添加 DDV_*