![]() ![]() ![]() |
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
きちんと再描画されるようになったのはよいのですが、今度は描画のちらつきが気になるかと思います。 特に、OSの「画面のプロパティ」の「効果」で、「ドラッグ中にウィンドウの内容を表示する」が チェックされていると、サイズを変更中に一定のタイミングでPaintイベントが発生し、 広い範囲で描画しようとするために、ちらつきが発生してしまいます。 描画のちらつきを抑えるには、「ダブルバッファ」というアルゴリズムを使います。 これは簡単に説明すると、描画のためのバッファを2つ取り、先に背面のバッファに描画したものを、 前面に描画することにより、描画中の線などが見えなくなるようにする方法です。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
■サンプル:SimpleDoubleBuffer■ まずは.NET Frameworkにあらかじめ用意されているクラスを使って、 簡単にダブルバッファを実現する方法を説明します。 この方法では先ほどと同様に、SetStyleメソッドを使用します。 フォーム、もしくはコントロールのコンストラクタに以下のコードを追加します。 SetStyle(ControlStyles.ResizeRedraw | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); SetStyleの第1引数のControlStylesはFlagsAttributeがTrue のenumであるため、上記のようにビット演算が可能です。 ここでは、ビットOrで指定したすべてのフラッグをTrueに変えることができます。 ControlStylesのそのほかの値と、フォーム、ユーザーコントロール、 コントロールでのデフォルトの値を表1に示します。 表1:ControlStylesのデフォルトの値
ControlStyles.DoubleBufferを有効にするためには、 必ず「ControlStyles.AllPaintingInWmPaint」を有効にしてください。 これで、ダブルバッファが実現できました。 バッファの設定など細かい作業は、基底クラスで行なってくれます。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
続いて、自分でバッファを作成する方法を説明します。 まずはじめにSetStyleですが、以下のように指定します。 SetStyle(ControlStyles.ResizeRedraw |ControlStyles.Opaque, true); 次に、Paintイベントハンドラを、以下のように記述します。 private void NormalDoubleBuffer_Paint( object sender, PaintEventArgs e) { Bitmap local_bmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height); Graphics bmp_graphics = Graphics.FromImage(local_bmp); bmp_graphics.Clear(BackColor); DrawAster(bmp_graphics); e.Graphics.DrawImage(local_bmp, 0, 0); } 先ほどダブルバッファのアルゴリズムには、2つのバッファを用意すると解説しましたが、 ここでは、元のGraphics以外に、Bitmapクラスからもうひとつの Graphics(bmp_graphics)を作成しています。 以降では説明の便宜上、元のGrapihicsを「表Graphics」と呼び、 Bitmapクラスから作成したもうひとつのGraphicsを「裏Graphics」と呼びます (裏画像ではありません…)。 裏Graphicsに対して、先ほど同様、DrawAsterメソッドで描画を行ない、 Graphics.DrawImageメソッドで描画済みのビットマップを表Graphicsに描画します。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
先ほどあんなに簡単に実現できたダブルバッファをなぜこんなに ややこしくする必要があるかと思っていらっしゃる方もいると思いますので、 両者のメリット/デメリットを簡単にあげてみましょう。 ■ControlStyles.DoubleBufferを使う方法■
■自分でバッファを指定する方法■
「ControlStyles.DoubleBufferを使う方法」のデメリットであげたように、 裏Graphicsのサイズが必ず表Graphicsと同じになるため、 大きな画面ではそれだけメモリが必要になります。 そのため、意図的に異常に大きなサイズに設定すると、 エラー(System.ComponentModel.Win32Exception)が発生します。 後ほど説明する、ScrollableControlでも同様の問題が起こります。 現在画面に表示されているサイズの分だけ裏バッファがあれば十分だと考えられますが、 ScrollableControlで現在見えていない領域のサイズを大きくした場合でも同様のエラーが出ることから、 表示サイズではなく、論理サイズの分のメモリが確保されてしまうと考えられます。 異常に大きなサイズを指定することはコーディングで防げますが、 それでも見えていない部分までバッファを作成してしまうのはもったいという場合には、 細かく制御するために「自分でバッファを指定する方法」で実装するほうがメモリの節約になります。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
■サンプル:NormalDoubleBuffer2■ ここで再び、ちらつきの原因に関して説明しますが、 通常の描画は背景色でいったん描画領域をクリアして、そこに描画したいものを描画するために、 描画に時間がかかる場合に、一瞬背景が見えてしまうために起こります。 「ControlStyles.DoubleBufferを使う方法」では、Control Styles.Opaqueを“True”にして、 背景の描画を行なわない ようにして、ちらつきを予防しています。 そのため、 protected override void OnPaintBackground( PaintEventArgs e) { } というように、PaintBackGroundイベントを無効化することでも同様に実装することが可能です。 この場合は、SetStyleでは、ResizeRedrawだけ設定すれば十分です。 サンプルNormalDoubleBufferとサンプルNormalDoubleBuffer2の両方を実行してみると、 両者が同じ動きをしていることがわかります。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
前へ | ページトップへ | 次へ![]() |