.NET TIPS

ダブル・バッファリングにより描画を行うには?

デジタルアドバンテージ
2004/08/20

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

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

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

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

private void Form1_Load(object sender, System.EventArgs e)
{
  System.Net.WebClient wc = new System.Net.WebClient();
  System.IO.Stream stream = wc.OpenRead("http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif");
  bitmap = new Bitmap(stream);
  stream.Close();

  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);

  for (int i = 0; i < 360; i += 10)
  {
    e.Graphics.RotateTransform(10);
    e.Graphics.DrawImage(bitmap, 0, 0);
  }
}
ビットマップを回転させながら描画するC#のサンプル・コード
 
Dim bitmap As Image

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  Dim wc As System.Net.WebClient = New System.Net.WebClient
  Dim stream As System.IO.Stream = wc.OpenRead("http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif")
  bitmap = New Bitmap(stream)
  stream.Close()

  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)

  For i As Integer = 0 To 360 Step 10
    e.Graphics.RotateTransform(10)
    e.Graphics.DrawImage(bitmap, 0, 0)
  Next
End Sub
ビットマップを回転させながら描画するVB.NETのサンプル・コード

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

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

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

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

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

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

 Controlクラス(System.Windows.Forms名前空間)には、このダブル・バッファリングによる描画の仕組みが実装されている。これを有効にするには、コントロール・スタイルでDoubleBuffer、UserPaint、AllPaintingInWmPaintの3つを設定すればよい(DoubleBufferだけを設定してもダブル・バッファリングは有効にならない。デフォルトではUserPaint以外は設定されていない)。具体的には、次のようなコードをあらかじめ実行しておくだけでよい。

this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

 この設定により、OnPaintメソッドでの描画はダブル・バッファリングされるようになる。先ほどのコードに上記の3行を加えたサンプル・コードを次に示す。

Image bitmap;

private void Form1_Load(object sender, System.EventArgs e)
{
  System.Net.WebClient wc = new System.Net.WebClient();
  System.IO.Stream stream = wc.OpenRead("http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif");
  bitmap = new Bitmap(stream);
  stream.Close();

  this.SetStyle(ControlStyles.ResizeRedraw, true);
  this.SetStyle(ControlStyles.DoubleBuffer, true);
  this.SetStyle(ControlStyles.UserPaint, true);
  this.SetStyle(ControlStyles.AllPaintingInWmPaint, 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);

  for (int i = 0; i < 360; i += 10)
  {
    e.Graphics.RotateTransform(10);
    e.Graphics.DrawImage(bitmap, 0, 0);
  }
}
ダブル・バッファリングにより描画するC#のサンプル・コード
 
Dim bitmap As Image

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  Dim wc As System.Net.WebClient = New System.Net.WebClient
  Dim stream As System.IO.Stream = wc.OpenRead("http://www.atmarkit.co.jp/fdotnet/images/fdotnet_m.gif")
  bitmap = New Bitmap(stream)
  stream.Close()

  Me.SetStyle(ControlStyles.ResizeRedraw, True)
  Me.SetStyle(ControlStyles.DoubleBuffer, True)
  Me.SetStyle(ControlStyles.UserPaint, True)
  Me.SetStyle(ControlStyles.AllPaintingInWmPaint, 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)

  For i As Integer = 0 To 360 Step 10
    e.Graphics.RotateTransform(10)
    e.Graphics.DrawImage(bitmap, 0, 0)
  Next
End Sub
ダブル・バッファリングにより描画するVB.NETのサンプル・コード

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

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

カテゴリ:Windowsフォーム 処理対象:ウィンドウ
使用ライブラリ:Controlクラス(System.Windows.Forms名前空間)
使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
使用ライブラリ:ControlStyles列挙体(System.Windows.Forms名前空間)
関連TIPS:ウィンドウのリサイズ時に再描画を行うには?
 
この記事と関連性の高い別の.NET TIPS
ダブル・バッファリングにより描画を行うには?(DoubleBuffered編)
背景の描画を禁止して再描画時のちらつきをなくすには?
ウィンドウのリサイズ時に再描画を行うには?
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 記事ランキング

本日 月間