首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

MFC 對話框與視窗背景位圖繪製完整指南

     編輯:VC 教學

問題背景

預設對話框背景為灰色 (COLOR_3DFACE)。開發者常希望以位圖作為背景 (如桌布效果),且不影響控制項顯示。關鍵在於正確處理 WM_ERASEBKGND 與 WM_CTLCOLOR 訊息。

核心原理

  1. WM_ERASEBKGND:Windows 要求視窗繪製背景以「擦除」先前內容。攔截此訊息,在裝置內容上繪製位圖。
  2. WM_CTLCOLOR:Windows 詢問控制項顏色屬性。將控制項背景模式設為透明 (TRANSPARENT),並回傳空心畫刷 (HOLLOW_BRUSH),避免控制項繪製不透明背景遮蓋位圖。

完整實作步驟

1. 建立對話框類別與資源

  • AppWizard 建立專案 Ld145。
  • 資源編輯器新增對話框 IDD_DIALOG1,放置靜態文字、編輯框、單選鈕、列表框等控制項。
  • ClassWizard 建立類別 CBitmapBkgdDlg。
  • 匯入位圖資源 IDB_BITMAP1。

2. 成員變數宣告 (BitmapBkgdDlg.h)

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()
};

3. 訊息映射 (BitmapBkgdDlg.cpp)

BEGIN_MESSAGE_MAP(CBitmapBkgdDlg, CDialog)
    ON_WM_CTLCOLOR()
    ON_WM_DESTROY()
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

4. 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;
}

5. 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; // 已處理背景擦除,不再呼叫預設處理
}

6. OnCtlColor 設定控制項透明背景

HBRUSH CBitmapBkgdDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    pDC->SetBkMode(TRANSPARENT); // 關鍵:控制項背景透明
    return m_brush;              // 回傳空心畫刷
}

7. OnDestroy 清理資源

void CBitmapBkgdDlg::OnDestroy()
{
    CDialog::OnDestroy();

    // 還原記憶體 DC 原始位圖並刪除物件
    ASSERT(m_hBmpOld);
    VERIFY(m_dcMem.SelectObject(CBitmap::FromHandle(m_hBmpOld)));
    m_Bitmap.DeleteObject();
}

8. 主視窗選單呼叫對話框

  • 主框架選單加入「Dialog → Bitmap Background」項目,ID ID_BITMAP_BKGND。
  • CMainFrame::OnBitmapBkgnd 建立並顯示模態對話框:
void CMainFrame::OnBitmapBkgnd()
{
    CBitmapBkgdDlg dlg;
    dlg.DoModal();
}

關鍵技巧總結

訊息處理重點
WM_ERASEBKGND使用 StretchBlt 將位圖縮放填滿客戶區,回傳 TRUE 表示已處理。
WM_CTLCOLORSetBkMode(TRANSPARENT) + 回傳 HOLLOW_BRUSH,控制項不繪製背景。
WM_DESTROY正確還原 DC 狀態並釋放 GDI 物件,防止資源洩漏。

常見問題與解決

  • 位圖不顯示:確認 LoadBitmap 成功、資源 ID 正確、StretchBlt 參數無誤。
  • 控制項周圍有白邊:檢查 OnCtlColor 是否對所有控制項類型都回傳透明模式與空心畫刷。
  • 調整視窗大小後位圖變形:在 OnSize 中重新計算 m_size 並選擇性重建記憶體 DC。

結語

掌握 WM_ERASEBKGND 與 WM_CTLCOLOR 協作,即可輕鬆為對話框或視窗套用任意位圖背景,且完全不影響控制項正常運作。此技巧廣泛應用於啟動畫面、關於對話框、皮膚介面等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved