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

Delphi 雙重緩衝繪圖 (Memory Bitmap) 徹底解決畫面閃爍問題

     編輯:Delphi

前言:為什麼需要雙重緩衝?

在 Windows GDI 繪圖中,直接在 WM_PAINT 回應裡對螢幕 DC 繪圖,會因頻繁重繪 (最小化/最大化/遮蓋/移動) 造成嚴重閃爍。雙重緩衝技術將繪圖操作導向記憶體位圖 (TBitmap),完成後一次 BitBlt 複製到螢幕,可徹底消除閃爍並提升效能。

核心原理:記憶體 DC 與相容位圖

  1. 建立記憶體裝置環境:MemoryDC := TCanvas.Create; MemoryDC.Handle := CreateCompatibleDC(0); 或直接使用 TCanvas 封裝。
  2. 建立相容位圖:MemoryBitmap := TBitmap.Create; MemoryBitmap.Width := ClientWidth; MemoryBitmap.Height := ClientHeight;
  3. 選入位圖:OldBitmap := SelectObject(MemoryDC.Handle, MemoryBitmap.Handle);
  4. 在 MemoryDC 上執行所有繪圖指令 (Line、TextOut、FillRect、StretchDraw 等)。
  5. 一次性複製到螢幕:BitBlt(ScreenDC.Handle, 0, 0, Width, Height, MemoryDC.Handle, 0, 0, SRCCOPY);
  6. 還原並釋放:SelectObject(MemoryDC.Handle, OldBitmap); DeleteDC(MemoryDC.Handle);

Delphi 實戰封裝:TDoubleBufferedCanvas 輔助類別

type
  TDoubleBufferedCanvas = class
  private
    FBitmap: TBitmap;
    FMemoryDC: HDC;
    FOldBitmap: HBITMAP;
    FCanvas: TCanvas;
  public
    constructor Create(Width, Height: Integer);
    destructor Destroy; override;
    procedure BeginDraw(TargetDC: HDC; const Rect: TRect);
    procedure EndDraw(TargetDC: HDC);
    property Canvas: TCanvas read FCanvas;
  end;

constructor TDoubleBufferedCanvas.Create(Width, Height: Integer);
begin
  FBitmap := TBitmap.Create;
  FBitmap.Width := Width;
  FBitmap.Height := Height;
  FBitmap.PixelFormat := pf32bit; // 建議 32-bit 避免調色盤問題
  FMemoryDC := CreateCompatibleDC(0);
  FOldBitmap := SelectObject(FMemoryDC, FBitmap.Handle);
  FCanvas := TCanvas.Create;
  FCanvas.Handle := FMemoryDC;
end;

destructor TDoubleBufferedCanvas.Destroy;
begin
  SelectObject(FMemoryDC, FOldBitmap);
  DeleteDC(FMemoryDC);
  FCanvas.Free;
  FBitmap.Free;
  inherited;
end;

procedure TDoubleBufferedCanvas.BeginDraw(TargetDC: HDC; const Rect: TRect);
begin
  // 可選:清除背景
  FCanvas.Brush.Color := clWhite;
  FCanvas.FillRect(Rect);
end;

procedure TDoubleBufferedCanvas.EndDraw(TargetDC: HDC);
begin
  BitBlt(TargetDC, 0, 0, FBitmap.Width, FBitmap.Height, FMemoryDC, 0, 0, SRCCOPY);
end;

在表單中使用

var
  DoubleBuffer: TDoubleBufferedCanvas;

procedure TForm1.FormCreate(Sender: TObject);
begin
  DoubleBuffer := TDoubleBufferedCanvas.Create(ClientWidth, ClientHeight);
  DoubleBuffered := True; // 開啟 VCL 內建雙重緩衝 (WinXP 以上)
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DoubleBuffer.Free;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  DoubleBuffer.BeginDraw(Canvas.Handle, ClientRect);
  // 所有繪圖指令寫在 DoubleBuffer.Canvas 上
  DoubleBuffer.Canvas.Pen.Color := clRed;
  DoubleBuffer.Canvas.Ellipse(10, 10, 100, 100);
  DoubleBuffer.Canvas.TextOut(20, 20, 'Hello Double Buffer!');
  DoubleBuffer.EndDraw(Canvas.Handle);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  DoubleBuffer.Free;
  DoubleBuffer := TDoubleBufferedCanvas.Create(ClientWidth, ClientHeight);
end;

進階技巧與注意事項

  • VCL 內建 DoubleBuffered:Delphi 6+ 表單/控制項具 DoubleBuffered: Boolean 屬性,設為 True 即自動啟用記憶體位圖緩衝,無需手寫類別 (WinXP 以上有效)。
  • 動態調整大小:OnResize 重建位圖尺寸,避免邊界殘影。
  • 透明度/Alpha 混合:需用 AlphaBlend 或 GDI+,普通 BitBlt 不支援 Alpha。
  • 大量圖形物件:建議維護圖形物件清單 (TList),OnPaint 只遍歷清單繪製,邏輯與繪圖分離。
  • 釋放順序:必須先 SelectObject(OldBitmap) 再 DeleteDC,否則 GDI 物件洩漏。

結語

雙重緩衝是解決 GDI 閃爍的標準方案。Delphi 透過 TBitmap + CreateCompatibleDC 或內建 DoubleBuffered 屬性,讓開發者以極低成本獲得流暢繪圖體驗。掌握記憶體 DC 生命週期管理,即可在遊戲迴圈、即時圖表、自訂控制項等高頻重繪場景中遊刃有餘。

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