|  | 
| .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イベントのイベント・ハンドラとなるメソッド)の実行が終了した後である。
| カテゴリ:Windowsフォーム 処理対象:ウィンドウ 使用ライブラリ:Controlクラス(System.Windows.Forms名前空間)
 使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
 使用ライブラリ:ControlStyles列挙体(System.Windows.Forms名前空間)
 関連TIPS:ウィンドウのリサイズ時に再描画を行うには?
 | 
 
| 
 
|  | generated by |  | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間