仮想リストビューを使ったときのデータのクリアの仕方

解決


まこと  2008-10-04 22:56:48  No: 32104

TListViewを使い、1000件単位のデータを表示していましたが、
もう少し速度を向上させたいと思い、仮想リストビューを使うこ
とにしました。
  その使い方について質問させてください。

●要件
  ①TStringListに入っている各文字列に基づき、ListView1にデータ
    を表示する。
    (具体的には、OwnerDataをTrueにした後、OnDataイベントで、
          Item.Caption := StringList1.Strings[Item.Index]
    などとしています。表示形式はvsReportです。)
  ②Button1を押したときには、ListView1の内容をクリアする。

●質問したい内容
    上の②で、ListView1の内容をクリアするとき、下のようにして
  います。

    ListView1.Items.BeginUpdate;
    ListView1.Items.Count := 0;
    StringList1.Text := ''; // StringList.Clearだと時間がかかったため置き換えた。
    ListView1.Items.EndUpdate;

  ここで、
    ListView1.Items.Clear;
  という一文を入れていないのですが、正しいのでしょうか?
    もし必要だとすれば、ListView1.Items.Count := 0; 
  の前に入れる必要があるのでしょうか?

  ネット上のサンプルではこれが入っていましたが、これを入れると
  処理が遅くなるので、必要ないなら省きたいと考えています。


monaa  2008-10-05 01:06:44  No: 32105

まず、
StringList1.Text := ''; 
StringList.Clear
の速度差ですが、VCLを読めばわかることですが、
StringList1.Text := ''の方が早い事は理論的にあり得ません。
ListView1.Items.Clear;
はListView1.Itemsを全く使用していなければ不要です。

しかし、一体どれくらいの速度を要求してるんですかね?
この辺の処理はそこそこの環境ならマイクロ秒オーダーだと思いますが…

ちょっとサンプル書いてみます。


monaa  2008-10-05 01:49:54  No: 32106

私的にはじゅうぶん早いです。

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
    aListView:TListView;
    aButton  :TButton;

    ListStringList : TStringList;
    procedure SetData;
    procedure aButtonClick(Sender: TObject);
    procedure aListViewData(Sender: TObject; Item: TListItem);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.aButtonClick(Sender: TObject);
begin
  aListView.Items.Count := ListStringList.Count;
end;

procedure TForm1.aListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := ListStringList.Strings[Item.Index];
end;

procedure TForm1.FormCreate(Sender: TObject);
var Column:TListColumn;
begin
  ListStringList:= TStringList.Create;
  SetData;

  aListView := TListView.Create(self);
  aListView.Align  := alClient;
  aListView.ViewStyle := vsReport;
    Column:= aListView.Columns.Add;
    Column.Width := 200;
  aListView.OnData := aListViewData;
  aListView.OwnerData:=True;
  aListView.Parent := Self;

  aButton := TButton.Create(Self);
  aButton.Caption := 'SetData';
  aButton.Anchors := [akRight,akBottom];
  aButton.Left := aListView.Width  - aButton.Width  - 30;
  aButton.Top  := aListView.Height - aButton.Height - 30;
  aButton.Parent := aListView;
  aButton.OnClick := aButtonClick;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  aButton.Free;
  aListView.Free;
  ListStringList.Free;
end;

procedure TForm1.SetData;
var
  DataCount,DataLen,i,p : Integer;
  str,DataStr,bufstr:string;
begin
  DataCount := 999999;  //好きな値を入れる
  DataLen   := Length(InttoStr(DataCount));
  bufstr    := '%.' + IntToStr(DataLen) + 'd';
  SetLength(str,(DataCount*DataLen + DataCount*2)*2);
  for i := 1 to DataCount do
  begin
    DataStr := Format(bufstr,[i]);
    for p := 1 to DataLen do
      str[(i-1)*(DataLen+2)+p] := DataStr[p];
    str[(i-1)*(DataLen+2)+DataLen+1] := #$D;
    str[(i-1)*(DataLen+2)+DataLen+2] := #$A;
  end;
  ListStringList.Text := str;
end;

end.


monaa  2008-10-05 01:52:57  No: 32107

SetData
  //SetLength(str,(DataCount*DataLen + DataCount*2)*2);
  SetLength(str,(DataCount*DataLen + DataCount*2));
バッファサイズ間違えてます。


monaa  2008-10-05 01:55:06  No: 32108

ううう…
  SetLength(str,(DataCount*(DataLen+2)));
です。


monaa  2008-10-05 02:05:17  No: 32109

ぶっちゃけこれでok
procedure TForm1.aButtonClick(Sender: TObject);
begin
  aListView.Items.Count := DataCount;
end;

procedure TForm1.aListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := IntToStr(Item.Index);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  DataCount := 9999999;
end;

要は、TListViewよりデータ処理に時間がかかってると思います。


まこと  2008-10-05 04:56:06  No: 32110

長いサンプルコードまで書いていただいてありがとうございます。

  先ほど、こちらでもサンプルプロジェクトを作って試してみました。
膨大な件数でも一瞬で表示/消去できました。
  TStringListも、単にクリアするだけなら一瞬でした。処理を切り分
けて試していたつもりですが、余計な処理が混じってしまっていたため
に時間がかかってしまっていたのだと思います。

  問題としては解決ですが、とりあえず自分でももう少し処理内容の
理解をしてからチェックマークを付けさせていただきます。

  本当に助かりました。どうもありがとうございました。


まこと  2008-10-10 04:17:40  No: 32111

時間をかけて動作内容の確認等をしましたが、結果はばっちりでした。
そのため、チェックを付けさせていただきます。

  改めて、どうもありがとうございました。


まこと  2008-10-10 04:18:17  No: 32112

肝心のチェックついていませんでした(^^;)


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

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






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