程序化結束應用程序
// 優雅關閉:發送 WM_CLOSE,觸發 OnClose 可提示保存
AfxGetMainWnd()->SendMessage(WM_CLOSE);
// 強制終止指定標題窗口 (不推薦,標題可變)
void TerminateWindow(LPCTSTR caption) {
CWnd* pWnd = CWnd::FindWindow(NULL, caption);
if (pWnd) pWnd->SendMessage(WM_CLOSE);
}
// 更穩健:枚舉進程/窗口匹配類名/進程ID
無模式對話框完整實現
關鍵差異:模式 `DoModal()` + `EndDialog()`;無模式 `Create()` + `DestroyWindow()` + `PostNcDestroy` 刪除對象。
class CMyModelessDlg : public CDialog {
public:
CMyModelessDlg() : CDialog(IDD_MY_DIALOG) {}
// 重寫關閉處理
virtual void OnOK() {
if (!UpdateData(TRUE)) return;
DestroyWindow(); // 不調用 EndDialog
}
virtual void OnCancel() { DestroyWindow(); }
// 關鍵:窗口銷毀後刪除 C++ 對象
virtual void PostNcDestroy() { delete this; }
};
// 主框架調用
void CMainFrame::OnShowModeless() {
CMyModelessDlg* pDlg = new CMyModelessDlg(); // 堆分配
if (pDlg->Create(IDD_MY_DIALOG)) {
pDlg->ShowWindow(SW_SHOW);
} else {
delete pDlg; // 創建失敗清理
}
}
啟動外部程序:三大 API 對比
| API | 複雜度 | 功能 | 典型用途 |
| `WinExec` | 極簡 (2 參數) | 路徑 + 顯示方式 | 簡單啟動,無返回值,已棄用 |
| `ShellExecute` | 簡單 | 文件/URL/動詞 (open/print/編輯)、工作目錄 | **首選**:打開文檔、瀏覽器、關聯程序 |
| `CreateProcess` | 複雜 (10 參數) | 完整進程控制:安全屬性、繼承、優先級、環境、啟動信息 | 需精細控制子進程、重定向 I/O、調試器 |
ShellExecute 範例
// 打開文本文件 (自動關聯 Notepad)
ShellExecute(NULL, _T("open"), _T("c:\\readme.txt"), NULL, _T("c:\\"), SW_SHOWNORMAL);
// 打開網址
ShellExecute(NULL, _T("open"), _T("https://example.com"), NULL, NULL, SW_SHOWNORMAL);
// 打印文檔
ShellExecute(NULL, _T("print"), _T("doc.pdf"), NULL, NULL, SW_HIDE);
CreateProcess 精簡範例
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if (CreateProcess(
_T("C:\\Windows\\Notepad.exe"), // 應用程序名
NULL, // 命令行 (NULL 用應用程序名)
NULL, NULL, // 進程/線程安全屬性
FALSE, // 不繼承句柄
NORMAL_PRIORITY_CLASS, // 優先級
NULL, // 環境塊 (繼承父進程)
NULL, // 當前目錄 (繼承父進程)
&si, &pi)) {
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess); // 或等待/監控
}
對話框背景顏色
全局設置 (影響所有對話框)
BOOL CMyApp::InitInstance() {
SetDialogBkColor(RGB(0,0,255), RGB(255,255,0)); // 藍底黃字
return TRUE;
}
單個視圖/對話框自定義背景
class CMyFormView : public CFormView {
CBrush m_brush; // 成員變量保持刷子生命週期
public:
CMyFormView() : CFormView(IDD_MY_FORM) {
m_brush.CreateSolidBrush(RGB(0,0,255)); // 藍色刷子
}
// 處理 WM_CTLCOLOR
HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {
if (nCtlColor == CTLCOLOR_DLG) // 僅對話框背景
return (HBRUSH)m_brush.GetSafeHandle();
return CFormView::OnCtlColor(pDC, pWnd, nCtlColor); // 控件交給默認
}
};
控件指針獲取與操作
| 方法 | 適用場景 | 代碼 |
| `GetDlgItem` | 臨時獲取、無 DDX 變量 | `CSpinButtonCtrl* p = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN);` |
| 類向導 DDX 變量 | 持久成員、類型安全、自動數據交換 | `CSpinButtonCtrl m_spin;` → `DDX_Control(pDX, IDC_SPIN, m_spin);` |
啟用/禁用控件
m_btnOK.EnableWindow(FALSE); // 禁用
m_btnApply.EnableWindow(TRUE); // 啟用
修改控件字體
// 成員變量保持字體對象
CFont m_font;
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
// 創建 8pt Arial
m_font.CreatePointFont(80, _T("Arial")); // 80 = 8pt * 10
m_btnOK.SetFont(&m_font);
return TRUE;
}
// 注意:字體對象必須比控件存活久 (成員變量滿足)
OLE 控件顏色轉換
// OLE_COLOR (長整數) → COLORREF
COLORREF cr = TranslateColor(GetBackColor());
CBrush brush(cr);
pDC->FillRect(&rc, &brush);
無通用對話框顯示文件列表
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
TCHAR path[MAX_PATH] = _T("C:\\Windows");
// 填充組合框
DlgDirListComboBox(path, IDC_COMBO, IDC_CURDIR,
DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_ARCHIVE);
return TRUE;
}
旋鈕控件 (Spin Control) 常見問題
| 現象 | 原因 | 解決 |
| 按 ↑ 數值減小 | 默認範圍 0~100,上限 0 下限 100 | `m_spin.SetRange(0, 100);` 設置正確上下限 |
| 不自動更新關聯編輯框 | Tab Order 中編輯框不在旋鈕之前 | Ctrl+D 調整 Tab Order,確保 Buddy 編輯框優先 |
位圖/圖標按鈕
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
// 按鈕屬性設置 BS_BITMAP 或 BS_ICON
m_btn1.SetIcon(AfxGetApp()->LoadIcon(IDI_ICON1));
m_btn2.SetBitmap(LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BMP1)));
return TRUE;
}
// 注意:位圖按鈕背景色需與對話框一致,否則有邊框
三態按鈕 (Push-like Checkbox)
// 資源編輯器:Checkbox + "Push-like" 樣式
// 程序無需額外代碼,自動呈現:未選中/選中/不確定 三態
動態創建控件
// 類成員
CButton* m_pDynamicBtn;
void CMyDialog::CreateDynamicButton() {
m_pDynamicBtn = new CButton(); // 必須堆分配
m_pDynamicBtn->Create(
_T("動態按鈕"),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
CRect(10, 10, 110, 34), // 位置大小
this, IDC_DYNAMIC_BTN);
}
// 銷毀對話框時 delete m_pDynamicBtn (或 PostNcDestroy)
限制編輯框輸入字符
簡單:數字輸入 (ES_NUMBER)
// 資源編輯器設置 Edit Control 樣式:Number (ES_NUMBER)
// 僅允許 0-9,自動過濾
進階:自定義字符過濾 (派生 CEdit + WM_CHAR)
class CAlphaEdit : public CEdit {
DECLARE_MESSAGE_MAP()
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
};
BEGIN_MESSAGE_MAP(CAlphaEdit, CEdit)
ON_WM_CHAR()
END_MESSAGE_MAP()
void CAlphaEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {
if (isalpha(nChar) || nChar == VK_BACK) // 允許字母和退格
CEdit::OnChar(nChar, nRepCnt, nFlags); // 調用基類處理
// 其他字符直接忽略 (不調用基類)
}
// 大寫轉換版本
void CUpperEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {
if (isalpha(nChar)) nChar = toupper(nChar);
// 必須繞過 CEdit::OnChar 直接調用 DefWindowProc
DefWindowProc(WM_CHAR, nChar, MAKELPARAM(nRepCnt, nFlags));
}
// 對話框中子類化
CAlphaEdit m_edit;
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
m_edit.SubclassDlgItem(IDC_EDIT, this); // 關鍵:運行時替換控件類
return TRUE;
}