VirtualTreeview的强大,毋庸置疑,不过,你能给演示演示,也不错,就是刚下来,只有一个可执行程序,感觉像病毒。

最近比较忙,没有上网,现在把我研究的结果和大家通报下,方便新手学习,避免走弯路和浪费时间。

我用到的功能粗略的研究了下,以下是我测试的结果,可能和高手的结果不同,请不要鄙视。

首先说一下速度问题,只有一列数字分组或者不分组,都很快,但是,我用的是十几个字段,并且好几个字段是很多汉字的,一共有 5 万多条记录。如果用 OnIniNode 事件,不分组大约 5 秒左右加载完成,分组要 50 秒,我怀疑是我分组的问题。但我都是一次把所有数据都取出来,再分的组,不知道什么原因,因为时间原因,我没有仔细分析。用传统方法分组,大约 15 秒左右加载完成。我自己觉得可以忍受了,没有再改,下面是我用到的功能的代码,点击列头排序我没有用到,但是感觉有用,也贴上了,代码比较乱,有问题可以问我,等几天再结贴。有不正确的或者补充的功能,请帖出来。

1、数据加载,没有分组的,需要分组,可以自己加条件,这个主要是为了说明怎么用传统方法加载数据,为了明晰清楚,所以,只有一个字段。
(1)、设集合指针
    PFAName_Rec = ^TFAName_re;

TFAName_re = record
        FAName: string;                 //方案名称
(2)、开始加载
    p_tree.Clear;
    p_tree.NodeDataSize := SizeOf(TFAName_re);

p_tree.BeginUpdate;
    RootNode := p_tree.AddChild(nil);
    Data := p_tree.GetNodeData(RootNode);
    
    while not Form_main.ADOQTest.Eof do
    begin
        if stop_thread then
            exit;

Data.FAName := Form_main.ADOQTest.FieldByName('FAName').AsString;
        Form_main.ADOQTest.Next;
    end;
    p_tree.EndUpdate;

2、显示事件,加载数据后,要显示必须在这个事件中加入显示的代码
procedure TForm_485.FA_TreeGetText(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
    var CellText: WideString);
var
    Data            : PFAName_Rec;
begin
    Data := Sender.GetNodeData(Node);

case Column of
        0:
            begin
                if Data^.FAName <> '' then
                    CellText := Data^.FAName;
            end;
    end;
end;

3、显示图标,虽然没什么大用,但是很美观
procedure TForm_485.Wait_Send_TreeGetImageIndex(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
    var Ghosted: Boolean; var ImageIndex: Integer);
var
    wait_send_rec   : P_wait_send_Rec;
begin
    if Column <> 2 then
        exit;
    wait_send_rec := Sender.GetNodeData(Node);

ImageIndex := wait_send_rec.is_send - 1;
end;

4、相邻行不同颜色
procedure TForm_485.Wait_Send_TreeBeforeItemErase(Sender: TBaseVirtualTree;
    TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
    var ItemColor: TColor; var EraseAction: TItemEraseAction);
begin
    if Odd(Node.Index) then
    begin
        //        ItemColor := $FFEEEE;

ItemColor := $00F7F7F7;
        EraseAction := eaColor;
    end;
end;

5、拖放,没什么大用的功能,某些地方很有用,用按钮或菜单实现一样。
   拖放需要加载 ActiveX 单元才行,否则会报错
(1)、  源控件事件  
procedure TForm_485.All_item_TreeMouseDown(Sender: TObject; Button:
    TMouseButton;
    Shift: TShiftState; X, Y: Integer);
begin
    if Button = mbLeft then
    begin
        if All_item_Tree.FocusedNode = nil then
            exit;
        if All_item_Tree.FocusedNode.ChildCount > 0 then
            exit;
        All_item_Tree.BeginDrag(False);
    end;
end;
(2)、目标事件1
procedure TForm_485.Wait_Send_TreeDragOver(Sender: TBaseVirtualTree;
    Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint;
    Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
begin
    if (Source = All_item_Tree) or (Source = Wait_Send_Tree) or (Source =
        Often_item_Tree) or (Source = FA_Tree) then
    begin
        Accept := true;
    end;
end;
(3)、目标事件2
procedure TForm_485.Wait_Send_TreeDragDrop(Sender: TBaseVirtualTree;
    Source: TObject; DataObject: IDataObject; Formats: TFormatArray;
    Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode);
var
    Data            : PFAName_Rec;
begin
    cur_send_Meter_addr := trim(Edit8.Text);
    cur_send_Meter_count := 1;

if (Source = All_item_Tree) then
    begin
        r(All_item_Tree);
    end;

if (Source = Often_item_Tree) then
    begin
        r(Often_item_Tree);
    end;

if (Source = Wait_Send_Tree) then
    begin
        move_item(Shift, Effect, Mode);
    end;

if (Source = FA_Tree) then
    begin
        if FA_Tree.FocusedNode = nil then
            exit;

Data := FA_Tree.GetNodeData(FA_Tree.FocusedNode);

get_FA_item(Data.FAName, Wait_Send_Tree);
    end;
end;

6、编辑数据,这个我感觉很实用
(1)、事件1
procedure TForm_485.Wait_Send_TreeEditing(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
begin
    if Column in [4..8] then
        Allowed := true;
end;
(2)、事件2
procedure TForm_485.Wait_Send_TreeDragAllowed(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
begin
    Allowed := Odd(Node.Index);
end;
(3)、事件3
procedure TForm_485.Wait_Send_TreeNewText(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex; NewText: WideString);
var
    wait_send_rec   : P_wait_send_Rec;
    str_meter_addr  : string;
begin
    wait_send_rec := Sender.GetNodeData(Node);

case Column of
        4:
            begin
                if trim(wait_send_rec.str_czy) = trim(NewText) then
                    exit;
                if length(trim(NewText)) <> 12 then
                    exit;

wait_send_rec.metter_addr := NewText;

if CheckBox3.Checked then
                begin
                    //保存到数据库
                    post_item_mrz('BiaoDZ', wait_send_rec.GuiYBS, NewText);
                end;

end;
     end;
end;

7、显示提示,作用不大,有胜于无的功能
procedure TForm_485.Wait_Send_TreeGetHint(Sender: TBaseVirtualTree;
    Node: PVirtualNode; Column: TColumnIndex;
    var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: WideString);
begin
    case Column of
        0: HintText := '第一列提示';
        2: HintText := '第三列提示';
        3: HintText := '第四列提示';
    end;
end;

8、点击列头排序,个人感觉非常有用的功能,但是我的程序中没有用到,所以,把我找到的代码贴上了,供大家参考。
procedure TfrmMain.vCustomerTreeHeaderClick(Sender: TVTHeader;
  Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
if Button = mbLeft then
  with Sender do
    begin
    if SortColumn <> Column then
       SortColumn := Column;
    if SortDirection = sdAscending then
       SortDirection := sdDescending
    else SortDirection := sdAscending;
    vCustomerTree.SortTree(Column,SortDirection,true);
    // BIG NOTE ! ... the "DoInit" variable MUST be set to true,
    // otherwise you are ONLY sorting on nodes that have already
    // been initialised - this can cause some interesting sorts !
    end;
end;

9、查找数据,我的代码比较多,看着可能不清晰,这是别人写的例子,应该容易理解点,我在前面调用了2个方法,第一个是取消原来的选择,第二个是收起节点,主要为了找到节点后展开找到的节点。这个例子中没有对找到的节点进行处理的代码,例如,选择找到的节点,展开找到的节点等。自己加吧,不难的。
(1)、之前的方法
    All_item_Tree.ClearSelection;
    All_item_Tree.FullCollapse();

(2)、调用方式
PNode := FindChild(Controltree,Controltree.RootNode,EMPID);
(3)、递归的查找方法
function FindChild(Sender: TBaseVirtualTree; hParent: PVirtualNode; EMPID: integer): PVirtualNode;
var
  llhChild: PVirtualNode;
  Data: PEntry;
begin
  Result := nil;

llhChild := hParent.FirstChild; //获取hParent的第一个子节点
  while Assigned(llhChild) do begin
    Data := Sender.GetNodeData(llhChild);
    if (Data.Kind = nkEmployee) and (Data.ID = EMPID) then begin
       Result := llhChild;
       Exit;
    end;

{对llhChild节点进行处理}
    Result := FindChild(Sender, llhChild, EMPID);
    if Result <> nil then Exit;
    llhChild := llhChild.NextSibling;
  end;

end;

10、MoveTo 使用方法,可以在不同的两个树中拖动,好像必须两棵树的结构一致,我只使用了在同一颗树中移动的功能。这个方法在拖动(DragDrop)事件中调用,按 Ctrl 是复制,其他是移动

procedure TForm.move_item(Shift: TShiftState; var Effect: Integer; var Mode:
    TDropMode);
    procedure DetermineEffect;
    begin
        if Shift <> [] then
        begin

if (Shift = [ssAlt]) or (Shift = [ssCtrl, ssAlt]) then
                Effect := DROPEFFECT_LINK
            else if Shift = [ssCtrl] then
                Effect := DROPEFFECT_COPY
            else
                Effect := DROPEFFECT_MOVE;
        end;
    end;

var
    Attachmode      : TVTNodeAttachMode;
    Nodes           : TNodeArray;
    i               : integer;
begin

case Mode of
        dmAbove:
            AttachMode := amInsertBefore;
        //    dmOnNode:
        //      AttachMode := amAddChildLast;
        dmOnNode:
            AttachMode := amInsertAfter;
        dmBelow:
            AttachMode := amInsertAfter;
    else
        AttachMode := amNowhere;
    end;

DetermineEffect;
    Nodes := Wait_Send_Tree.GetSortedSelection(True);
    if Effect = DROPEFFECT_COPY then
    begin
        for I := 0 to High(Nodes) do
            Wait_Send_Tree.CopyTo(Nodes[I], Wait_Send_Tree.DropTargetNode,
                AttachMode, False);
    end
    else
        for I := 0 to High(Nodes) do
            Wait_Send_Tree.MoveTo(Nodes[I], Wait_Send_Tree.DropTargetNode,
                AttachMode, False);

//   Wait_Send_Tree.mo
end;

virtualtree 的使用(Delphi)的更多相关文章

  1. 学习笔记:7z在delphi的应用

    最近做个发邮件的功能,需要将日志文件通过邮件发送回来用于分析,但是日志文件可能会超级大,测算下来一天可能会有800M的大小.所以压缩是不可避免了,delphi中的默认压缩算法整了半天不太好使,就看了看 ...

  2. delphi连接sql存储过程

    针对返回结果为参数的 一. 先建立自己的存储过程 ALTER PROCEDURE [dbo].[REName] ) AS BEGIN select ROW_NUMBER() over(order by ...

  3. delphi 2010与delphi XE破解版的冲突

    在系统中同时安装了Dephi 2010LITE版与Delphi XE lite后,总是会有一个有问题 是因为两者都是读取C:\ProgramData\Embarcadero目录下的license文件, ...

  4. [Delphi] Delphi版本号对照

    VER300    Delphi Seattle / C++Builder Seattle    23    230    (Delphi:Win32/Win64/OSX/iOS32/iOS64/An ...

  5. delphi tidhttp 超时设置无效的解决方法

    现在delphi都发布到xe8了,tidhttp还有缺陷,那就是超时设置在没有网络或者连不上服务器的时候是无效的,不管你设置为多少都要10-20秒.connectTimeout和readTimeout ...

  6. Delphi Code Editor 之 编辑器选项

    Delphi Code Editor 之 编辑器选项 可从Code Editor的右键菜单中选择“Properties”菜单项来查看编辑器选项.也可以从主菜单[Tools | Editor Optio ...

  7. Delphi使用ADO进行数据库编程

    Delphi是一个可视化的编程工具,ADO编程也是这样,所以话不多言,直接通过代码.截图和语言来说明. 我的数据库是Oracle,为了测试,先建一个表:create table practice(un ...

  8. 怎么使用Delphi获取当前的时间,精确到毫秒

    先介绍一个可能比较常用的方法,获取当前时间 var datetime: string; begin datetime:= FormatDateTime('yyyy-mm-dd hh:mm:ss', N ...

  9. Delphi在创建和使用DLL的时候如果使用到string,请引入ShareMem单元

    当使用了长字符串类型的参数.变量时,如string,要引用ShareMem. 虽然Delphi中的string功能很强大,但若是您编写的Dll文件要供其它编程语言调用时,最好使用PChar类型.如果您 ...

随机推荐

  1. 【matlab】随意记录

    v = -0.5:0.05:0.5; [x, y] = meshgrid(v); z = sqrt(1.0 - x.^2 - y.^2); mesh(x,y,z); 画一个球的一部分: 2. 求cel ...

  2. osg::NodeVisitor中计算一个节点对应的世界变换矩阵、法向量、顶点坐标

    class MyNodeVisitor:public osg::NodeVisitor { pulic: MyNodeVisitor():osg::NodeVisitor(osg::NodeVisit ...

  3. 关于Cookie和Session的优缺点

    关于Cookie和Session的优缺点 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. Cookie的优缺点:优点:极高的扩展性和可用 ...

  4. jsdoc文档

    官网文档:http://usejsdoc.org/index.html一个比较全的jsdoc示例 /** * @fileoverview 文件上传队列列表显示和处理 * @author 水车 **/ ...

  5. T4模板

    T4,即4个T开头的英文字母组合:Text Template Transformation Toolkit. T4文本模板,即一种自定义规则的代码生成器.根据业务模型可生成任何形式的文本文件或供程序调 ...

  6. 常用shell命令操作

    1.找出系统中所有的*.c 和*.h 文件 (-o 或者) $find / -name "*.cpp" -o -name "*.h" 2.设定 eth0 的 I ...

  7. Swift - 推送之本地推送(UILocalNotification)

    // 本地推送通知是通过实例化UILocalNotification实现的.要实现本地化推送可以在AppDelegate.swift中添加代码实现,本事例是一个当App进入后台时推送一条消息给用户. ...

  8. Clr Via C#读书笔记----基元线程同步构造

    线程文章:http://www.cnblogs.com/edisonchou/p/4848131.html 重点在于多个线程同时访问,保持线程的同步. 线程同步的问题: 1,线程同步比较繁琐,而且容易 ...

  9. WCF分布式开发必备知识(1):MSMQ消息队列

    本章我们来了解下MSMQ的基本概念和开发过程.MSMQ全称MicroSoft Message Queue,微软消息队列,是在多个不同应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一 ...

  10. poj 2262【素数表的应用---判断素数】【哈希】

    Goldbach's Conjecture Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 35214   Accepted: ...