核心概念
- 無模式對話框:顯示後不阻塞主視窗,用戶可在應用程式其他地方繼續操作;
- 通用對話框:封裝於
COMDLG32.DLL,含檔案、列印、字型、顏色、頁面設定、尋找取代,基類 CCommonDialog;
- 訊息傳遞:
SendMessage (同步、直接呼叫視窗程序) vs PostMessage (非同步、投遞隊列);
- 對話框屬於**主框架視窗**,不屬於 View;對話框物件生命週期至應用程式結束,
DestroyWindow 不會自動 delete C++ 物件,需手動管理。
自定義訊息實戰
// 定義
#define WM_GOODBYE (WM_USER + 5)
// 對話框發送
m_pView->PostMessage(WM_GOODBYE, IDOK); // wParam 附帶 IDOK
// View 類處理
class CMyView : public CView {
afx_msg LRESULT OnGoodbye(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_MESSAGE(WM_GOODBYE, OnGoodbye) // 必須在 AFX_MSG_MAP 註釋區塊**外側**
END_MESSAGE_MAP()
LRESULT CMyView::OnGoodbye(WPARAM wParam, LPARAM lParam) {
// wParam = IDOK
return 0;
}
技巧:建構函數傳遞 View 指標
class CMyDialog : public CDialog {
public:
CMyDialog(CView* pView, CWnd* pParent = NULL)
: CDialog(IDD_MYDLG, pParent), m_pView(pView) {}
CView* m_pView;
};
無模式對話框關鍵重寫
class CMyModelessDlg : public CDialog {
// 必須重寫,防止 ESC/Enter/按鈕觸發基類 EndDialog
virtual void OnOK() {
UpdateData(TRUE); // 可選:回寫資料
DestroyWindow(); // 正確銷毀無模式對話框
}
virtual void OnCancel() {
DestroyWindow();
}
// 物件銷毀由外部管理,或在 PostNcDestroy 刪除 this
virtual void PostNcDestroy() { delete this; }
};
通用檔案對話框 CFileDialog 深度應用
嵌套自訂控件 (範例:增加「刪除」按鈕)
- 建立子對話框資源,Style: Child / No Border,放入 Group Box,ID 設為
stc32 (固定,系統識別嵌入點);
- 衍生
CSpecialFileDialog : public CFileDialog;
- 覆寫
OnInitDialog:
GetParent()->GetDlgItem(IDOK)->SetWindowText(_T("Delete")); 修改既有按鈕文字;
GetParent()->SetIcon(...) 設定父視窗圖示;
- 新增按鈕處理:
GetParent()->GetDlgItem(0x480)->GetWindowText(m_strFileName); 取檔名編輯框 (ID 0x480);
GetParent()->SendMessage(WM_COMMAND, IDCANCEL); 關閉對話框。
CFile::Remove(m_strFileName) 刪除檔案 (不經回收站)。
關鍵結構 m_ofn (OPENFILENAME)
CFileDialog dlg(TRUE); // TRUE=開啟, FALSE=另存新檔
dlg.m_ofn.lpstrFilter = _T("Text\0*.txt\0All\0*.*\0");
dlg.m_ofn.lpstrTitle = _T("選擇檔案");
dlg.m_ofn.Flags |= OFN_EXPLORER | OFN_ENABLEHOOK; // 啟用 Hook
if (dlg.DoModal() == IDOK) {
CString path = dlg.GetPathName(); // 完整路徑
}
其他通用對話框速查
| 類別 | 功能 |
CColorDialog | 選擇/建立顏色 |
CFontDialog | 選擇字型 (填充 LOGFONT,不建立字型物件) |
CPrintDialog | 印表機設定與列印 |
CPageSetupDialog | 頁面設定 |
CFindReplaceDialog | 尋找/取代 (無模式) |
Win32 限制
- 標準檔案對話框**無法**動態建立控件 (其他通用對話框同);
- 若需大幅客製,建議自行實作對話框而非 Hook 通用對話框。
對話框標題列加圖示
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
HICON hIcon = AfxGetApp()->LoadIcon(IDI_MYICON);
SetIcon(hIcon, TRUE); // 大圖示
SetIcon(hIcon, FALSE); // 小圖示
return TRUE;
}
// 若為 Child Style 無標題列,需 GetParent()->SetIcon(...) 設定父視窗