|   | 
          
 
            
|  
              
 .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で掲載しているコードとほぼ同じなので、詳しくはそちらを参照してほしい。
 
        
 
|  
 | 
 
generated by  
 | 
 
 
 | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間