實現步驟
1. 資源導入
- 資源視圖 → 右鍵 Insert → Bitmap
- 匯入圖片,假設資源 ID 為 `IDB_BITMAP1`
2. OnPaint 重寫
void CMyDialogDlg::OnPaint() {
if (IsIconic()) {
// 圖示模式:預設繪製
CPaintDC dc(this);
SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
} else {
// 正常模式:繪製背景圖片
CPaintDC dc(this); // 畫布 DC
CRect rc;
GetClientRect(&rc); // 客戶區矩形
CDC dcMem; // 記憶體 DC (雙緩衝)
dcMem.CreateCompatibleDC(&dc);
CBitmap bmpBackground;
bmpBackground.LoadBitmap(IDB_BITMAP1); // 載入資源位圖
BITMAP bitmap;
bmpBackground.GetBitmap(&bitmap); // 獲取位圖尺寸
CBitmap* pOldBmp = dcMem.SelectObject(&bmpBackground); // 選入記憶體 DC
// 關鍵:拉伸繪製填滿客戶區
dc.StretchBlt(0, 0, rc.Width(), rc.Height(),
&dcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
dcMem.SelectObject(pOldBmp); // 恢復原位圖
}
}
關鍵 API 說明
| API | 用途 |
| `CPaintDC` | 繪圖設備上下文,自動處理 `BeginPaint`/`EndPaint` |
| `CDC::CreateCompatibleDC` | 建立與螢幕相容的記憶體 DC,實現雙緩衝防閃爍 |
| `CBitmap::LoadBitmap` | 從資源載入位圖 |
| `CBitmap::GetBitmap` | 獲取位圖寬高資訊 (`BITMAP` 結構) |
| `CDC::SelectObject` | 將位圖選入 DC,返回舊位圖指標 (需保存以便恢復) |
| `CDC::StretchBlt` | 拉伸位塊傳輸:來源矩形 → 目標矩形自動縮放 |
進階:背景圖片平鋪而非拉伸
// 替換 StretchBlt 為平鋪迴圈
for (int y = 0; y < rc.Height(); y += bitmap.bmHeight) {
for (int x = 0; x < rc.Width(); x += bitmap.bmWidth) {
dc.BitBlt(x, y, bitmap.bmWidth, bitmap.bmHeight, &dcMem, 0, 0, SRCCOPY);
}
}
常見問題
- ❌ **圖片不顯示**:資源 ID 拼寫錯誤、未 `LoadBitmap` 成功 (檢查返回值)
- ❌ **閃爍嚴重**:未使用記憶體 DC 直接在 `dc` 上繪製
- ❌ **調整大小後殘留**:未處理 `WM_ERASEBKGND` 返回 `TRUE` 防止系統擦除背景
補充:阻止系統擦除背景
BOOL CMyDialogDlg::OnEraseBkgnd(CDC* pDC) {
return TRUE; // 由 OnPaint 完全接管背景繪製
}