| 類型 | 行為 | 典型例子 |
| 模態 | 關閉前禁止操作同程式其他窗口 | 開啟檔案、列印、屬性設定 |
| 非模態 | 可同時操作其他窗口 | 尋找/取代、工具箱、屬性頁 |
MFC 對話框開發標準六步驟
- **資源編輯器**繪製對話框模板,自動更新
.rc。
- **ClassWizard** 建立
CDialog 派生類,關聯模板資源 ID。
- **ClassWizard** 添加成員變數 (控件值)、
DoDataExchange (DDX)、驗證函數 (DDV)。
- **ClassWizard** 為按鈕/控件添加消息處理函數 (
BN_CLICKED, EN_CHANGE...)。
- 編輯特殊初始化 (
OnInitDialog) 與消息處理函數;關閉時記得調用 OnOK。
- 視圖/主框架代碼中構造對話框對象,調用
DoModal() (模態) 或 Create() (非模態)。
實戰專案:北京體育彩票 36 選 7 選號器 (Dialog Based)
界面設計 (資源編輯器)
- 刪除預設 OK/Cancel 按鈕。
- 添加:靜態文字「電腦體育彩票選號:」、7 個 Edit 控件 (IDC_EDIT1~7)、1 個 Button「選號」(IDC_BUTTON1)。
- 每個 Edit 控件屬性:**Number** (只允許數字)、**Read Only** (防用戶手改)。
ClassWizard 綁定變數 (int 型)
Control ID Variable Type
IDC_EDIT1 m_num1 int
IDC_EDIT2 m_num2 int
...
IDC_EDIT7 m_num7 int
添加按鈕點擊處理
Message Maps → IDC_BUTTON1 → BN_CLICKED → OnButton1。
核心算法:隨機數生成、去重、排序
void CGuessDlg::OnButton1() {
// 1. 初始化 1~36 候選池
int pnum[36];
for (int i = 0; i < 36; ++i) pnum[i] = i + 1;
int num[7] = {0};
int temp;
// 2. 選 7 個不重複號碼
for (int i = 0; i < 7; ++i) {
// 每次重新播種:當前時間作種子,保證序列不重複
srand((unsigned)time(NULL));
temp = rand() % 36; // 0~35
while (pnum[temp] == 0) { // 已被取走,重選
srand((unsigned)time(NULL));
temp = rand() % 36;
}
num[i] = pnum[temp]; // 記錄號碼 (1~36)
pnum[temp] = 0; // 標記已用
}
// 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];
// 5. 更新界面 (FALSE = 變數 → 控件)
UpdateData(FALSE);
}
關鍵技術點解析
- 隨機數種子:
srand((unsigned)time(NULL)) 在每次 rand() 前調用,利用當前秒數作種子,**避免程式多次運行產生相同序列** (偽隨機數特性)。
- 去重策略:候選池陣列
pnum,選中後置 0,下次遇到 0 即重選。空間換時間,簡單高效。
- 排序:7 個元素用冒泡/選擇排序即可,代碼極短,無需
qsort/std::sort。
- DDX 機制:
UpdateData(FALSE) 觸發 DoDataExchange → DDX_Text 將 m_numX 格式化為字串寫入 Edit 控件。
反向 UpdateData(TRUE) 將控件文字解析為整數存入變數 (含 DDV_MinMaxInt 驗證)。
DoDataExchange 自動生成代碼
void CGuessDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_num1);
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDX_Text(pDX, IDC_EDIT3, m_num3);
DDX_Text(pDX, IDC_EDIT4, m_num4);
DDX_Text(pDX, IDC_EDIT5, m_num5);
DDX_Text(pDX, IDC_EDIT6, m_num6);
DDX_Text(pDX, IDC_EDIT7, m_num7);
}
運行效果與優化建議
- 點擊「選號」按鈕,7 個 Edit 瞬間顯示排序後的隨機號碼。
- **優化 1**:運行時滑鼠變「沙漏」 —
CWaitCursor wait; (構造即變沙漏,析構自動恢復)。
- **優化 2**:添加進度條控件 (
CProgressCtrl) 顯示選號進度 (下篇實現)。
- **優化 3**:用
std::random_device + std::mt19937 + std::uniform_int_distribution (C++11) 替換 rand/srand,統計質量更高。
雷神心法:從「能跑」到「好用」
- **最小可行性產品 (MVP)**:先跑通核心邏輯 (隨機、去重、排序、顯示)。
- **體驗打磨**:沙漏游標、進度條、輸入驗證、鍵盤快捷鍵 (Enter 觸發選號)、工具提示。
- **健壯性**:檢查
time(NULL) 返回值、處理 rand() 返回 0 邊界、防止重複點擊 (按鈕禁用/標誌位)。
- **可維護性**:將算法提取為獨立函數
GenerateLotteryNumbers(int count, int max, vector& out),便於單元測試、換算法、移植平台。
下一篇預告
Day 10:模態對話框與通用控件 (下) — 攔截 ESC/Enter 關閉、自定義對話框背景/控件顏色 (WM_CTLCOLOR)、添加進度條 (CProgressCtrl) 顯示選號進度、總結對話框改進模式。
- 上一篇文章: 《VC++技術內幕》學習筆記(八):色彩與字體 — RGB/COLORREF、CFont::CreateFont 21 參數詳解、可縮放字體繪製實戰
- 下一篇文章: 《VC++技術內幕》學習筆記(十):模態對話框與通用控件實戰 (下) — 攔截關閉、自定義顏色、進度條
Copyright ©
程式碼之家 All Rights Reserved