.NET TIPS

ListBoxコントロールのオーナー描画(高さ可変)により画像を一覧表示するには?

デジタルアドバンテージ 遠藤 孝信
2005/08/26

 「TIPS:ListBoxコントロールのオーナー描画(高さ固定)により画像を一覧表示するには?」に対し、本稿ではListBoxコントロールのオーナー描画により、任意の高さで項目を描画する方法について解説する。

 次の画面は、高さの異なる画像を項目として表示しているリストボックスの例である。

高さ可変のオーナー描画によりリストボックスに画像を表示するサンプル・アプリケーションの実行画面
ボタンをクリックすることにより、特定のディレクトリに格納されているJPEG画像を一覧表示する。画面は上から2番目の項目を選択しているところ。1番目の項目とは高さが異なっている。

ListBoxコントロールのプロパティ設定

 ListBoxコントロールで高さ可変のオーナー描画を利用するには、DrawModeプロパティにDrawMode.OwnerDrawVariable(System.Windows.Forms名前空間のDrawMode列挙体の値)を設定する。

 この設定により、ListBoxコントロールでは各項目の描画に関して次の2つのイベントが発生するようになる。

  • MeasureItemイベント:項目の描画サイズが必要とされた場合に発生
  • DrawItemイベント:項目を描画する必要が生じた場合に発生

 後者のDrawItemイベントに関しては前掲のTIPSで解説済みだ。ここではMeasureItemイベントに関して解説する。

項目の描画に先立って発生するMeasureItemイベント

 MeasureItemイベント(measureは「測る」という意味)は、項目描画のためのDrawItemイベントの前に発生する。

 このイベントのイベント・ハンドラとなるメソッドでは、これから描画しようとしている項目の高さをセットする。具体的には、メソッドのパラメータとして渡されるMeasureItemEventArgsクラス(System.Windows.Forms名前空間)のオブジェクトのItemHeightプロパティに設定すればよい。対象となっている項目については、同オブジェクトのIndexプロパティから、そのインデックス番号を取得することができる。

 なお、高さ可変のオーナー描画であっても、1つの項目の高さは255ピクセルを超えることはできないので注意が必要である*(256以上の値をItemHeightプロパティに設定した場合には、その値を256で割ったときの余りが設定されるようである)。

* 日本語のリファレンス・マニュアルには記載されていないが、英語版には明記されている。

高さ可変のオーナー描画によりリストボックスに画像を表示するサンプル・アプリケーション

 以下に、冒頭で示したサンプル・アプリケーションのコードを示す。

 このコードを実行するには、Visual Studio .NETでWindowsアプリケーションを新規作成し、ListBoxコントロールとButtonコントロールをフォームに配置しておく必要がある。そして、配置したButtonコントロールのClickイベント、ListBoxコントロールのDrawItemイベントとMeasureItemイベントの各イベント・ハンドラとして、リスト内の3つのメソッドをそのコメントに従って指定しておく。

const int spacing = 3; // 画像の周りの余白
const int MaxItemHeight = 255; // ItemHeightの最大値

// 幅w、高さh内に収まるようなImageオブジェクトを作成
Image createThumbnail(Image image, int w, int h)
{
  float fw = (float)w / (float)image.Width;
  float fh = (float)h / (float)image.Height;

  float scale = Math.Min(fw, fh);
  int nw = (int)(image.Width * scale);
  int nh = (int)(image.Height * scale);

  return new Bitmap(image, nw, nh);
}

// ListBoxのDrawItemイベントのハンドラ
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
  if (e.Index == -1) // 項目がない場合にも呼び出される
    return;

  e.DrawBackground();

  Image thumbnail = (Image)listBox1.Items[e.Index];
  // 画像を中央に表示
  Console.WriteLine(e.Index + ":" + e.Bounds);
  e.Graphics.DrawImage(thumbnail,
    e.Bounds.X + (e.Bounds.Width - thumbnail.Width) / 2,
    e.Bounds.Y + (e.Bounds.Height - thumbnail.Height) / 2);

  e.DrawFocusRectangle();
}

// ListBoxのMeasureItemイベントのハンドラ
private void listBox1_MeasureItem(object sender, MeasureItemEventArgs e)
{
  Image thumbnail = (Image)listBox1.Items[e.Index];
  e.ItemHeight = thumbnail.Height + spacing * 2;
}

// ButtonのClickイベントのハンドラ
private void button1_Click(object sender, EventArgs e)
{
  // プロパティ設定
  listBox1.ScrollAlwaysVisible = true;
  listBox1.DrawMode = DrawMode.OwnerDrawVariable;

  string imageDir = @"c:\images"; // 画像ディレクトリ
  string[] images = System.IO.Directory.GetFiles(imageDir, "*.jpg");

  foreach (string s in images)
  {
    Image original = Image.FromFile(s);
    Image thumbnail = createThumbnail(
      original,
      listBox1.ClientSize.Width - spacing * 2,
      MaxItemHeight - spacing * 2);

    listBox1.Items.Add(thumbnail); // 画像の追加

    original.Dispose();
    // thumbnailオブジェクトは破棄できない
  }
}
Const spacing As Integer = 3 ' 画像の周りのスペース
Const MaxItemHeight As Integer = 255 ' ItemHeightの最大値

' 幅w、高さh内に収まるようなImageオブジェクトを作成
Function createThumbnail(ByVal image As Image, ByVal w As Integer, ByVal h As Integer) As Image
  Dim fw As Double = CDbl(w) / CDbl(image.Width)
  Dim fh As Double = CDbl(h) / CDbl(image.Height)

  Dim scale As Double = Math.Min(fw, fh)
  Dim nw As Integer = CInt(image.Width * scale)
  Dim nh As Integer = CInt(image.Height * scale)

  Return New Bitmap(image, nw, nh)
End Function


' ListBoxのDrawItemイベントのハンドラ
Private Sub ListBox1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles ListBox1.DrawItem
  If e.Index = -1 Then ' 項目がない場合にも呼び出される
    Return
  End If

  e.DrawBackground()

  Dim thumbnail As Image = CType(ListBox1.Items(e.Index), Image)
  ' 画像を中央に表示
  e.Graphics.DrawImage(thumbnail, _
    e.Bounds.X + (e.Bounds.Width - thumbnail.Width) \ 2, _
    e.Bounds.Y + (e.Bounds.Height - thumbnail.Height) \ 2)

  e.DrawFocusRectangle()
End Sub

' ListBoxのMeasureItemイベントのハンドラ
Private Sub ListBox1_MeasureItem(ByVal sender As Object, ByVal e As MeasureItemEventArgs) Handles ListBox1.MeasureItem
  Dim thumbnail As Image = CType(ListBox1.Items(e.Index), Image)
  e.ItemHeight = thumbnail.Height + spacing * 2
End Sub

' ButtonのClickイベントのハンドラ
Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
  ' プロパティ設定
  ListBox1.ScrollAlwaysVisible = True
  ListBox1.DrawMode = DrawMode.OwnerDrawVariable

  Dim imageDir As String = "c:\images" ' 画像ディレクトリ
  Dim images As String() = System.IO.Directory.GetFiles(imageDir, "*.jpg")

  For Each s As String In images
    Dim original As Image = Image.FromFile(s)
    Dim thumbnail = createThumbnail(original, _
      ListBox1.ClientSize.Width - spacing * 2, _
      MaxItemHeight - spacing * 2)

    ListBox1.Items.Add(thumbnail) ' 画像の追加

    original.Dispose()
    ' thumbnailオブジェクトは破棄できない
  Next
End Sub
高さ可変のオーナー描画によりリストボックスに画像を表示するコード(上:C#、下:VB.NET)

 このコードでは、画像の追加時にリストボックスのサイズに合わせたサムネイル画像を作成しておき、それをリストボックスの項目として追加している。DrawItemイベント・ハンドラでは、対象となる画像を取り出し、その画像の高さを項目の高さとして設定している。

 DrawItemイベント・ハンドラ以外のコードに関しては前掲のTIPSで掲載しているコードとほぼ同じなので、詳しくはそちらを参照してほしい。End of Article

カテゴリ:Windowsフォーム 処理対象:ListBoxコントロール
使用ライブラリ:ListBoxコントロール(System.Windows.Forms名前空間)
使用ライブラリ:MeasureItemEventArgsクラス(System.Windows.Forms名前空間)
関連TIPS:ListBoxコントロールのオーナー描画(高さ固定)により画像を一覧表示するには?
 
この記事と関連性の高い別の.NET TIPS
ListBoxコントロールのオーナー描画(高さ固定)により画像を一覧表示するには?
文字列や画像を無効状態で描画するには?
Windowsフォームで簡単に画像を表示するには?
[ASP.NET AJAX]ListSearchコントロールで検索可能なリストを作成するには?
ダブル・バッファリングにより描画を行うには?(DoubleBuffered編)
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

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

本日 月間