承接上篇「體育彩票選號器」,本篇實現三項關鍵改進:
WM_CTLCOLOR)。CProgressCtrl) 即時顯示選號進度。OnOK → 對話框關閉。OnCancel → 對話框關閉。// GuessDlg.h
class CGuessDlg : public CDialog {
// ...
virtual void OnOK(); // 重寫
virtual void OnCancel(); // 重寫
};
// GuessDlg.cpp
void CGuessDlg::OnOK() { } // 空實現:吞掉 Enter 關閉
void CGuessDlg::OnCancel() { } // 空實現:吞掉 ESC 關閉
BN_CLICKED → OnButton2。void CGuessDlg::OnButton2() { CDialog::OnOK(); } — 顯式調用基類 OnOK 正常關閉並返回 IDOK。**原理**:OnOK/OnCancel 是 CDialog 虛函數,重寫即可攔截預設行為;基類實現包含 EndDialog(IDOK/IDCANCEL)。
每個控件繪製前發送 WM_CTLCOLOR (反映為 OnCtlColor) 給父對話框。父窗口可在處理函數中:
pDC->SetTextColor(...)pDC->SetBkColor(...)HBRUSH) 用於繪製控件**非文字區域**背景。// 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);
}
| 常數 | 控件類型 |
|---|---|
| CTLCOLOR_BTN | 按鈕 |
| CTLCOLOR_DLG | 對話框本身 (非客戶區背景) |
| CTLCOLOR_EDIT | 編輯框 |
| CTLCOLOR_LISTBOX | 列表框 |
| CTLCOLOR_MSGBOX | 訊息框 |
| CTLCOLOR_SCROLLBAR | 滾動條 |
| CTLCOLOR_STATIC | 靜態文字、框架、矩形 |
CProgressCtrl m_wndProgress (控件型變數,直接操作控件)。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); // 變數 → 控件
}
| 函數 | 用途 | |
|---|---|---|
| SetRange(min, max) | 設定範圍 (預設 0-100) | |
| SetPos(pos) | 設定當前位置 | |
| SetStep(step) | 設定 StepIt 增量 | |
| StepIt() | 按 Step 增量前進並重繪 | |
| OffsetPos(offset) | 相對當前位置偏移 | |
| GetPos() | 獲取當前位置 |
| 需求 | 核心技術 | 關鍵代碼位置 |
|---|---|---|
| 攔截關閉 | 重寫 OnOK/OnCancel 為空 + 專用按鈕調用基類 | 頭文件聲明 + cpp 空實現 + 按鈕處理 |
| 自定義顏色 | WM_CTLCOLOR (OnCtlColor) + CreateSolidBrush/SetBkColor | OnInitDialog 創建刷子 + OnCtlColor 返回刷子 + 析構刪除 |
| 進度顯示 | CProgressCtrl + SetRange/StepIt | 資源編輯器添加 + 綁定控件變數 + 長時間循環中調用 StepIt |
| 沙漏游標 | CWaitCursor (RAII) | 長時間操作函數開頭 CWaitCursor wait; |
| 工具提示 | CToolTipCtrl + AddTool + Activate(TRUE) | OnInitDialog 初始化 |
| 輸入驗證 | DDV_MinMaxInt / DDV_MaxChars / 自定義 DDV | DoDataExchange 中添加 DDV_* |