.NET TIPS

ダブル・バッファリングにより描画を行うには?(DoubleBuffered編)[2.0のみ、C#、VB]

デジタルアドバンテージ 遠藤 孝信
2006/05/19

本稿は「TIPS:ダブル・バッファリングにより描画を行うには?」に加筆・修正を行い、.NET Framework 2.0に対応させた改訂版です。

 複雑なグラフィックを画面に描画する場合、描画の過程が見えてしまい、結果的に描画がちらつくことがある。本稿では、「ダブル・バッファリング」を用いた描画により、これを抑制する方法について紹介する。

ちらつくグラフィックの描画例

 例えば次のサンプル・コード*は、回転させたビットマップを36回描画するが、描画に時間がかかるため、特にウィンドウを大きなサイズにリサイズした場合などには描画がちらつく。

* このサンプル・コードを試すには、まずVisual Studio 2005で「Windows アプリケーション」の新規プロジェクトを作成する。そしてフォームをダブルクリックしてコードを開き、自動作成されているForm1_Loadメソッドを削除してから、このサンプル・コードをコピー&ペーストすればよい。

Image bitmap;

private void Form1_Load(object sender, EventArgs e) {
  // Webからビットマップを取得
  using (System.Net.WebClient wc = new System.Net.WebClient())
  using (System.IO.Stream stream = wc.OpenRead(
      "http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif")) {
    bitmap = new Bitmap(stream);
  }
  // リサイズ時に自動的に再描画させる
  this.SetStyle(ControlStyles.ResizeRedraw, true);
}

protected override void OnPaint(PaintEventArgs e) {
  base.OnPaint(e);

  float scale =
    (float)this.ClientSize.Width / (float)bitmap.Width / 2F;
  e.Graphics.TranslateTransform(
    this.ClientSize.Width / 2, this.ClientSize.Height / 2);
  e.Graphics.ScaleTransform(scale, scale);

  // 10度ずつ回転させながらビットマップを描画
  for (int i = 0; i < 360; i += 10) {
    e.Graphics.RotateTransform(10);
    e.Graphics.DrawImage(bitmap, 0, 0);
  }
}
Dim bitmap As Image

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  ' Webからビットマップを取得
  Using wc As New System.Net.WebClient
    Using st As System.IO.Stream = wc.OpenRead( _
        "http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif")
      bitmap = New Bitmap(st)
    End Using
  End Using
  ' リサイズ時に自動的に再描画させる
  Me.SetStyle(ControlStyles.ResizeRedraw, True)
End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
  MyBase.OnPaint(e)

  Dim scale As Single = _
    CSng(Me.ClientSize.Width) / CSng(bitmap.Width) / 2.0F
  e.Graphics.TranslateTransform( _
    Me.ClientSize.Width / 2, Me.ClientSize.Height / 2)
  e.Graphics.ScaleTransform(scale, scale)

  ' 10度ずつ回転させながらビットマップを描画
  For i As Integer = 0 To 360 Step 10
    e.Graphics.RotateTransform(10)
    e.Graphics.DrawImage(bitmap, 0, 0)
  Next
End Sub
ビットマップを回転させながら描画するサンプル・コード(上:C#、下:VB)

 なお、このコードでは、ウィンドウのリサイズ時にも自動的に再描画が行われるように「TIPS:ウィンドウのリサイズ時に再描画を行うには?」で紹介している方法により、ResizeRedrawコントロール・スタイルを設定している。

 このコードを含むプロジェクトを実行すると、次のようなウィンドウが表示される。


上記サンプル・コードの実行時の画面
ウィンドウのサイズを大きくした場合などには、再描画時にビットマップが順に描画されていく様子が見えてしまう。

ダブル・バッファリングを用いた描画

 このような複雑なグラフィックをちらつかせずに描画するには「ダブル・バッファリング」という手法が一般的によく用いられる。これは、グラフィックを画面に直接描画せずに、あらかじめ用意したメモリ上のビットマップ(オフスクリーン・バッファ、裏画面などと呼ばれる)に対していったんすべての描画を行い、それを画面に転送する方法である。

 この方法では、描画が完了したビットマップを転送するだけなので、描画途中のちらつきは完全になくなる。


ダブル・バッファリングによる描画
グラフィックを画面に直接描画せずに、オフスクリーン・バッファにいったんすべての描画を行い、それを画面に転送する。

 Controlクラス(System.Windows.Forms名前空間)には、このダブル・バッファリングによる描画の仕組みが実装されている。

 .NET Framework 1.xでこの機能を有効にするには、「TIPS:ダブル・バッファリングにより描画を行うには?」で解説しているように、3つのコントロール・スタイルを設定する必要があった。

 しかし.NET Framework 2.0では、Controlクラスに新しくDoubleBufferedプロパティが追加され、このプロパティをtrueに設定するだけでダブル・バッファリングが有効になるようになった。この設定により、OnPaintメソッドでの描画はダブル・バッファリングされるようになる。先ほどのコードにこの設定を加えたサンプル・コードを次に示す。

Image bitmap;

private void Form1_Load(object sender, EventArgs e) {
  // Webからビットマップを取得
  using (System.Net.WebClient wc = new System.Net.WebClient())
  using (System.IO.Stream stream = wc.OpenRead(
      "http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif")) {
    bitmap = new Bitmap(stream);
  }
  // リサイズ時に自動的に再描画させる
  this.SetStyle(ControlStyles.ResizeRedraw, true);
  // ダブル・バッファリングをONにする
  this.DoubleBuffered = true;
}

protected override void OnPaint(PaintEventArgs e) {
  base.OnPaint(e);

  float scale =
    (float)this.ClientSize.Width / (float)bitmap.Width / 2F;
  e.Graphics.TranslateTransform(
    this.ClientSize.Width / 2, this.ClientSize.Height / 2);
  e.Graphics.ScaleTransform(scale, scale);

  // 10度ずつ回転させながらビットマップを描画
  for (int i = 0; i < 360; i += 10) {
    e.Graphics.RotateTransform(10);
    e.Graphics.DrawImage(bitmap, 0, 0);
  }
}
Dim bitmap As Image

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  ' Webからビットマップを取得
  Using wc As New System.Net.WebClient
    Using st As System.IO.Stream = wc.OpenRead( _
        "http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif")
      bitmap = New Bitmap(st)
    End Using
  End Using
  ' リサイズ時に自動的に再描画させる
  Me.SetStyle(ControlStyles.ResizeRedraw, True)
  ' ダブル・バッファリングをONにする
  Me.DoubleBuffered = True
End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
  MyBase.OnPaint(e)

  Dim scale As Single = _
    CSng(Me.ClientSize.Width) / CSng(bitmap.Width) / 2.0F
  e.Graphics.TranslateTransform( _
    Me.ClientSize.Width / 2, Me.ClientSize.Height / 2)
  e.Graphics.ScaleTransform(scale, scale)

  ' 10度ずつ回転させながらビットマップを描画
  For i As Integer = 0 To 360 Step 10
    e.Graphics.RotateTransform(10)
    e.Graphics.DrawImage(bitmap, 0, 0)
  Next
End Sub
ダブル・バッファリングにより描画するサンプル・コード(上:C#、下:VB)

 OnPaintメソッド(および、背景の描画を行うOnPaintBackgroundメソッド)のパラメータから得られるGraphicsオブジェクト(サンプル・コードではe.Graphics)では、通常はウィンドウのクライアント領域が描画先としてセットされている。

 しかし、ダブル・バッファリングが有効の場合には、その描画先がオフスクリーン・バッファとなる。また、実際に描画(オフスクリーン・バッファから画面への転送)が行われるのは、OnPaintメソッド(あるいはPaintイベントのイベント・ハンドラとなるメソッド)の実行が終了した後である。End of Article

利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:Windowsフォーム 処理対象:ウィンドウ
使用ライブラリ:Controlクラス(System.Windows.Forms名前空間)
使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
関連TIPS:ダブル・バッファリングにより描画を行うには?
関連TIPS:ウィンドウのリサイズ時に再描画を行うには?

この記事と関連性の高い別の.NET TIPS
ダブル・バッファリングにより描画を行うには?
背景の描画を禁止して再描画時のちらつきをなくすには?
ウィンドウのリサイズ時に再描画を行うには?
PictureBoxコントロールにグラフィックを描画するには?
文字列や画像を無効状態で描画するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間