避免閃爍關鍵:**所有繪圖操作在記憶體 DC 完成,最後一次性 BitBlt 到螢幕 DC**。
class CMyDialog : public CDialog {
CRect m_rectBitmap; // 位圖在對話框客戶區矩形
// ...
protected:
BOOL DrawBitmap(CString strTime, CRect* pRect); // 繪製函式
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnDestroy();
DECLARE_MESSAGE_MAP()
};
OnInitDialog)
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
SetTimer(1, 1000, NULL); // 1 秒定時器
CRect rectClient; GetClientRect(&rectClient);
int w = 180, h = 45;
m_rectBitmap.right = rectClient.right - 25;
m_rectBitmap.left = m_rectBitmap.right - w;
m_rectBitmap.top = rectClient.top + 35;
m_rectBitmap.bottom = m_rectBitmap.top + h;
return TRUE;
}
DrawBitmap
BOOL CMyDialog::DrawBitmap(CString strTime, CRect* pRect) {
CClientDC dcScreen(this); // 螢幕 DC
if (!dcScreen.m_hDC) return FALSE;
// 1. 建立相容記憶體 DC
CDC dcMem;
dcMem.CreateCompatibleDC(&dcScreen);
// 2. 建立相容位圖 (繪圖目標)
CBitmap bmp;
bmp.CreateCompatibleBitmap(&dcScreen, pRect->Width(), pRect->Height());
// 3. 選入記憶體 DC,保存舊位圖
CBitmap* pOldBmp = dcMem.SelectObject(&bmp);
// 4. 選入字型
CFont font;
font.CreatePointFont(200, _T("Arial"), &dcScreen); // 20 點
CFont* pOldFont = dcMem.SelectObject(&font);
// 5. 繪圖操作 (全在記憶體 DC)
dcMem.SetBkMode(OPAQUE);
dcMem.SetBkColor(RGB(0,0,0)); // 黑底
dcMem.FillSolidRect(0, 0, pRect->Width(), pRect->Height(), RGB(0,0,0));
dcMem.SetTextColor(RGB(255,0,0)); // 紅字
CRect rectText(0, 0, pRect->Width(), pRect->Height());
dcMem.DrawText(strTime, &rectText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// 6. 關鍵:一次性複製到螢幕
dcScreen.BitBlt(pRect->left, pRect->top, pRect->Width(), pRect->Height(),
&dcMem, 0, 0, SRCCOPY);
// 7. 還原 DC 狀態 (重要!)
dcMem.SelectObject(pOldFont);
dcMem.SelectObject(pOldBmp);
// bmp, font, dcMem 解構時自動釋放 GDI 物件
return TRUE;
}
void CMyDialog::OnTimer(UINT_PTR nIDEvent) {
if (nIDEvent == 1) {
CTime time = CTime::GetCurrentTime();
CString strTime = time.Format(_T("%H:%M:%S"));
DrawBitmap(strTime, &m_rectBitmap);
}
CDialog::OnTimer(nIDEvent);
}
void CMyDialog::OnDestroy() {
KillTimer(1);
CDialog::OnDestroy();
}
OnInitDialog 建立一次,OnDestroy 釋放,DrawBitmap 僅重複使用。CreateCompatibleBitmap 參考螢幕 DC 會自動適應 DPI。字型大小用 MulDiv 換算邏輯單位。TransparentBlt 或手動 Alpha Blend (AlphaBlend API)。DrawBitmap。| 錯誤 | 後果 | 修正 |
|---|---|---|
未還原 SelectObject 舊物件 | GDI 物件洩漏、DC 狀態錯亂、後續繪圖異常 | 嚴格成對 SelectObject(pOld),或用 RAII 封裝 |
位圖尺寸與 BitBlt 尺寸不符 | 截斷或拉伸 | 確保 CreateCompatibleBitmap 尺寸 = BitBlt 寬高 |
在 OnPaint 外使用 CClientDC 頻繁繪製 | 閃爍、效能差 | 雙緩衝 + 定時器主動更新,或改用 WM_PAINT 觸發 |