上一篇介紹了自繪視窗標題列、邊框、系統按鈕的基本原理。但實際專案中,最大的挑戰在於如何讓所有視窗(主視窗、子對話框、屬性頁等)擁有統一風格。Windows 系統預設視窗風格一致,但 MFC 的 CDialog 若要徹底改變外觀極其困難,除非深入 MFC 核心甚至作業系統核心。作者經過無數次嘗試,終找到可行方案:建立自訂基底對話框類別 CTitleBarDlg,所有業務對話框繼承它而非 CDialog。
主視窗同樣是一個對話框,參考上一篇自繪標題列、邊框、按鈕的方法完成。重點在 OnInitDialog() 的處理:
BOOL CTitleBarDlg::OnInitDialog()
{
// 嚴禁在此處修改/新增程式碼!子類別的 OnInitDialog 依賴此流程
m_ToolTip.Create(this, TTS_ALWAYSTIP);
m_ReSizeFlag = TRUE;
CRect rtWnd;
GetClientRect(&rtWnd);
m_OldWidth = rtWnd.Width();
m_OldHeight = rtWnd.Height();
OldPoint.x = rtWnd.Width();
OldPoint.y = rtWnd.Height();
if (!m_BaseFlag) {
m_BaseFlag = TRUE;
CDialog::OnInitDialog();
// ************************************
// 僅允許在這裡修改/新增主視窗專屬初始化碼
// ************************************
}
return TRUE;
}
CYourDlg(基類為 CDialog)。YourDlg.h 與 YourDlg.cpp 中所有 CDialog 替換為 CTitleBarDlg(建議用「取代」功能)。YourDlg.h 加入 #include "TitleBarDlg.h"。CTitleBarDlg nID 必須刪除,否則無法編譯通過。// 顯示代碼範例
CYourDlg* pMyDlg = new CYourDlg;
pMyDlg->Create(IDD_YOUR_DLG);
pMyDlg->ShowWindow(SW_SHOW);
// 注意:必須在適當時機 delete pMyDlg 避免記憶體洩漏
// 若使用 DoModal() 目前尚未成功,歡迎高手提供解法
DoModal() 會導致風格失效。| 訊息 | 用途 |
|---|---|
| WM_NCPAINT | 重繪非客戶區(標題列、邊框),可自繪標題列任意內容 |
| WM_NCLBUTTONDOWN | 非客戶區滑鼠左鍵按下(如標題列按鈕點擊) |
| WM_NCMOUSEMOVE | 非客戶區滑鼠移動(懸停效果、按鈕熱追蹤) |
| WM_SIZE | 視窗大小改變,調整內部控件位置與大小 |
透過 CTitleBarDlg 基底類別,成功實現了主視窗與非模態子對話框的統一風格。雖然模態對話框與獨立視窗仍有限制,但此架構已滿足大多數業務應用需求。後續將探討:將設計好的漂亮視窗子類化、美化其他控件(編輯框、列表框等)、控件隨視窗自動調整大小。敬請期待。