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

MFC 雙緩沖繪圖實戰:消除拖拽關鍵點時的屏幕閃爍

     編輯:關於VC++

項目背景與目標

主界面需顯示一張包含人臉的圖片,通過 dlib detector 獲取 68 個面部關鍵點並繪製其上。用戶可拖拽關鍵點調整位置並保存。核心難點:拖拽過程中頻繁重繪導致嚴重閃爍。本文聚焦雙緩沖實現,其他業務邏輯略過。

核心實現步驟

1. 定義核心成員變量

CDC dc_mem;           // 內存繪圖 DC
CDC* dc;                // 螢幕繪圖 DC
vector<CPoint> face;   // 68 個關鍵點坐標
CBitmap bitmap;         // 內存位圖
CImage image;           // 圖片對象

2. 初始化繪圖 DC

BOOL CEditLmDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    dc = GetDC();  // 獲取客戶區 DC
    return TRUE;
}

3. 關鍵:禁用背景擦除

在類中聲明並映射 OnEraseBkgnd,直接返回 TRUE 防止系統擦除背景引發閃爍:

// 頭文件聲明
afx_msg BOOL OnEraseBkgnd(CDC* pDC);

// 消息映射
ON_WM_ERASEBKGND()

// 實現
BOOL CEditLmDlg::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;  // 關鍵步驟!
}

4. 核心繪圖函數 DrawOnBuffer()

void CEditLmDlg::DrawOnBuffer()
{
    CRgn rgn;
    rgn.CreateRectRgn(0, 0, image_width, image_height);
    dc->SelectClipRgn(&rgn);  // 設置裁剪區:僅刷新圖片區域,避免其他控件閃爍

    dc_mem.CreateCompatibleDC(dc);
    bitmap.CreateCompatibleBitmap(dc, edit_rect.Width(), edit_rect.Height());
    CBitmap* pOldBit = dc_mem.SelectObject(&bitmap);

    dc_mem.FillSolidRect(edit_rect, dc->GetBkColor());  // 填充背景
    dc_mem.SetStretchBltMode(HALFTONE);                 // 高質量拉伸模式

    CRect rect(0, 0, image_width, image_height);
    image.Draw(dc_mem.m_hDC, rect);                     // 繪製底圖到內存 DC

    // 將所有關鍵點繪製到 dc_mem(代碼略)

    // 一次性 BitBlt 到螢幕
    dc->BitBlt(0, 0, edit_rect.Width(), edit_rect.Height(), &dc_mem, 0, 0, SRCCOPY);

    dc->SelectClipRgn(NULL);     // 恢復裁剪區
    dc_mem.DeleteDC();
    bitmap.DeleteObject();
}

關鍵點解析:

  • CreateRectRgn 限制刷新區域僅為圖片矩形,其他控件不受影響
  • 繪圖全過程在內存 DC 完成,最後一次 BitBlt 上屏,極快無閃爍
  • 結束時務必清理裁剪區與 GDI 對象

5. 滑鼠拖拽交互

處理三個滑鼠消息,更新坐標後調用 Invalidate() 觸發重繪:

// 頭文件聲明
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);

// 消息映射
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()

在 OnLButtonUp、OnMouseMove 中更新 face 向量對應點座標,隨即 Invalidate() → OnPaint → DrawOnBuffer() 流暢閉環。

總結

雙緩沖精髓在於:將所有繪圖操作集中在單一繪圖函數中,利用內存 DC 完成合成,最後一次性輸出螢幕。代價是需要較多全局/成員變量保存繪圖狀態數據,但換來的流暢體驗絕對值得。

原文參考:https://www.cnblogs.com/battlescars/p/cpp_mfc_drawonbuffer.html

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