DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ImageListにImageを追加するのが遅い(ListView+ImageList)

環境/言語:[WindowsXP SP2 VB2005 EE]
分類:[.NET]

お世話になっております。
ListViewのLargeIconで画像をサムネイル表示できるツールを作っているのですが、
ListViewに表示する画像をImageListに登録する速度が遅すぎて困っています。


’ListViewのほうには事前にアイテムを追加してある
’このループで画像をロードし、各アイテムのアイコンとして表示していく
For i As Integer = 0 To MaxIndex
 Dim imagefile As String = filesArray(i) '画像ファイルを指定
 If ImageList1.Images.ContainsKey(id) = False Then'未追加のキーか判断
   Dim thumbnail As Image = createThumbnail(imagefile)’縮小画像作成
   ImageList1.Images.Add("キー", thumbnail)’イメージリストに追加
   thumbnail.Dispose()
 End If
 ListView1.Items(i).ImageKey = "キー" ’キーを指定してListViewに表示
Next

という感じで追加しているのですが、
画像が500枚あると2分、1000枚で4分かかってしまいます。
(AthlonXP X2 3800+メモリ2Gの環境です)

縮小画像を作る過程や、最終的にListViewに表示する処理など、
どこが遅いのか1つ1つ省いて検証しましたが、どの処理を省いても速度が一緒で、
「ImageList.Images.Add()」がボトルネックになっていました。

画像を一旦配列に入れてから改めてAddRangeで登録すると、
ループで1つ1つ登録するよりも速くなり、4分→30秒に短縮できました。
しかしAddRangeでは項目一つ一つにキーを適切に登録することができないこと、
また30秒程度かかりますがその間無反応でプログレスバーも出せないことで、
それはそれで問題が多くなりました。

エクスプローラの縮小画像表示ほど速くなくてもかまいませんが、
もう少し使い勝手の良い速度で画像を表示できないものでしょうか。
ImageListを使わずに、CollectionのアイテムをListViewに表示する方法などがあれば、一番助かりますが。

何卒アドバイスお願いいたします。

ちなみにListViewを使わずに画像を一つ一つ描画すればよいのでしょうけれど、
作っているプログラムの性質上どうしてもListViewを使いたいと考えています。
2008/03/11(Tue) 22:07:14 編集(投稿者)
2008/03/09(Sun) 14:13:41 編集(投稿者)
 
はじめまして、引っ込んだ略と申します。
 
 私に考えつく方法として、ListViewのOwnerDrawプロパティをTrueにして、
 DrawItemイベントハンドラ内で描画処理を記述する方法があります。
  http://msdn2.microsoft.com/ja-jp/library/system.windows.forms.listview.drawitem.aspx
  
 この場合、ImageList以外のコレクションに格納した画像を使用できるので、
 ImageList.Add(AddRange)による所要時間の増大を避けることができるようです。
 
 サンプルコードを書いてみました。
  http://dobon.net/cgi-bin/up/files/036.zip
 # ↑私のPCで、なぜかDownLoadできません。現段階では原因は分かりません。
 [追記]DownLoadできました。私のPC側の原因だったようです。[ここまで追記]
 
 
 ※ プログラム内でファイルへの書き込みは一切行っておりませんが、
 ※ 念のため使用は自己責任でお願いします。
 ※ コードの改造は自由です。
 
 <私の環境(CeleronM1.5GHz、メモリ512MB、XPHomeSP2、VB2008ExpressEdition)での測定結果>
 
  画像ファイル(1024x768のBitmap、サイズ2.25MB)をハードディスクから読み込み、100x100ピクセルのthumbnailを作成する処理を、同じ画像ファイルで1000回繰り返し行い、ListViewに1000枚のthumbnail画像を表示した場合

   1.OwnerDrawプロパティがTrueの場合、33秒。
      うち14秒は画像のファイルからの読み込み、18秒はThumbNail作成、ListViewItem追加は0.4秒。

   2.OwnerDrawプロパティをFalseにすると、10秒程度遅くなる。
      (ImageList.Add(AddRangeでも同様)の分だけ所要時間が増加)

   ※ 同じファイルを1000回開いた場合の結果なので、
   ※ ファイルからの読み込みの所要時間(14秒)は参考データです。
   ※ 1000個の異なるファイルを開いた場合は、多分もっと時間がかかります。
 
 以上、参考になれば幸いです。
 
以上です。
引っ込んだ略と申します。

 失礼いたしました。
 Array.Contains()という、VB2005では使えないメソッドを使用していたため、
 VB2005ではコンパイルエラーになるコードになっていましたので、訂正いたしました。

  (VB2005版)http://dobon.net/cgi-bin/up/files/037.zip

 あと、OwnerDrawを行う場合には、
 ListViewに表示されるthumbnail画像の縦横比を
 元の画像に合わせました。
 (OwnerDrawを行わない場合(ImageListに画像を格納する場合)には、
  thumbnail画像の縦横比を元の画像に合わせることが、現段階ではできていません)

以上です。
>引っ込んだ略 様

ご返信どうもありがとうございます!
せっかくアドバイス頂いていたのに返事が遅れまして、
大変申し訳ございませんでした<(_ _)>
やや諦めムードにさしかかり、チェックを疎かにしておりました。

わざわざファイルまでアップロードして頂きまして、本当に恐縮です。
これからアドバイス頂いたようにやってみたいと思います。

取り急ぎ、お礼のみ失礼いたします<(_ _)>

DOBON.NET | プログラミング道 | プログラミング掲示板