Virtual Treeview使用要点

Virtual Treeview是一套Delphi下优秀的VCL控件,代码质量高,使用灵活、功能强大、性能非常好,可以用于表达Treeview和表格类数据。它的代码现在托管在google code上。

这套控件使用了很久了,非常满意其表现,之前一直使用V4版,现在V5正式发布了,新版花了几年时间进行重构, 代码结构更加合理,去除了老版大量的小缺陷,很多功能进行了重新设计,参与维护的人也更多了。

Virtual Treeview的设计思路与官方的Treeview完全不一样,VT是基于高性能和更丰富的表现而开发的,在上手方面比Treeview要慢一些,但一旦上手,就会发现非常好用。

在使用VT之前,就应该设计好以什么方式展示数据,每个节点应该有些什么属性。在构思好后,就可以按以下步骤来实现VT的使用了。

1、节点数据

在实际使用Virtual Treeview之前,应该先设计好一个节点数据的结构体,用于方便每个节点的展示。

比如一个典型的设计如下:

  PTreeData = ^TTreeData;
  TTreeData = record
    Level: integer;     // 节点级别:0根;1节点;2参数
    NodeType: integer;  // 节点类型
    Id: Integer;        // 数据id
    Caption: String;    // 节点标题
    obj : TObject;      // 节点对应的对象或空
  end;

其中Caption用于控制节点显示,Id用于方便节点对应数据的快速定位,obj用于把节点与相关的对象关联在一起,其它数据也是用于方便进行数据处理的。

2、列的处理

一般情况下,如果是只当成普通Treeview,无需考虑列(Column)的处理,直接使用即可。如果一行有多列数据需要显示,则得先在属性Header-Columns中增加所需的列,并设置合适的列宽。缺省列(Column)设置为空,列索引(TColumnIndex)应该为-1,在设置了列后,第一列的列索引为0,第二列的列索引为1。

3、第一个节点

在树中的所有节点中,只有根节点的父节点为空(nil)。创建根节点的示例代码如下:

var
  Data : PTreeData;
  Node: PVirtualNode;
  RootNode: PVirtualNode;

  vst.Clear;  // 清除所有节点
  vst.NodeDataSize := Sizeof(TTreeData);  // 设置节点数据大小
  RootNode := vst.AddChild(nil);   // 增加一个根节点
  vst.ValidateNode(RootNode, false);
  Data := vst.GetNodeData(RootNode);  // 获取节点数据
  Data.Caption := ‘根节点1‘;  // 设置将要显示在节点的文本信息

4、多级节点

创建完全根节点后,就可以在根节点后增加各级子节点了。

  Node := vst.AddChild(RootNode);  // 增加一级子节点
  data := vst.GetNodeData(Node);  //  获取节点数据
  data.Level := vst.GetNodeLevel(Node);  // 设置节点级别,方便后继处理
  Node := vst.AddChild(Node);       //  增加二级子节点
  data := vst.GetNodeData(Node);
  data.Level := vst.GetNodeLevel(Node);
  Node := vst.AddChild(RootNode);  //  再增加一个一级子节点
  data := vst.GetNodeData(Node);
  data.Level := vst.GetNodeLevel(Node);
  // 当然这里可以批量产生多个子节点,比如
  //  for i:=0 to 99 do
  //  begin  Node := vst.addchild(rootNode); ... end;
  vst.FullExpand(RootNode);  //  把根节点下的所有子节点打开

上面只是简单示例,完整示例中需要把节点数据都设置完整。

这里还有一种方式进行更高速的创建子节点,比如:

vst.ChildCount[RootNode] := 100;

这样,就可以一下给根节点设置100个一级子节点。当然,这些节点的数据都还是缺省状态,我们可以在适当的时候和适当的位置再进行设置。

如果我们需要一次插入多个节点,为了提高显示效率,我们应该在插入前调用BeginUpdate,在插入完成后再调用EndUpdate。

5、显示节点内容

运行后,可以发现树的确出来了,但所有节点显示的都是似乎"Node"字样的东西,怎么样把我们需要显示的内容显示出来?

我们需要设置Virtual Treeview的GetText事件,VT在显示节点信息时会调用GetText来获取要显示的内容。我们可以增加类似下面的代码:

procedure TfrmMain.vstGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  Data : PTreeData;
begin
  CellText := ‘‘;
  Data := vst.GetNodeData(Node);
  if not Assigned(Data) then
     exit;
  Case Data.Level of
  0:
    begin
      CellText := Data.Caption;
    end;
  1:
    begin
      CellText := format(‘一级子节点‘,[]);
    end;
  2:
    begin
      CellText := format(‘二级子节点‘,[]);
    end;
  end;
end;

当然,实际代码要复杂的多。而且这个代码并没有处理多列的情况,如果有多列就得针对各列再加一级case语句就可以了。也就是说类似这样的代码,假设我们设置了一个节点有三列:

procedure TfrmMain.vstGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  Data : PTreeData;
begin
  CellText := ‘‘;
  Data := vst.GetNodeData(Node);
  if not Assigned(Data) then
     exit;
  Case Column of
  0:  // 第一列的处理
    begin
      Case Data.Level of
      0:
        begin
          CellText := Data.Caption;
        end;
      1:
        begin
          CellText := format(‘一级子节点‘,[]);
        end;
      2:
        begin
          CellText := format(‘二级子节点‘,[]);
        end;
      end;

    end;
  1:  // 第二列的处理
    begin
      // 一般是取Data中obj对象,再取其中的数据用于处理显示
    end;
  2:  // 第三列的处理
    begin
      // 一般是取Data中obj对象,再取其中的数据用于处理显示
    end;
  end;
end;

也就是说vst各节点的内容,其实都是通过代码来控制并设置的。无论是Treeview形式还是表格形式或两者综合体,数据的显示都是这么处理的。

5、节点图标

经常我们需要在每个节点前加个小图标,可用于表达这个节点的状态、类型或纯美观。Virtual Treeview显示图标一样也是要与TImageList配合使用的。我们需要先在一个ImageList中加载上合适的所有图标,然后在GetImageIndex事件中进行判断处理每个节点应该使用的图标的索引来加载ImageList中的图标。

比如:

procedure TfrmMain.vstGetImageIndex(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: Integer);
var
  Data : PTreeData;
begin
  Data := vst.GetNodeData(Node);
  if not Assigned(Data) then
     exit;
  Case Data.Level of
  0:
    begin
      ImageIndex := 2;
    end;
  1:
    begin
      ImageIndex := 0;
    end;
  2:
    begin
      ImageIndex := 0;
    end;
  end;
end;

6、节点数据空间的清理

在Virutal Treeview组件释放时,我们应该同时清理掉每个节点对应的数据空间。我们应该在FreeNode事件中写上以下类似的代码来完成这个工作:

procedure TfrmMain.vstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var Data : PTreeData; begin Data := vst.GetNodeData(Node); if Assigned(Data) then begin Data.Caption := ‘‘; // String must be cleaned manual, otherwise there is memory leak // 节点数据记录中对应的数据对象,不一定得在这释放,可以在其它地方统一处理 //FreeAndNil(Data.obj);
end; end;

节点数据空间不需要我们释放,在前面对vst初始化时写过这么一句代码:

vst.NodeDataSize := Sizeof(TTreeData);  // 设置节点数据大小

这里就是初始化节点数据记录空间的,这个空间会被vst自动释放。但这个记录体中的类似字符串或指针所指向的内存空间或对像是不会被自动释放的。所以,这里我们把Data.Caption字符串清空,以避免内存泄漏。

时间: 2024-08-02 07:08:15

Virtual Treeview使用要点的相关文章

Virtual Treeview - Paint cycles and stages

The most complex process in Virtual Treeview is without doubts its painting. Read here what stages Virtual Treeview enters during paint and how you can customize this process. Description Similar to the system tree view Virtual Treeview defines so ca

C/C++技术常用网站

软件下载网站[visual studio 2005编译器] http://www.xdowns.com/ debug调试大牛 http://blogs.msdn.com/oldnewthing/ http://blogs.msdn.com/lixiong/ 绝版图书淘宝站: http://shop59563940.taobao.com/ www.vckbase.com www.codeproject.com http://www.acejoy.com --- ace 网站 http://www.

Delphi与字符编码(实战篇)(MultiByteToWideChar会返回转换后的宽字符串长度)

本文目标: 了解Delphi的字符串类型 字符编码的检测与转换 简体繁体转换 0. 导言 看完“.Net与字符编码(理论篇)”,我们明白了字符是自然语言中的最小单位,在存储和传输的过程中可以使用三种编码方法:ASCII.DBCS以及Unicode.常见的DBCS编码有GB2312.GBK和BIG5,而UTF-8.UTF-16和UTF-32则是最常用的Unicode编码类型. 1. 字符串类型 在Delphi中有两种字符串类型:AnsiString和WideString.AnsiString被称为

Windows应用程序高级控件之TreeView

TreeView控件--树控件 为用户显示节点层次结构,每个节点又可以包含子节点. 添加和删除树节点 添加--TreeView的Nodes属性的Add方法:public virtual int Add(TreeNode node) 删除--TreeView的Nodes属性的Remove方法:public void Remove(TreeNode node) 添加-实例代码: private void Form1_Load(object sender, EventArgs e) { //为树控件建

C#反射技术概念作用和要点

反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的名称.限定符和参数等.有了反射,即可对每一个类型了如指掌.如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道. 1..NET可执行应用程序结构 程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构. 应用程序结构分为应用程序域—程序集—模块—类型—成员

WPF 自定义列表筛选 自定义TreeView模板 自定义ListBox模板

有很多项目,都有数据筛选的操作.下面提供一个案例,给大家做参考. 左侧是数据源,搜索框加TreeView控件,右侧是ListBox控件.在左侧数据列点击添加数据,然后点击确定,得到所筛选的数据. 下面直接看代码吧,比较好理解~ 筛选控件做成用户控件,当然也可以直接放在主界面,如果不复用的话.数据源都是固定的,实际用的话,新建个ViewModel将数据源绑定就行了. 1.筛选控件界面: <UserControl x:Class="WpfApplication17.SelectControl&

虚拟互换(virtual swap)

虚拟互换(virtual swap) 经济学中的互换(Swap)指的是这么一个东西:有2个交易方A.B需要进行跨国交易,各自都需要另外一个国家的某个商品,他们本来可以通过标准的汇率到各自国家的银行办理外币兑换,然后再到国外去采购什么的,所谓的Swap就是不需要这么做,直接以物物交换的等价原则,同时为对方购买,然后发出货物即可. 实际上这里的货物并不需要是实物,可以是虚拟的某种权利,互换实际上潜在地降低了交易费用(但有时双方不能直接建立信任关系的话,就要通过第三方监管,这样代价可能又变大了),并且

helloworld讲解cocos2d-x的编程思路与要点

用helloworld讲解cocos2d-x的编程思路与要点 本文以cocos2d-x的helloworld为例,讲解cocos2d-x引擎的特点和要点,2.2为了展示新功能,把包括屏幕自适应在内的新特性相关代码加入了helloworld工程代码里,但是也增加新人的上手难度,我会避过不谈,只说关键的几句代码,对于已经了解cocos2d-x架构的朋友,本文后面的内容对你毫无帮助,可以去关注我写的<cocos2d-x提高篇>(不过此刻我或许还没写).当然了,不可能一开始就把所有内容说清楚,刚上手的

Delphi Treeview 操作实例

怎么改变Treeview中的图标? OnClick事件Click获取Node.text 批量处理及实现TreeView结点拖拽的实例 //这个过程根据你的要求选择图标procedure TForm1.TreeView1GetImageIndex(Sender: TObject; Node: TTreeNode);begin  if Node.HasChildren then      if Node.Expanded then          Node.ImageIndex := 3   //