仮想リストビューの使い方

解決


  2007-04-14 09:35:31  No: 25781

ファイル検索をしてファイル名やパスの結果を、大量表示の時の表示速度が速いということなのでListViewに仮想リストビューとして表示したいのですが、調べてみましたがいまいち使い方が分からずうまくいきません。

皆様アドバイスをお願いします


まこと  2007-04-14 18:04:33  No: 25782

google にて「delphi + 仮想リストビュー」等のキーワードで調べてみた
ら,いくつかサンプルが出てきました。

ここで聞くよりもはやいかと思いますので,そちらを参照されてはどうで
しょうか。

もしまたわからないということであれば,わからないポイントを絞って質
問するとスムーズに回答が貰えると思います。


  2007-04-16 02:11:36  No: 25783

まことさんありがとうございます。
もう一度調べ直して、こちらのサイトを参考にある程度動くようなのを作ってみました。
http://www.occn.zaq.ne.jp/maekawa/delphitip/index.html#c031
それで、下記のコードを書いてみましたが、SubItemに検索したファイルのファイルパスを表示したいのですが、やり方がよくわからないのでアドバイスをお願いします。

unit Unit0;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls;

type
  TForm0 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ListView1Data(Sender: TObject; Item: TListItem);
  private
    { Private 宣言 }
    vListViewItems : TList;
    procedure FileFind(const S: String);
  public
    { Public 宣言 }
  end;

var
  Form0: TForm0;

implementation

{$R *.dfm}

procedure TForm0.Button1Click(Sender: TObject);
var
  S: String;
begin
  vListViewItems.Clear;
  
  S := Edit1.Text;

  if IsDelimiter('\', S, Length(S)) then
    SetLength(S, Length(S) - 1);

  FileFind(S);
end;

procedure TForm0.FileFind(const S: String);
var
  SR: TSearchRec;

  NewListItem: TListItem;
begin
  if FindFirst(S + '\*.*', faAnyFile, SR) = 0 then
    begin
      repeat
        if (SR.Name <> '.') and (SR.Name <> '..') then
          if (SR.Attr and faDirectory) <> 0 then
          begin
          FileFind(S + '\' + SR.Name);

            NewListItem := TListItem.Create(ListView1.Items);
            NewListItem.Caption := SR.Name;
            vListViewItems.Add(NewListItem);
          end
          else
          begin

            NewListItem := TListItem.Create(ListView1.Items);
            NewListItem.Caption := SR.Name;
            vListViewItems.Add(NewListItem);
          end;
          ListView1.Items.Count := vListViewItems.Count;
      until FindNext(SR) <> 0;
      FindClose(SR);
    end;
end;

procedure TForm0.FormCreate(Sender: TObject);
begin
  vListViewItems := TList.Create;
  Edit1.Text := 'C:\text'
end;

procedure TForm0.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := TListItem(vListViewItems[Item.index]).Caption;
end;

end.


まこと  2007-04-16 05:21:07  No: 25784

調べて実際に動くところまでいったのですね。お疲れ様でした。

  質問の内容についてですが,たぶんファイル検索の再帰処理(サブフォルダ
の中まで次々と検索を行っていくルーチン)の部分がよくわからないポイン
トであるように思いました。

  とりあえず,参考になるかと思いますので,以前タブブラウザを作成した
ときに書いた,お気に入りメニューバー作成のコードを掲載しておきます。

  新規作成フォーム上にMainMenu1をおき,N1という名前のメニューを作って
ください。また,Button1もおいてください。後は以下のコードを入力するだ
けです。

  private
    procedure EnumFiles(DirectoryName: string; BaseMenuItem: TMenuItem);

procedure TForm1.EnumFiles(DirectoryName: string; BaseMenuItem: TMenuItem);
var
  SearchRec: TSearchRec;
  MenuItem{, SubMenuItem}: TMenuItem;
  SL1, SL2: TStringList;
  i: Integer;
begin
  if Copy(DirectoryName,Length(DirectoryName),1)<>'\' then DirectoryName:=DirectoryName+'\';

  //ファイルとフォルダでは,作成するメニューのタイプが違うので,別々に管理する。
  SL1 := TStringList.Create;
  SL2 := TStringList.Create;

  if FindFirst(DirectoryName+'*.*', faAnyFile-faHidden, SearchRec) = 0 then
    try
      repeat
        if SearchRec.Attr and faDirectory <> 0 then begin
          if not ((SearchRec.Name = '.') or (SearchRec.Name = '..')) then begin
            //フォルダはSL1へ。
            SL1.Add(SearchRec.Name);
          end;
        end else begin
            //ファイルはSL2へ。
            SL2.Add(SearchRec.Name);
        end;
      until FindNext(SearchRec) <> 0;

      SL1.Sort;
      SL2.Sort;

      for i := 0 to SL1.Count - 1 do begin
        MenuItem := TMenuItem.Create(Self);
        MenuItem.Caption := SL1.Strings[i];
        BaseMenuItem.Add(MenuItem);
        //フォルダなら再度メニュー作成処理へ。
        EnumFiles(DirectoryName + SL1.Strings[i] +'\', MenuItem);
      end;

      for i := 0 to SL2.Count - 1 do begin
        MenuItem:=TMenuItem.Create(Self);
        MenuItem.Caption := SL2.Strings[i];
        //ファイルなら単純にメニューを作って終了。
        BaseMenuItem.Add(MenuItem);
      end;

    finally
      FindClose(SearchRec);
    end;

    SL1.Free;
    SL2.Free;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 //↓IEの「お気に入り(&A)」に相当するメニュー。メニューアイテムなら何でもよいです。
 N1.Clear;
 //↓フォルダパスは適当に書き換えてください。
 EnumFiles('C:\Documents and Settings\Owner\Favorites', N1);
end;


まこと  2007-04-16 05:34:12  No: 25785

申し訳ありませんが,的外れな回答をしてしまったかもしれません。
もし間違っていたらご容赦ください。単純にファイル名の代わりにパス
を表示したいということであれば,S + '\' + SR.Name でいけます。


  2007-04-16 07:52:46  No: 25786

まことさん、すみません説明不足でうまく伝わっていなかったかもしれません。

ListViewがvsReportの時のリストでFileFindで出てきたデータで「ファイル名」と「ファイルパス」のカラムのリストを作りたい時
仮想リストビューじゃないときは

FileFindにある
  NewListItem := TListItem.Create(ListView1.Items);
  NewListItem.Caption := SR.Name;
  vListViewItems.Add(NewListItem);

の場所のコードに
  NewListItem := ListView1.Items.Add;
  NewListItem.Caption := SR.Name;
  NewListItem.SubItems.Add(S);

という風に書いていたのを、多数のファイル情報の表示を早くするためにこれを仮想リストビューの形で表示したく上記のコードにしてみたのですが
仮想リストビューじゃない時のNewListItem.SubItems.Add(S);の部分を仮想リストビューでどうやって表示するかのわかりません。
もう一度アドバイスお願いします。


風来坊  2007-04-16 08:16:02  No: 25787

procedure TForm0.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := TListItem(vListViewItems[Item.index]).Caption;
  Item.SubItems.Assign(TListItem(vlistViewItems[Item.Index]).SubItems);
end;

で、いいんじゃないの?


  2007-04-16 09:17:24  No: 25788

風来坊さん、ありがとうございます。
FileFindを
  NewListItem := TListItem.Create(ListView1.Items);
  NewListItem.Caption := SR.Name;
  NewListItem.SubItems.Add(S);
  vListViewItems.Add(NewListItem);

にして
ListView1Dataに
  Item.SubItems.Assign(TListItem(vlistViewItems[Item.Index]).SubItems);

を加えて試してみました。
目的の値自体は表示することができたのですが、リストがちらつくようになりました。

 XPスタイルの仮想リストビューでちらつきをなくすには?
 https://www.petitmonte.com/bbs/answers?question_id=4225

仮想リストビューのちらつきという事で、上のようなのを見つけたのですが原因も違うみたいですし
載っていた対応も試してみましたが改善できませんでした。

他に手段、又はちらつきを無くす方法があれば助言をお願いします


風来坊  2007-04-16 10:10:35  No: 25789

VirtualTreeview
http://www.lischke-online.de/
敷居は高いかもしれませんがいいですよ。
リストビューとしても使えますし…


aサインは×  2007-04-17 03:21:53  No: 25790

>ListView1Dataに
>  Item.SubItems.Assign(TListItem(vlistViewItems[Item.Index]).SubItems);

素直に Item.SubItems.Add()を使えばチラツキは解決。
Data保持にはTListItemでなく自前のRecordの方がいいと思うけど。


  2007-04-18 06:14:50  No: 25791

風来坊さん、aサインは×さんありがとうございます
VirtualTreeviewはだいぶ高機能そうですけど、今のところListViewを使用していきたいと思っているので、すみません。

Item.SubItems.Add()やRecordをつかうのですね。
仮想リストビュー時の動作の流れや、Recordでどんな風にデータ保持をすればいいのか分からないのでもう少し調べて試してみます


Mr.XRAY  URL  2007-04-26 07:26:31  No: 25792

ついいまし方,仮想リストビューで指定フォルダ内のファイル一覧を取得
するサンプルをUPしました.参考になれば幸いです

http://homepage2.nifty.com/Mr_XRAY/Delphi/plSamples/T_ListView.htm#01

説明するまでもありませんが,このリスト1のメソッドSetFilesListToItemsの
引数が指定のフォルダ名です.したがって,取得したファイル名の前に付加す
ればフルパスとなります.


  2007-05-01 07:22:21  No: 25793

Mr.XRAYさん、ありがとうございます。
まだ色々詰まっていましたので大変参考になりました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加