預設對話框背景為灰色 (COLOR_3DFACE)。開發者常希望以位圖作為背景 (如桌布效果),且不影響控制項顯示。關鍵在於正確處理 WM_ERASEBKGND 與 WM_CTLCOLOR 訊息。
TRANSPARENT),並回傳空心畫刷 (HOLLOW_BRUSH),避免控制項繪製不透明背景遮蓋位圖。Ld145。IDD_DIALOG1,放置靜態文字、編輯框、單選鈕、列表框等控制項。CBitmapBkgdDlg。IDB_BITMAP1。class CBitmapBkgdDlg : public CDialog
{
protected:
CDC m_dcMem; // 記憶體 DC
CBitmap m_Bitmap; // 背景位圖
HBITMAP m_hBmpOld; // 原始位圖控制代碼
HBRUSH m_brush; // 空心畫刷
BITMAP m_bmInfo; // 位圖資訊
CPoint m_pt; // 繪製起點
CSize m_size; // 繪製尺寸
// ... 其餘 ClassWizard 產生碼 ...
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg void OnDestroy();
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CBitmapBkgdDlg, CDialog)
ON_WM_CTLCOLOR()
ON_WM_DESTROY()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
OnInitDialog 初始化背景位圖BOOL CBitmapBkgdDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 取得空心畫刷
VERIFY(m_brush = (HBRUSH)GetStockObject(HOLLOW_BRUSH));
// 載入位圖資源
VERIFY(m_Bitmap.LoadBitmap(IDB_BITMAP1));
m_Bitmap.GetObject(sizeof(BITMAP), &m_bmInfo);
// 計算客戶區尺寸
CRect rectClient;
GetClientRect(&rectClient);
m_size.cx = rectClient.right;
m_size.cy = rectClient.bottom;
m_pt = rectClient.TopLeft();
// 建立相容記憶體 DC 並選入位圖
CClientDC dc(this);
VERIFY(m_dcMem.CreateCompatibleDC(&dc));
CBitmap* pBmpOld = m_dcMem.SelectObject(&m_Bitmap);
VERIFY(m_hBmpOld = (HBITMAP)pBmpOld->GetSafeHandle());
return TRUE;
}
OnEraseBkgnd 繪製背景位圖BOOL CBitmapBkgdDlg::OnEraseBkgnd(CDC* pDC)
{
// 將位圖拉伸繪製至整個客戶區
pDC->StretchBlt(m_pt.x, m_pt.y, m_size.cx, m_size.cy,
&m_dcMem, 0, 0, m_bmInfo.bmWidth-1, m_bmInfo.bmHeight-1, SRCCOPY);
return TRUE; // 已處理背景擦除,不再呼叫預設處理
}
OnCtlColor 設定控制項透明背景HBRUSH CBitmapBkgdDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
pDC->SetBkMode(TRANSPARENT); // 關鍵:控制項背景透明
return m_brush; // 回傳空心畫刷
}
OnDestroy 清理資源void CBitmapBkgdDlg::OnDestroy()
{
CDialog::OnDestroy();
// 還原記憶體 DC 原始位圖並刪除物件
ASSERT(m_hBmpOld);
VERIFY(m_dcMem.SelectObject(CBitmap::FromHandle(m_hBmpOld)));
m_Bitmap.DeleteObject();
}
ID_BITMAP_BKGND。CMainFrame::OnBitmapBkgnd 建立並顯示模態對話框:void CMainFrame::OnBitmapBkgnd()
{
CBitmapBkgdDlg dlg;
dlg.DoModal();
}
| 訊息 | 處理重點 |
|---|---|
| WM_ERASEBKGND | 使用 StretchBlt 將位圖縮放填滿客戶區,回傳 TRUE 表示已處理。 |
| WM_CTLCOLOR | SetBkMode(TRANSPARENT) + 回傳 HOLLOW_BRUSH,控制項不繪製背景。 |
| WM_DESTROY | 正確還原 DC 狀態並釋放 GDI 物件,防止資源洩漏。 |
LoadBitmap 成功、資源 ID 正確、StretchBlt 參數無誤。OnCtlColor 是否對所有控制項類型都回傳透明模式與空心畫刷。OnSize 中重新計算 m_size 並選擇性重建記憶體 DC。掌握 WM_ERASEBKGND 與 WM_CTLCOLOR 協作,即可輕鬆為對話框或視窗套用任意位圖背景,且完全不影響控制項正常運作。此技巧廣泛應用於啟動畫面、關於對話框、皮膚介面等場景。