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

VC++ 雙緩衝繪圖消除閃爍:CDC 與 CBitmap 實作步驟

     編輯:VC 教學

前言

在 OnPaint 中直接對螢幕 DC 繪圖,若繪圖指令多或區域大,會產生明顯閃爍。雙緩衝技術先在記憶體相容 DC 繪製完畢,再一次 BitBlt 複製到螢幕,可徹底消除閃爍。

實作步驟

void CMyView::OnDraw(CDC* pDC)
{
    // 1. 建立記憶體相容 DC
    CDC memDC;
    memDC.CreateCompatibleDC(pDC);

    // 2. 建立相容點陣圖(依客戶區大小)
    CRect rectClient;
    GetClientRect(&rectClient);
    CBitmap bmp;
    bmp.CreateCompatibleBitmap(pDC, rectClient.Width(), rectClient.Height());

    // 3. 選入點陣圖並保存舊物件
    CBitmap* pOldBmp = memDC.SelectObject(&bmp);

    // 4. 在記憶體 DC 進行所有繪圖
    memDC.FillSolidRect(rectClient, RGB(255,255,255)); // 清背景
    for (int i = 0; i < 100; ++i) {
        memDC.MoveTo(i*10, 0);
        memDC.LineTo(i*10, rectClient.Height());
    }
    // 繪製其他複雜圖形...
    // memDC.Rectangle(...);
    // DrawMenuButton(memDC);

    // 5. 一次性複製到螢幕 DC
    pDC->BitBlt(0, 0, rectClient.Width(), rectClient.Height(),
                &memDC, 0, 0, SRCCOPY);

    // 6. 還原舊點陣圖並清理
    memDC.SelectObject(pOldBmp);
    // memDC、bmp 會在離開作用域自動釋放
}

關鍵細節

  • CreateCompatibleDC 建立的 DC 初始為 1x1 單色點陣圖,**必須**先 SelectObject 一個適當大小的相容點陣圖才能正常繪圖。
  • SelectObject 回傳的舊物件指標**必須**在結束前 SelectObject 回去,否則會導致 GDI 物件洩漏,甚至讓 DC 無法刪除。
  • 點陣圖大小應與客戶區一致;若視窗可調整大小,需在 OnSize 中重建或動態調整。
  • 若繪圖內容固定,可將 CBitmap 與 CDC 做為成員變數,僅在尺寸改變時重建,提升效能。

進階:封裝為 CDoubleBufferDC 類別

class CDoubleBufferDC : public CDC {
public:
    CDoubleBufferDC(CDC* pDC, const CRect& rect)
        : m_pDC(pDC), m_rect(rect), m_pOldBmp(NULL)
    {
        CreateCompatibleDC(pDC);
        m_bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
        m_pOldBmp = SelectObject(&m_bmp);
        SetBkMode(TRANSPARENT);
    }
    ~CDoubleBufferDC() {
        if (m_pDC->m_hDC) {
            m_pDC->BitBlt(m_rect.left, m_rect.top,
                          m_rect.Width(), m_rect.Height(),
                          this, 0, 0, SRCCOPY);
        }
        SelectObject(m_pOldBmp);
    }
private:
    CDC* m_pDC;
    CRect m_rect;
    CBitmap m_bmp;
    CBitmap* m_pOldBmp;
};

// 使用方式
void CMyView::OnDraw(CDC* pDC) {
    CRect rc; GetClientRect(&rc);
    CDoubleBufferDC dbDC(pDC, rc);
    dbDC.FillSolidRect(rc, RGB(255,255,255));
    // 所有繪圖操作改用 dbDC
    for (int i=0; i<100; ++i) dbDC.LineTo(i*10, rc.Height());
}

適用場景

  • 遊戲迴圈、即時圖表、複雜向量圖形渲染。
  • 任何 WM_PAINT 處理超過 16ms 導致閃爍的情況。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved