我正在尝试使用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?
谢谢!
答案 0 :(得分:11)
为什么不在虚拟模式下使用列表视图?这看起来和感觉都很正确并且表现很好。
Delphi TListView控件是Windows列表视图组件的包装器。在默认操作模式下,列表数据的副本将从您的应用程序传输到Windows控件,这很慢。
此替代方案称为Windows术语中的虚拟列表视图。您的应用程序未将数据传递给Windows控件。相反,当控件需要显示数据时,它会向您的应用询问所需的数据。
Delphi TListView控件使用OwnerData属性公开虚拟列表视图。你必须稍微重新编写列表视图代码,但这并不太难。
我还提供了另一个question的链接,其中包含类似的内容。相当奇怪的是,该问题的公认答案谈到了列表框,即使问题是列表视图控件。
答案 1 :(得分:6)
使用VirtualStringTree它比简单的TListView复杂一点,但是这是一个非常简单的教程,我已经创建了一段时间,如何使用VirtualStringTree http://www.youtube.com/watch?v=o6FpUJhEeoY我希望它有所帮助,欢呼!
答案 2 :(得分: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日志显示的代码。我将所有代码保存在datamodule中,只需使用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;
答案 3 :(得分:4)
只需使用普通的TListView,但在虚拟模式中使用它。
这很简单:
OwnerData
属性设置为true
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;
这就是全部!
要记住的一些事情:
答案 4 :(得分:1)
获取VT Contributions包并查看虚拟字符串树的一些后代。那是在那里。我没有在项目中使用它们,但它们似乎使虚拟串树更容易使用。
尽管如此,这是我的入门指南:
我发现在使用虚拟字符串树之后,你可以充分利用它的唯一方法是实现init节点/子函数并设置根节点数,这与你的列表非常相似使用ownerdraw查看:= true。
使用VirtualStringTree很容易做到,你只需要实现get text函数和节点大小函数(将它设置为你想用作树后面数据的任何记录的大小)< / p>
我发现它几乎总是更容易做到
TVirtualTreeNodeRecordData = record
Data : TVirtualTreeNodeData;
end
并在init函数上创建数据对象。它为您创建指针,但您需要释放对象(再次使用另一个删除节点回调)。