源码:

{*------------------------------------------------------------------------------
Virtual TreeView使用示例

@author 屈剑峰 email: qujianfeng@gmail.com
@version 2008/10/16 1.0 Initial revision.
@todo
@comment
-------------------------------------------------------------------------------}
unit Unit4;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, VirtualTrees, ImgList, Menus, AdvMenus;

type
{*------------------------------------------------------------------------------
首先,先自己定义一个结点所对应的数据结构。
这一般是一个结构体,内容根据你的需要自己定义
-------------------------------------------------------------------------------}
TMyRec=record
Text:string;//结点显示的文本
ImageIndex:Integer;//结点显示的图片索引。注意:要在结点显示图片必须TreeOptions.MiscOptions包含toCheckSuppot
Id:string;//数据Id,可以为数据库记录的Id
CheckType:TCheckType; //选择框类型
CheckState:TCheckState;//选择框状态
//...你还可以自己加
end;
{*------------------------------------------------------------------------------
定义一个上面结构体的指针类型,后面要用到这个东东
-------------------------------------------------------------------------------}
PMyRec=^TMyRec;

TForm4 = class(TForm)
vsttree: TVirtualStringTree;
il1: TImageList;
advpmn1: TAdvPopupMenu;
N1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure vsttreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
procedure vsttreeInitNode(Sender: TBaseVirtualTree; ParentNode,
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
procedure vsttreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean;
var ImageIndex: Integer);
procedure N1Click(Sender: TObject);
procedure vsttreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure vsttreeGetPopupMenu(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; const P: TPoint; var AskParent: Boolean;
var PopupMenu: TPopupMenu);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form4: TForm4;

implementation

{$R *.dfm}

procedure TForm4.FormCreate(Sender: TObject);
var
RootNode,ChileNode:PVirtualNode;
Data:PMyRec;
begin
//指定结点数据大小
vsttree.NodeDataSize:=SizeOf(TMyRec);
//指定树里要用的图片列表
vsttree.Images:=il1;

//添加根节点
RootNode:= vsttree.AddChild(nil);
Data:=vsttree.GetNodeData(RootNode);
Data^.Text:='根结点';
Data^.Id:='RootID';
Data^.ImageIndex:=0;
Data^.CheckType:=ctTriStateCheckBox;
Data^.CheckState:=csUncheckedNormal;


//添加一个子结点
ChileNode:=vsttree.AddChild(RootNode);
Data:=vsttree.GetNodeData(ChileNode);
Data^.Text:='子结点1';
Data^.Id:='ChildId1';
Data^.ImageIndex:=1;
Data^.CheckType:=ctTriStateCheckBox;
Data^.CheckState:=csUncheckedNormal;

//再添加一个子结点
ChileNode:=vsttree.AddChild(RootNode);
Data:=vsttree.GetNodeData(ChileNode);
Data^.Text:='子结点2';
Data^.Id:='ChildId2';
Data^.ImageIndex:=1;
Data^.CheckType:=ctTriStateCheckBox;
Data^.CheckState:=csUncheckedNormal;

//默认展开一级结点,这句话要写在初始的最后
vsttree.Expanded[RootNode]:=True;

{
注:在这里把数据添加进树后,树里并不能显示出结点
要在几个事件里写代码才行:
OnInitNode:在这个事件里初始化结点,如指定复选框以及状态
OnGetText:在这个事件里指定结点的显示文本
OnGetPopupMenu:在这个事件里指定下拉菜单
OnGetImageIndex:指定结点的图片索引
OnFreeNode:释放结点时您要做的一些释放动作

通过这些事件,才能把结点的显示情况描述清楚。而您的
结构体是用来持有您每个结点的数据的。
}
end;
//弹出菜单的点击事件
procedure TForm4.N1Click(Sender: TObject);
var
CurrentNode:PVirtualNode;
Data:PMyRec;
Checked:string;
begin
{示例取点击结点的数据。
注意:TreeOptions.SelectionOptions必须包含toRightClickSelect
}
//取得当前选中结点
CurrentNode:=vsttree.FocusedNode;
if Assigned(CurrentNode) then
begin
Data:= vsttree.GetNodeData(CurrentNode);
if CurrentNode.CheckState=csCheckedNormal then
begin
Checked:='是';
end
else
begin
Checked:='否';
end;
ShowMessage('当前结点:'+#13
+'Id='+Data^.Id+#13
+'Text='+Data^.Text+#13
+'是否选中='+Checked);
end;
end;

procedure TForm4.vsttreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
Data:PMyRec;
begin
Data:=Sender.GetNodeData(Node);
Finalize(Data^);
end;

procedure TForm4.vsttreeGetImageIndex(Sender: TBaseVirtualTree;
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
var Ghosted: Boolean; var ImageIndex: Integer);
var
Data:PMyRec;
begin
Data:=Sender.GetNodeData(Node);
ImageIndex:=Data^.ImageIndex;
end;

procedure TForm4.vsttreeGetPopupMenu(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; const P: TPoint;
var AskParent: Boolean; var PopupMenu: TPopupMenu);
begin
if Assigned(Node) then
begin
PopupMenu:=advpmn1;
end
else
begin
PopupMenu:=nil;
end;
end;

procedure TForm4.vsttreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var
Data:PMyRec;
begin
Data:=Sender.GetNodeData(Node);
CellText:=Data^.Text;
end;

procedure TForm4.vsttreeInitNode(Sender: TBaseVirtualTree; ParentNode,
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
Data:PMyRec;
begin
Data:=Sender.GetNodeData(Node);
Node.CheckType:=Data^.CheckType;
Node.CheckState:=Data^.CheckState;
end;

end.
http://wz.csdn.net/url/1314938/
TVirtualStringTree 的用法。
2007-10-07 16:59
***属性
    RootNodeCount 总数 , 与StringGrid的RowCount一样。
***方法
    Clear 清空全部node
    DeleteSelectedNodes 清空选择的行
    Invalidate 重新加载
   GetNodeDate() 取出节点的对象或结构,但在例子上好象采用的是结构比较多, NodedataSize =
sizeof(TReCode)
    ContentToHtml()另存为外部文件,这地方有unicode ,txt ,cvs, 就是没有xls的文件,如以后可能要增加这个功能。
    ComputeNodeHeight()这个方法可以设行高,但一直没有代码可以查看到。
   ValidateNode(ANode) 设ANode当前有效。
***事件
    OnStructureChange 生成form发生的事件。
    OnFocuseChangeed , OnFuncustChangeing 选择当前行发生的事件。
    OnGetText() 设置单元格内的字符内容。
    OnMeasureItem() 事件内有设置行高处理。
    OnPaintText() 设置显示的字体是怎么样的。可以处理不同行的显示内容。
    OnGetHint() 可以定到单元格显示浮动的提示内容。

例子:
          ChildCount[FocusedNode] := ChildCount[FocusedNode] + Count;
          Expanded[FocusedNode] := True;
          InvalidateToBottom(FocusedNode);

        Data.Caption := Format('Level %d, Index %d', [GetNodeLevel(Node), Node.Index]);

遍历节点方法:
var
      node : PVirtualNode;

      Result:= '';
      node := VT.RootNode;
      while Assigned(Node) do
      begin
         if node.CheckState in [ csCheckedNormal, csMixedPressed ] then
            Result := Result + IntToStr( Node.Index ) + ',';

         node := VT.GetNext(node);   //下一个.
      end;

还可以选择选择的内容:
     Node := VT.GetFirstSelected;   // GetFirstSelected 与 GetNextSelected(Node) 的做法。
      while Assigned(Node) do
      begin
         Result := Result + ',' + IntToStr( Node.Index );
【VirtualStringTree使用心得】
沈闻天 2006.05.27

(1) 这是一个可扩展到多层的树视图。视图就是单纯显示,无法与传入数据自动同步,必须手动写。
(2) 无论父节点还是子节点,传入数据必须是一个相同的结构(record),存放在其data属性里,通过“指针:=GetNodeData(节点)”获得地址,传入传出其“指针^.各结构属性”。
(3) 控件从RootNodeCount:=根节点数目大于0开始激发,立即激发onGetNodeDataSize,来获得传入结构数据的大小,此处可以返回sizeof(结构类型)。
(4) 然后对每个节点(包括已激发的子节点)进行OnInitNode,此处可以可以直接修改节点的属性,并用(2)的方法传入其data,以备以后调用。
(5) InitNode时,可以Include(InitialStates, ivsHasChildren)来说明含有字节点,但不会加载子节点。
如要加载,可以(1)界面直接双击打开,或者(2)代码Include(InitialStates, ivsExpanded)
亦可(3)直接调用ReinitChildren[父节点],(4)直接设置Sender.ChildCount[父节点],来加载。
此时会激发onInitChildren,事件中可以设置ChildCount,然后对每一个子节点,一一激发InitNode。
(6) 每个节点激发(InitNode)后,会激发GetText,用于显示文本。此处可以根据Column来分别返回CellText。
(7) 如果某个节点Checktype设为ctCheckbox,则该节点前会增加check框,其值通过CheckState设定。
(8) 【bug】如果同为ctCheckbox,父子节点的CheckState是不关联的,也就是说,点选父节点,下属子节点一个也不会改变选值。
如需同步,就要在onCheck中用代码实现。我在本unit内,实现了
(a)父节点选中,则全部子节点也选中
(b)子节点全部选中,则父节点也选中
©子节点全部选空,则父节点也选空
即使onChecked事件即使加入了父子节点Checked同步代码,因为InitNode时不加载Child,未扩展开的子节点是无法调用onChecked代码与父节点同步的。
所以千万注意InitNode时,要用Sender.ReinitChildren(Node,True);先履一遍字节点。
(9) VirtualStringTree各个事件内,许多Node参数不是“var”返回值的,所以对它们赋值于事无补。
如需要,最好使用“VirtualStringTree.各属性[节点]:=值”,具体值是否返回,可以查看VirtualStringTree源码。
(10)onGetImageIndex获得每个节点的图标,要搭配TImagelist控件;onGetHint获得每个节点的Hint。