在 VC++ 進行繪圖時,直接在 OnPaint 或 OnDraw 中繪製複雜圖形到螢幕 DC(CPaintDC 或 CClientDC),常會因繪製順序、覆蓋區域重疊導致明顯閃爍。解決方案是採用雙緩衝(Double Buffering):先在記憶體裝置內容(Memory DC)完成所有繪圖,再一次 BitBlt 到螢幕,因記憶體複製極快,使用者感知不到中間過程,即可消除閃爍。
CDC::CreateCompatibleDC)。CBitmap::CreateCompatibleBitmap),尺寸等於客戶區大小。SelectObject),此後所有繪圖操作導向該位圖。BitBlt 或 StretchBlt 將記憶體位圖一次複製到螢幕 DC。void CMyView::OnDraw(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
if (rect.IsRectEmpty()) return;
// 1. 建立記憶體 DC
CDC memDC;
if (!memDC.CreateCompatibleDC(pDC)) return;
// 2. 建立相容位圖
CBitmap bitmap;
if (!bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height())) return;
// 3. 選入位圖並保存舊位圖
CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
// 4. 填滿背景(避免殘留)
memDC.FillSolidRect(&rect, pDC->GetBkColor()); // 或 GetSysColor(COLOR_WINDOW)
// ===== 在此進行所有繪圖操作,針對 memDC =====
// 範例:畫矩形、文字、載入圖片等
memDC.Rectangle(10, 10, 100, 100);
memDC.TextOut(20, 20, _T("Hello Double Buffering!"));
// ...
// 5. 一次複製到螢幕
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
// 6. 還原與清理(選回舊位圖後,bitmap 與 memDC 解構時會自動釋放)
memDC.SelectObject(pOldBitmap);
// bitmap 與 memDC 離開作用域自動 DeleteObject/DeleteDC
}
若繪圖頻率高(如遊戲、即時繪圖),可在視窗建立時一次配置,避免重複建立/銷毀開銷:
class CMyView : public CView
{
CDC m_memDC;
CBitmap m_bitmap;
CBitmap* m_pOldBitmap;
CRect m_clientRect;
void InitMemDC(CDC* pDC)
{
GetClientRect(&m_clientRect);
m_memDC.CreateCompatibleDC(pDC);
m_bitmap.CreateCompatibleBitmap(pDC, m_clientRect.Width(), m_clientRect.Height());
m_pOldBitmap = m_memDC.SelectObject(&m_bitmap);
}
void OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// 視窗大小改變時重建位圖
m_memDC.SelectObject(m_pOldBitmap);
m_bitmap.DeleteObject();
m_memDC.DeleteDC();
CDC* pDC = GetDC();
InitMemDC(pDC);
ReleaseDC(pDC);
}
void OnDraw(CDC* pDC)
{
// 直接使用 m_memDC 繪圖
m_memDC.FillSolidRect(m_clientRect, RGB(255,255,255));
// ... 繪圖 ...
pDC->BitBlt(0, 0, m_clientRect.Width(), m_clientRect.Height(), &m_memDC, 0, 0, SRCCOPY);
}
~CMyView()
{
m_memDC.SelectObject(m_pOldBitmap);
}
};
OnSize 時必須重建位圖。FillSolidRect 或 PatBlt 清背景。pDC 繪圖,或使用 CreateCompatibleDC(NULL) 建立螢幕相容 DC 再 StretchBlt。Graphics 物件指向記憶體 DC 的 GetSafeHdc(),注意鎖定/解鎖。TRUE 於 OnEraseBkgnd 禁止背景擦除,配合雙緩衝可進一步減少閃爍。WS_EX_COMPOSITED 擴充樣式,系統自動提供視窗級雙緩衝(子視窗也需支援)。雙緩衝是消除 GDI 繪圖閃爍的標準技術。掌握 CreateCompatibleDC、CreateCompatibleBitmap、SelectObject、BitBlt 流程,並妥善管理 GDI 物件生命週期,即可實現流暢無閃爍的繪圖體驗。