.NET TIPS

ウィンドウのリサイズ時に再描画を行うには?

デジタルアドバンテージ
2004/07/30

 ウィンドウに(フォーム上に)グラフィックの描画を行う場合には、当然ながらウィンドウのリサイズ時にも正しく再描画されるようにしなくてはならない。本稿ではウィンドウのリサイズ時の再描画方法について解説する。

OnPaintメソッドによるグラフィックの描画

 ウィンドウへの描画は、Formクラス(System.Windows.Forms名前空間)のOnPaintメソッドをオーバーライドするか、Paintイベントのイベント・ハンドラを追加して行うのが基本的なやり方だ(正確には、OnPaintメソッドはFormクラスのスーパー・クラスであるControlクラス(System.Windows.Forms名前空間)から継承したメソッド)。

 次のサンプル・コード*は、オーバーライドしたOnPaintメソッドにおいて、クライアント領域全体にビットマップを表示するものだ。表示用のビットマップは、フォームのロード時にWebサイトから取得している(これについては「TIPS:画像を読み込むには?」の「Web上の画像の読み込み」で解説している)。

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

private void Form1_Load(object sender, 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.ClientSize = bitmap.Size;
}

protected override void OnPaint(PaintEventArgs e)
{
  base.OnPaint(e);
  e.Graphics.DrawImage(bitmap, this.ClientRectangle);
}
OnPaintメソッドによりビットマップを表示する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.ClientSize = bitmap.Size
End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
  MyBase.OnPaint(e)
  e.Graphics.DrawImage(bitmap, Me.ClientRectangle)
End Sub
OnPaintメソッドによりビットマップを表示するVB.NETのコード(一部)

 OnPaintメソッドでは、フォームのClientRectangleプロパティにより、クライアント領域の表す四角形(左上隅の座標とクライアント領域の幅および高さを含んでいる)を得て、それと同じサイズでビットマップを描画する。これにより常にクライアント領域全体にビットマップが表示されるようにしている。

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

上記サンプル・コードの実行時の画面

 この時点では何も問題ないが、このウィンドウをマウスなどでリサイズすると次のような画面となって描画が正しく行われない。

ウィンドウをリサイズした場合の画面
この画面はウィンドウを下方向に大きくした場合のもの。OnPaintメソッドでは無効領域に対してしか描画が行えないので、クライアント領域全体に対して描画したとしても、実際に描画されるのは(この場合には)リサイズにより広くなった部分だけである。この画面の下部で表示が層状態になっているのは、ウィンドウの枠をドラッグしてリサイズしている間にも何度か再描画が行われているためだ。

 ウィンドウのリサイズ時には再描画が必要となるのでOnPaintメソッドが呼び出されるが、OnPaintメソッドでの描画は基本的に無効領域に対してしか行えない。上記の画面の場合には、ウィンドウをリサイズすることにより広くなった部分が無効領域である。

OnResizeメソッドによるクライアント領域全体の無効化

 本来、無効領域は再描画の必要な部分をできるだけ限定して再描画時のコストを抑えるためのものだ。しかし、今回のコードのように描画内容がウィンドウのサイズに依存するような場合には、ウィンドウのリサイズ時にクライアント領域全体が無効領域となる必要がある。

 ウィンドウがリサイズされたときにクライアント領域全体を無効領域とするには、ウィンドウのリサイズ時に呼び出されるOnResizeメソッドをオーバーライドして(あるいはResizeイベントのイベント・ハンドラを作成して)、フォームのInvalidateメソッドを呼び出せばよい。Invalidateメソッドは指定した領域を無効にするためのもので、メソッドにパラメータを指定しない場合には、クライアント領域全体が無効となる。

 Invalidateメソッドを呼び出すOnResizeメソッドの記述例は次のようになる。

protected override void OnResize(EventArgs e)
{
  base.OnResize(e);
  this.Invalidate();
}

コントロール・スタイルの設定によるリサイズ時の再描画

 上記のようなOnResizeメソッドを記述せずに、フォームの「コントロール・スタイル」に「ControlStyles.ResizeRedraw」を設定しておいても同様の効果が得られる。フォームにコントロール・スタイルを設定するには、フォームのSetStyleメソッドを使用する。

this.SetStyle(ControlStyles.ResizeRedraw, true);

 このメソッドの第1パラメータには、ControlStyles列挙体(System.Windows.Forms名前空間)で定義されている値を指定する。また第2パラメータでは指定したスタイルのオン/オフをbool値で指定する。

 次のサンプル・コードは、上記の1行を先ほどのサンプル・コードに追加したものだ。

Image bitmap;

private void Form1_Load(object sender, 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.ClientSize = bitmap.Size;

  this.SetStyle(ControlStyles.ResizeRedraw, true);
}

protected override void OnPaint(PaintEventArgs e)
{
  base.OnPaint(e);
  e.Graphics.DrawImage(bitmap, this.ClientRectangle);
}

// SetStyleの代わりに以下のコードでもOK
// protected override void OnResize(EventArgs e)
// {
//   base.OnResize(e);
//   this.Invalidate();
// }
コントロール・スタイルの設定によりリサイズ時の再描画を行う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.ClientSize = bitmap.Size

  Me.SetStyle(ControlStyles.ResizeRedraw, True)

End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
  MyBase.OnPaint(e)
  e.Graphics.DrawImage(bitmap, Me.ClientRectangle)
End Sub

' SetStyleの代わりに以下のコードでもOK
' Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
'   MyBase.OnResize(e)
'   Me.Invalidate()
' End Sub
コントロール・スタイルの設定によりリサイズ時の再描画を行うVB.NETのサンプル・コード

 このコードを含むプロジェクトを実行し、先ほどと同様にウィンドウをリサイズした場合の画面は次のようになる。

リサイズ時にも正しく描画されたウィンドウ

 このプログラムでは、ウィンドウをリサイズしても表示内容が乱れることはない。

 ただし、ここで示したコードを実際に実行すれば分かるように、ウィンドウのリサイズ時には描画がかなりちらつく。この対処については「TIPS:背景の描画を禁止して再描画時のちらつきをなくすには?」でまとめている。End of Article

カテゴリ:Windowsフォーム 処理対象:ウィンドウ
使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
使用ライブラリ:ControlStyles列挙体(System.Windows.Forms名前空間)
関連TIPS:背景の描画を禁止して再描画時のちらつきをなくすには?

この記事と関連性の高い別の.NET TIPS
背景の描画を禁止して再描画時のちらつきをなくすには?
ダブル・バッファリングにより描画を行うには?
ダブル・バッファリングにより描画を行うには?(DoubleBuffered編)
クライアント領域やウィンドウ領域の座標を取得するには?
ある座標や領域がコントロールの領域内に含まれているかを確認するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

更新履歴
【2004/08/05】 関連TIPSとして「TIPS:背景の描画を禁止して再描画時のちらつきをなくすには?」についての記述を追加しました。

「.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 記事ランキング

本日 月間