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

對話框動態顯示位圖:雙緩衝繪製即時時鐘範例完整實作

     編輯:關於C語言

核心技術:記憶體 DC 雙緩衝

避免閃爍關鍵:**所有繪圖操作在記憶體 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();
}

進階優化

  • 減少 GDI 物件建立開銷: 字型、位圖、記憶體 DC 可改為成員變數,OnInitDialog 建立一次,OnDestroy 釋放,DrawBitmap 僅重複使用。
  • 高 DPI 支援: 使用 CreateCompatibleBitmap 參考螢幕 DC 會自動適應 DPI。字型大小用 MulDiv 換算邏輯單位。
  • 透明背景: 若需透明位圖疊加,用 TransparentBlt 或手動 Alpha Blend (AlphaBlend API)。
  • 防止重入: 繪製耗時長時可加關鍵區保護 DrawBitmap。

常見錯誤

錯誤後果修正
未還原 SelectObject 舊物件GDI 物件洩漏、DC 狀態錯亂、後續繪圖異常嚴格成對 SelectObject(pOld),或用 RAII 封裝
位圖尺寸與 BitBlt 尺寸不符截斷或拉伸確保 CreateCompatibleBitmap 尺寸 = BitBlt 寬高
在 OnPaint 外使用 CClientDC 頻繁繪製閃爍、效能差雙緩衝 + 定時器主動更新,或改用 WM_PAINT 觸發
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved