9

由于速度差异很大,我正在尝试使用 VirtualStringTree 而不是 Listview 来构建我的项目。问题是,即使在查看了演示之后,我也无法确切地弄清楚我将如何将它用作 ListView。就像,添加、删除和基本上只是使用 ListView 项目非常容易,但是当我查看 VT 时,它变得几乎太复杂了。

我正在寻找的只是一个看起来像 ListView、带有子项等的 VT。

以下是一些使用 ListView 的例程,我想与 VT 一起使用(这只是一个伪示例:

procedure Add;
begin
  with ListView.Items.Add do
    Begin
      Caption := EditCaption.Text;
      SubItems.Add(EditSubItem.Text):
    End;

end;

Procedure ReadItem(I : Integer);
begin

   ShowMessage(ListView.Items[I].Caption);
   ShowMessage(ListView.Items[I].SubItems[0]);

end;

当然,还有删除功能,但因为那就像 1 行,我没有打扰:P

任何人都可以将上述示例转换为使用 ListView 样式的 VT 吗?

谢谢!

4

5 回答 5

11

为什么不在虚拟模式下使用列表视图?这将看起来和感觉正确并且表现出色。

Delphi TListView 控件是Windows 列表视图组件的包装器。在其默认操作模式下,列表数据的副本从您的应用程序传输到 Windows 控件,这很慢。

对此的替代方法在 Windows 术语中称为虚拟列表视图。您的应用不会将数据传递给 Windows 控件。相反,当控件需要显示数据时,它会要求您的应用程序仅提供所需的数据。

Delphi TListView 控件通过使用 OwnerData 属性公开虚拟列表视图。您将不得不重新编写列表视图代码,但这并不难。

我还提供了一个指向另一个问题的链接,该问题涵盖了类似的领域。相当奇怪的是,即使该问题是关于列表视图控件的,该问题的公认答案也谈到了列表框。

于 2011-01-03T17:53:18.420 回答
6

使用 VirtualStringTree 它比简单的 TListView 复杂一些,但是这里有一个非常简单的教程,我已经创建了一会儿关于如何使用 VirtualStringTree http://www.youtube.com/watch?v=o6FpUJhEeoY我希望它有帮助,干杯!

于 2011-01-03T18:34:39.057 回答
5

只需使用您的普通 TListView,但在虚拟模式下使用它。

这真的很简单:

  1. OwnerData属性设置为true
  2. 实现OnData事件处理程序。

显示 3 行的简单列表的示例实现:

Type TMyItem=record
  Item:String;
  SubItem:String;
end;

var Items:Array of TMyItem;

// set up some in-memory dataset.. choose your own layout
SetLength(Items,3);
Items[0].Item := 'foo1';
Items[0].SubItem := 'bar1';

Items[1].Item := 'foo2';
Items[1].SubItem := 'bar2';

Items[2].Item := 'foo3';
Items[2].SubItem := 'bar3';

// tell ListView1 how many items there are
ListView1.Items.Count := Length(Items); 

procedure TfrmMain.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := IntToStr(Item.Index);
  Item.SubItems.Add( MyArray[Item.Index] );
  Item.SubItems.Add( UpperCase(MyArray[Item.Index]) );
end;

// Updating a value:
Items[1].Item := 'bzzz';
ListView1.Update;

就这样!

需要记住的一些事项:

  1. 您不再调用 ListView1.Items.Add() 了。
  2. 您需要将自己的数据列表保存在内存中的某个位置,或者实时获取数据,因此您不能再将数据“存储”在列表视图中。
  3. 您需要设置 items.count 属性,否则您将看不到任何内容。
  4. 如果有变化,请调用 ListView1.Update()。
于 2011-01-04T02:06:07.527 回答
4
procedure Add;
Var
  Data: PLogData;
  XNode: PVirtualNode;
begin
  with vst do
    Begin
      XNode := AddChild(nil);
      ValidateNode(XNode, False);
      Data := GetNodeData(Xnode); 
      Data^.Name:= EditCaption.Text;
      Data^.Msg := EditSubItem.Text;
    End;

end;

Procedure ReadItem(I : Integer);
var
  Data: PLogData;
begin
  if not Assigned(vst.FocusedNode) then Exit;

  Data := vst.GetNodeData(vst.FocusedNode);
  ShowMessage(Data^.Name);
  ShowMessage(Data^.Msg);

end;

基本上这就是你需要做的,但是 VirtualStringTree 有/需要很多其他的东西一起工作才能完全理解它。一旦你“得到它”,VST 就变得简单而强大。以下网页将为您提供帮助:http ://wiki.freepascal.org/VirtualTreeview_Example_for_Lazarus

下面我将添加更多用于简单 VST 日志显示的代码。我将所有代码保存在数据模块中,只需使用过程 Log 来显示信息并将您的 FormMain.vstLog 更改为您的...

unit udmVstLog;

interface

uses
  SysUtils, Windows, Forms, Classes, Graphics,
  VirtualTrees, ActnList, Dialogs, ExtDlgs;

type
  PLogData = ^TLogData;
  TLogData = record
    IsErr   : Boolean;
    Name: String;
    Msg : String;
  end;

type
  TdmVstLog = class(TDataModule)
    actlst1: TActionList;
    actClear: TAction;
    actSave: TAction;
    actCopyLine2Mem: TAction;
    sdlgLog: TSaveTextFileDialog;
    procedure DataModuleCreate(Sender: TObject);
    procedure actClearExecute(Sender: TObject);
    procedure actSaveExecute(Sender: TObject);
    procedure actCopyLine2MemExecute(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
    procedure VSTPaintText(Sender: TBaseVirtualTree;
      const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
      TextType: TVSTTextType);
  end;

  procedure Log(aIsErr: Boolean; AName, AMsg: string); overload;
  procedure Log(AName, AMsg: string); overload;
  procedure Log(AMsg: string); overload;

var
  dmVstLog: TdmVstLog;

implementation

uses uFormMain, ClipBrd;

{$R *.dfm}
procedure Log(aIsErr: Boolean; AName, AMsg: string);
Var
  Data: PLogData;
  XNode: PVirtualNode;
begin
  XNode:=FormMain.vstLog.AddChild(nil);
  FormMain.vstLog.ValidateNode(XNode, False);
  Data := FormMain.vstLog.GetNodeData(Xnode);
  Data^.IsErr := aIsErr;
  if aIsErr then
    Data^.Name:= DateTimeToStr(Now) + ' ERROR ' + AName
  else
    Data^.Name:= DateTimeToStr(Now) + ' INFO ' + AName;
  Data^.Msg:= AMsg;
end;

procedure Log(AName, AMsg: string);
begin
  Log(False,AName,AMsg);
end;

procedure Log(AMsg: string);
begin
  Log(False,'',AMsg);
end;



// VirtualStringTree Events defined here
procedure TdmVstLog.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Data: PLogData;
begin
  Data:=Sender.GetNodeData(Node);
  Finalize(Data^);
end;

procedure TdmVstLog.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
 Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
var
  Data: PLogData;
begin
  Data := Sender.GetNodeData(Node);
  case Column of
    0: CellText := Data^.Name + ' - '+ Data^.Msg;
  end;
end;

procedure TdmVstLog.VSTPaintText(Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType);
Var
  Data: PLogData;
begin
  Data := Sender.GetNodeData(Node);

  if Data^.IsErr then
    TargetCanvas.Font.Color:=clRed;

end;

//PopUpMenu Actions defined here!
procedure TdmVstLog.actClearExecute(Sender: TObject);
begin
  FormMain.vstLog.Clear;
end;

procedure TdmVstLog.actCopyLine2MemExecute(Sender: TObject);
var
  Data: PLogData;
begin
  if not Assigned(FormMain.vstLog.FocusedNode) then Exit;

  Data := FormMain.vstLog.GetNodeData(FormMain.vstLog.FocusedNode);
  ClipBoard.AsText := Data^.Name + ' - ' + Data^.Msg;
end;

procedure TdmVstLog.actSaveExecute(Sender: TObject);
Var
  XNode: PVirtualNode;
  Data: PLogData;
  ts: TStringList;
begin
  If FormMain.vstLog.GetFirst = nil then Exit;
  XNode:=nil;
  if sdlgLog.Execute then begin
    ts:= TStringList.create;
    try
      Repeat
        if XNode = nil then XNode:=FormMain.vstLog.GetFirst Else XNode:=FormMain.vstLog.GetNext(XNode);
        Data:=FormMain.vstLog.GetNodeData(XNode);
        ts.Add(Data^.Name + ' - '+ Data^.Msg);
      Until XNode = FormMain.vstLog.GetLast();
      ts.SaveToFile(sdlgLog.FileName);
    finally
      ts.Free;
    end;
  end;

end;

// Datamodule Events defined here
procedure TdmVstLog.DataModuleCreate(Sender: TObject);
begin
  with FormMain.vstLog do begin
    NodeDataSize := SizeOf(TLogData);
    OnFreeNode := VSTFreeNode;
    OnGetText := VSTGetText;
    OnPaintText := VSTPaintText;
  end;
end;

end.

...

procedure RemoveSelectedNodes(vst:TVirtualStringTree);
begin
  if vst.SelectedCount = 0 then Exit;
  vst.BeginUpdate;
  vst.DeleteSelectedNodes;
  vst.EndUpdate;
end;

procedure RemoveAllNodes(vst:TVirtualStringTree);
begin
  vst.BeginUpdate;
  vst.Clear;
  vst.EndUpdate;
end;
于 2011-01-03T20:46:26.787 回答
1

获取VT Contributions包并查看虚拟字符串树的一些后代。那是在里面。我没有在项目中使用它们,但它们似乎使 Virtual String Tree 更易于使用。


这是我的入门入门:

我在使用 Virtual String Tree 之后发现,您可以充分利用它的唯一方法是实现 init 节点/子函数并设置根节点数,这与使用 ownerdraw 的列表视图非常相似:= 真的。

用 VirtualStringTree 做事很容易,你只需要实现获取文本函数和节点大小函数(将它设置为你想用作树后面数据的任何记录的大小)

我发现它几乎总是更容易做到 TVirtualTreeNodeRecordData = record Data : TVirtualTreeNodeData; end

并在 init 函数上创建数据对象。它为您创建指针,但您需要释放对象(同样,使用另一个删除节点回调)。

于 2011-01-03T20:51:35.367 回答