DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

コントロールのGraphicsオブジェクトを使って、画像を表示する

Windowsフォームコントロール(フォームを含む)に画像を表示する方法はいくつかありますが(「コントロールやフォームに画像を表示する」で紹介しています)、ここではコントロールのGraphicsオブジェクトを使う方法を説明します。この方法は、.NET Framework Windowsフォームアプリケーションのグラフィックス機能の基礎であるGDI+を直接使用する方法です。

この方法で画像を表示する場合、まずコントロールのGraphicsオブジェクトを作成して、次にそのGraphicsオブジェクトを使って画像を描画するという手順になります。

コントロールのGraphicsオブジェクトを作成する方法は、通常は次の2つです。

  1. Paintイベントハンドラに渡されるPaintEventArgsオブジェクトのGraphicsプロパティで取得する。
  2. Control.CreateGraphicsメソッドで作成する。

以下、それぞれについて説明します。

Paintイベントで描画する方法

コントロールのPaintイベントでは、イベントハンドラに渡されるPaintEventArgsオブジェクトのGraphicsプロパティによって、そのコントロールのGraphicsオブジェクトを取得できます。

次の例では、Panelコントロール(Panel1)にcurrentImageフィールドの画像(C:\test\1.jpg)を表示しています。

VB.NET
コードを隠すコードを選択
'Imports System.Drawing

'画像ファイルを読み込む
Private currentImage As Image = Image.FromFile("C:\test\1.jpg")

'Panel1のPaintイベントハンドラ
Private Sub Panel1_Paint(ByVal sender As Object, _
        ByVal e As PaintEventArgs) Handles Panel1.Paint
    If Not (currentImage Is Nothing) Then
        'DrawImageメソッドで画像を座標(0, 0)の位置に表示する
        e.Graphics.DrawImage(currentImage, _
            0, 0, currentImage.Width, currentImage.Height)
    End If
End Sub
C#
コードを隠すコードを選択
//using System.Drawing;

//画像ファイルを読み込む
Image currentImage = Image.FromFile(@"C:\test\1.jpg");

//Panel1のPaintイベントハンドラ
private void Panel1_Paint(object sender, PaintEventArgs e)
{
    if (currentImage != null)
    {
        //DrawImageメソッドで画像を座標(0, 0)の位置に表示する
        e.Graphics.DrawImage(currentImage,
            0, 0, currentImage.Width, currentImage.Height);
    }
}
注意:上の例のようにして表示した画像ファイルはロックされ、削除できなくなります。この問題の解決法は「表示中の画像ファイルが削除できない問題の解決法」で説明しています。

この例で使用しているImage.FromFileメソッドは、画像ファイルをImageオブジェクトとして読み込む仕事をしています。これについて詳しくは、「画像ファイルを読み込み、Imageオブジェクトを作成する」で説明しています。

また、Graphics.DrawImageメソッドは、ImageオブジェクトをGraphicsオブジェクトに描画する仕事をしています。これについて詳しくは、「画像(Imageオブジェクト)を描画する」で説明しています。

ここではImageオブジェクトを描画するためにGraphics.DrawImageメソッドを使用しましたが、Graphicsクラスの他のメソッドを使えば、様々な図形や線、文字などを描画することもできます。これらについても、「長方形、多角形、楕円、円弧、扇形を描く」、「線を描く」、「曲線を描く」、「文字を描く」などで詳しく説明しています。

補足:フォームに画像を表示させる場合は、上記と同様にPaintイベントハンドラを使う方法以外に、OnPaintメソッドをオーバーライドし、その内で画像を描画する方法も良く使われます。

Paintイベントを発生させる

この方法では、表示させたい画像を新しい画像に変えたいとしても、そのままではうまく行きません。例えば上の例で、currentImageフィールドに別のImageオブジェクトを設定したとしても、すぐには新しい画像が表示されません。このような場合は、コントロールのInvalidateメソッドを呼び出して、コントロールのPaintイベントを強制的に発生させます。

以下の例では、2つの画像を入れ替えてPanel1に表示しています。currentImageフィールドに新しい画像を設定した後で「Panel1.Invalidate」を呼び出さないと、新しい画像が表示されないことをご確認ください。

VB.NET
コードを隠すコードを選択
'Imports System.Drawing

'画像ファイルを読み込む
Private images As Image() = New Image() { _
    Image.FromFile("C:\test\1.jpg"), _
    Image.FromFile("C:\test\2.jpg")}
Private currentImage As Image = Nothing

'Panel1のイベントハンドラ
Private Sub Panel1_Paint(ByVal sender As Object, _
        ByVal e As PaintEventArgs) Handles Panel1.Paint
    If currentImage IsNot Nothing Then
        'DrawImageメソッドで画像を描画する
        e.Graphics.DrawImage(currentImage, _
            0, 0, currentImage.Width, currentImage.Height)
    End If
End Sub

'Button1のClickイベントハンドラ
Private Sub Button1_Click(ByVal sender As Object, _
        ByVal e As EventArgs) Handles Button1.Click
    '表示する画像を入れ替える
    If Not (currentImage Is images(0)) Then
        currentImage = images(0)
    Else
        currentImage = images(1)
    End If
    'コントロールを再描画する。これがないと、新しい画像が表示されない。
    Panel1.Invalidate()
End Sub
C#
コードを隠すコードを選択
//using System.Drawing;

//画像ファイルを読み込む
Image[] images = new Image[] {
    Image.FromFile(@"C:\test\1.jpg"),
    Image.FromFile(@"C:\test\2.jpg") };
Image currentImage = null;

//Panel1のイベントハンドラ
private void Panel1_Paint(object sender, PaintEventArgs e)
{
    if (currentImage != null)
    {
        //DrawImageメソッドで画像を描画する
        e.Graphics.DrawImage(currentImage,
             0, 0, currentImage.Width, currentImage.Height);
    }
}

//Button1のClickイベントハンドラ
private void Button1_Click(object sender, EventArgs e)
{
    //表示する画像を入れ替える
    if (currentImage != images[0])
    {
        currentImage = images[0];
    }
    else
    {
        currentImage = images[1];
    }
    //コントロールを再描画する。これがないと、新しい画像が表示されない。
    Panel1.Invalidate();
}

もしコントロールのサイズを変えた時に画像が正しく表示されない場合は、コントロールのResizeイベントで再描画します。

VB.NET
コードを隠すコードを選択
'Panel1のResizeイベントハンドラ
Private Sub Panel1_Resize(ByVal sender As Object, _
        ByVal e As EventArgs) Handles Panel1.Resize
    DirectCast(sender, Control).Invalidate()
End Sub
C#
コードを隠すコードを選択
//Panel1のResizeイベントハンドラ
private void Panel1_Resize(object sender, EventArgs e)
{
    ((Control)sender).Invalidate();
}

Invalidateメソッドに関してより詳しくは、「Refresh、Update、Invalidateメソッドの違い」をご覧ください。

CreateGraphicsメソッドを使う方法

Paintイベントによる方法がどうしても使えない場合は、こちらの方法です。

コントロールのGraphicsオブジェクトは、Control.CreateGraphicsメソッドで作成できます。CreateGraphicsメソッドで作成したGraphicsオブジェクトは、使用後Disposeメソッドで破棄する必要があります。

次のコードはその例として、Panelコントロール(Panel1)の座標(60, 10)に画像(C:\Blue hills.jpg)を表示しています。

VB.NET
コードを隠すコードを選択
'Imports System.Drawing

'画像ファイルを読み込む
Dim img As Image = Image.FromFile("C:\Blue hills.jpg")

'Panel1のGraphicsオブジェクトを作成
Dim g As Graphics =  Panel1.CreateGraphics()

'画像を描画
g.DrawImage(img, 60, 10, img.Width, img.Height)

'ImageとGraphicsオブジェクトを破棄
img.Dispose()
g.Dispose()
C#
コードを隠すコードを選択
//using System.Drawing;

//画像ファイルを読み込む
Image img = Image.FromFile(@"C:\Blue hills.jpg");

//Panel1のGraphicsオブジェクトを作成
Graphics  g= Panel1.CreateGraphics();

//画像を描画
g.DrawImage(img, 60, 10, img.Width, img.Height);

//ImageとGraphicsオブジェクトを破棄
img.Dispose();
g.Dispose();

この方法には大きな欠点があります。それは、画像を1度描画しただけで、再描画しない点です。試しに上記のコードで表示された画像の上に別のウィンドウを重ねてから、そのウィンドウをどかしてみてください。画像が消えてしまったはずです。このような再描画が必要な場面ではPaintイベントが発生しますので、Paintイベントハンドラで画像を描画していれば画像が消えることがありません。このようにCreateGraphicsメソッドを使った方法は実用性に乏しいです。

注意:Panel1のPaintイベントハンドラに上記のコードを記述しないでください。正しく表示されなくなります。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • Windows Vista以降でUACが有効になっていると、ファイルへの書き込みに失敗する可能性があります。詳しくは、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。