TListViewの処理スピードに不満がある場合

TExtListViewコンポーネントのVirtualモードを使用することで大幅なスピードアップがみこまれます。
このコンポーネントは以下から入手が可能です。
Brad Stowers: bstowers@pobox.com
Delphi Free Stuff:  http://www.pobox.com/~bstowers/delphi/

拙作LhaMiは、TListViewをコンポーネントのVirtualモードに置き換えることで、書庫ファイル読み込み〜表示までのスピードが劇的に向上しました。
但しこのコンポーネントをVirtualモードで使用するためには多少の追加コードが必要になります。これがドキュメントが英文ということもあって、動くようになるまでに苦労しました。
ここでは、簡単なサンプルでその基本的な使用法について説明したいと思います。

また、ここをクリックすると、サンプルプログラムのソースと実行ファイルをダウンロードできます(163,840byte)
このソースはDelphi3でコンパイルできます。

まずはTExtListViewを入手して、コンポーネント登録してください。
フォームにTExtListViewを貼り付けて、プロパティ VirtualMode を True にします(これをFalseのままにすると、TListViewと同じ使い方が出来ます)。

次にカラムプロパティエディタで表示するアイテムを編集します。

ここからが本番です。

ソースの宣言部に、表示アイテムに合わせた構造体を宣言します。

type
  // ExtListViewの仮想モード用データ格納構造体
  PVirtualItem = ^TVirtualItem;
  TVirtualItem = packed record
    Name: string[255]; //実際のアイテムカラム構造に合わせて
    Size: string[16]; //宣言する
    ImageIndex: integer;
  end;

次にこの構造体を保存するリストを宣言します(宣言部は必要に応じて変更してください)

  private
    { Private 宣言 }
    ItemCache: TList; //実際にデータを保存するリスト

FormCreate部等の初期化を行う部分に

  Itemcache := TList.Create;

としてItemCacheを初期化しておきます。

次にアイテムを追加する処理です
ここでは、nameとsizeの二つのアイテムを追加しています。

// 仮想モードでリストを追加する
procedure TMainForm.VirtualListAdd(name: string; size: Extended);
var
  additem: PVirtualItem;
begin
  New(additem);
  additem^.Name := name;
  additem^.Size := Format('%12.0n', [size]);
  additem^.ImageIndex := 0;
  ItemCache.Add(additem);
end;


ここがポイントです。TExtListViewのVirtualモードでは、アイテムの表示時に呼ばれるイベントを自前で準備しなければなりません。
TExtListViewのプロパティ→イベントページにあるOnVMGetItemInfoイベントハンドラを設定します。

//TExtListViewがVirtualモードのときにイベントOnVMGetItemInfoで
//呼ばれる処理
//TExtListViewのプロパティエディタ→イベントOnVMGetItemInfoを
//ダブルクリックして作成されたprocedure部に処理を埋め込む
procedure TMainForm.ExtListView1VMGetItemInfo(Sender: TObject; Item,
  SubItem: Integer; var Mask: TLVVMMaskItems; var Image, Param, State,
  StateMask, Indent: Integer; var Text: String);
begin
  if ItemCache = nil then Exit;

  if (ItemCache.Count > 0) and (ItemCache.Count > Item) then
  begin
    if lvifText in Mask then
    begin
      case SubItem of  //アイテムは左から0,1,2・・・となる
                       //アイテム数分だけ指定する
        0: Text :=  PVirtualItem(ItemCache[Item])^.Name;
        1: Text :=  PVirtualItem(ItemCache[Item])^.Size;
      end;
    end;
    if lvifImage in Mask then
      image := PVirtualItem(ItemCache[Item])^.ImageIndex;
  end;
end;


あとはTExtListViewのアイテムを削除する処理です。TListViewなら、ListView1.Items.Clear とすればすみますが、Virtualモードでは確保したポインタメモリの破棄→TListのクリヤーといった手順を踏む必要があります。

  if ItemCache <> nil then
  begin
    for ii := ItemCache.Count - 1 downto 0 do
    begin
      Dispose(ItemCache[ii]);
      ItemCache.Delete(ii);
    end;
    ItemCache.Clear;	// Vmode;
  end;

サンプルプログラムでは、WIndowsがインストールされているドライブの全てのフォルダを検索して、そのフォルダ名とフォルダ内のファイルサイズ合計を表示しています。

TListView標準・・・「標準」ボタン
TListView+BeginUpdateとEndUpdate追加・・・「Update追加」ボタン
TExtListView Virtualモード・・・「Virtual」ボタン
をそれぞれ押してみてください。
検索に要した時間がmsで表示されます。
このサンプルではアイテム数が二つしかないため、劇的なスピードの差はありませんが、カラム数が多い場合や、追加するアイテム数が多い場合には大きな差となってあらわれます。
尚、サンプルプログラムの改変や流用は自由です。みなさんもいろいろといじってみてください。