首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

MFC 對話框 Tab 切換導致 OnPaint 繪圖消失:雙緩衝區完美解決

     編輯:程式設計綜合問答

問題根因

TabControl 切換頁面時會觸發 WM_PAINT 重繪,若直接在 OnPaint 中用 MoveTo/LineTo 即時繪圖,舊幀內容會被背景擦除覆蓋,導致曲線消失。

解決方案:記憶體位圖雙緩衝 (Double Buffering)

// 類別成員
CBitmap m_memBitmap;
CDC   m_memDC;
CRect m_drawRect; // 繪圖區域

// OnInitDialog 初始化
void CMyDlg::OnInitDialog() {
    CDialogEx::OnInitDialog();
    GetDlgItem(IDC_STATIC_DRAW)->GetWindowRect(&m_drawRect);
    ScreenToClient(&m_drawRect);
    CClientDC dc(this);
    m_memDC.CreateCompatibleDC(&dc);
    m_memBitmap.CreateCompatibleBitmap(&dc, m_drawRect.Width(), m_drawRect.Height());
    m_memDC.SelectObject(&m_memBitmap);
    // 初始清白
    m_memDC.FillSolidRect(&m_drawRect, RGB(255,255,255));
    DrawCurveToMemDC(); // 畫好第一幀
}

// 所有繪圖邏輯集中於此,只畫到 m_memDC
void CMyDlg::DrawCurveToMemDC() {
    CPen pen(PS_SOLID, 2, RGB(0,0,255));
    CPen* oldPen = m_memDC.SelectObject(&pen);
    m_memDC.MoveTo(10, 100);
    m_memDC.LineTo(200, 50);
    // ... 更多 LineTo
    m_memDC.SelectObject(oldPen);
}

// OnPaint 僅做 BitBlt
void CMyDlg::OnPaint() {
    CPaintDC dc(this);
    dc.BitBlt(m_drawRect.left, m_drawRect.top,
              m_drawRect.Width(), m_drawRect.Height(),
              &m_memDC, 0, 0, SRCCOPY);
}

// 需要更新曲線時(如新數據到達)
void CMyDlg::OnNewDataPoint(double value) {
    DrawCurveToMemDC(); // 重畫記憶體 DC
    InvalidateRect(&m_drawRect, FALSE); // 觸發 WM_PAINT
}

關鍵優勢

  • Tab 切換、視窗遮擋、最小化還原 皆由 OnPaint 統一 BitBlt,畫面永不丟失。
  • 繪圖邏輯與顯示邏輯解耦,便於維護與單元測試。
  • 可擴展為「多層圖層」:背景層、網格層、曲線層、標註層分別用 CBitmap,合成時依序 BitBlt。

資源釋放

void CMyDlg::OnDestroy() {
    m_memDC.SelectObject(m_memDC.GetCurrentBitmap()); // 還原預設位圖
    m_memBitmap.DeleteObject();
    m_memDC.DeleteDC();
    CDialogEx::OnDestroy();
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved