|   | 
 
|  
 .NET TIPS 
ダブル・バッファリングにより描画を行うには?(DoubleBuffered編)[2.0のみ、C#、VB]
デジタルアドバンテージ 遠藤 孝信 
2006/05/19 | 
  | 
 
 
 
 | 
 複雑なグラフィックを画面に描画する場合、描画の過程が見えてしまい、結果的に描画がちらつくことがある。本稿では、「ダブル・バッファリング」を用いた描画により、これを抑制する方法について紹介する。
ちらつくグラフィックの描画例
 例えば次のサンプル・コード*は、回転させたビットマップを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イベントのイベント・ハンドラとなるメソッド)の実行が終了した後である。
 
|  
 | 
 
generated by  
 | 
 
 
 | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間