フォームのピクチャボックスなどに画像や線を描画するには、Graphicsオブジェクトに対して描画を行いますが、Graphicsオブジェクトの作成方法はいくつかあり、描画の際の挙動も異なります。
Graphicsオブジェクトの作成方法は以下の通り
●Imageオブジェクトから作成
●PaintイベントのPaintEventArgsから取得
●CreateGraphicsメソッドによる作成
●FromHwndメソッドによる作成
以下にフォームのPictureBoxをDockしたときにPictureBoxに描画するためのGraphicsオブジェクトの作成方法を例にとって説明したいと思います。
Imageオブジェクト(Bitmapオブジェクト)から作成
以下の例ではフォームのリサイズイベント内でピクチャボックスと同じサイズのBitmapオブジェクトを作成し、ピクチャボックスのImageプロパティへBitmapオブジェクトを設定し、BitmapオブジェクトからGraphicオブジェクトを作成し、線を描画しています。
private void Form1_Resize(object sender, EventArgs e)
{
if ((pictureBox1.Width == 0) || (pictureBox1.Height == 0)) return;
var bmp = pictureBox1.Image as Bitmap;
if (bmp != null)
{
bmp.Dispose();
}
bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
pictureBox1.Image = bmp;
using (var g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);
pictureBox1.Refresh();
}
}
実行例
ここではピクチャボックスのリサイズイベントではPictureBoxの大きさの取得に失敗する場合があるため、Formのリサイズイベントで処理を行っています。
PaintイベントのPaintEventArgsから取得
PictureBoxなどのコントロールのPaintイベントのPaintEventArgsからGraphicsオブジェクトを作成します。
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.Clear(Color.White);
g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);
}
実は上記コードだけでは問題があり、PictureBoxがリサイズされると、領域が更新された部分のみ線が描画されてしまうため、以下のようになってしまいます。
このようにならないようにするには、コントロールのResizeイベントでコントロールのInvalidate()を実行することで、コントロール全体の領域が更新され、正しく描画されるようになります。
private void pictureBox1_Resize(object sender, EventArgs e)
{
pictureBox1.Invalidate();
}
CreateImageメソッドで作成
var g = pictureBox1.CreateGraphics();
g.Clear(Color.White);
g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);
FromHwndメソッドで作成
var g = Graphics.FromHwnd(pictureBox1.Handle);
g.Clear(Color.White);
g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);
まとめ
基本的にはImageオブジェクトからFromImageメソッドによりGraphicsオブジェクトを作成する方法がおススメです。
この方法ではGraphicsオブジェクトへ画像や線を描画した内容はBitmapオブジェクトへ反映されるので、使い勝手も良いかと思います。
この方法で描画速度が遅く感じる場合は手動ダブルバッファという方法があるので、こちらのページを参照下さい。
PaintイベントでGraphicsオブジェクトを取得する方法はプログラムが簡単なので、ちょっとした評価用のプログラムなどでは使用することはありますが、描画タイミングなど複雑なプログラムを作成しようとすると、Paintイベント内だけで描画するプログラムを作成するのは難しくなるので、私のブログでPaintイベントでGraphicsオブジェクトを取得しているコードがあったら、「手を抜いているんだな!」と思って下さい。
CreateImage、FromHwndメソッドを用いた方法では、なにせ描画が遅い!
線などたくさん描画するようなプログラムでは、線一本一本が描画される様子が見えるぐらいに遅いです。そのため、私は、この方法をほとんど使いません。
←画像処理のためのC#テクニックへ戻る