有两个表:
主表:DictflMaster (fl_dalei) 大类25类
明细表:DictFlSlave(flmx_flh,flmx_flmc,flmx_top)明细纪录大约10万条
按主表大类分类,大类下放明细表小类。
现已经实现从sqlServer 库加载,只是速度太慢(50秒),(奔四、256MB、win2000 联想机)。
****************************************************
   如何更快加载Treeview呢?要求能够在1-5秒之内加载。
****************************************************源码如下:
------------------------------------------------------------------
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ComCtrls, Db, ADODB, Grids, DBGrids, Gauges, ExtCtrls;type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    Query: TADOQuery;
    TreeView: TTreeView;
    BitBtn1: TBitBtn;
    QueryTemp: TADOQuery;
    EditCount: TEdit;
    Gauge: TGauge;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.DFM}procedure TForm1.BitBtn1Click(Sender: TObject);
var
  TmpNode ,TmpNode1 : Ttreenode ;
  TmpNodeTxt ,TmpBegin,TmpEnd : string ;
  FlagLen ,i : integer ;
begin
  with Query do
  begin
    close ;
    sql.clear ;
    sql.add(' select * from  DictflMaster order by fl_dalei ');   // where fl_dalei like ''%a%''
    open ;
    TmpNode  := TreeView.Items.AddChild(nil,'档案类别') ;
    TmpNode1 := TmpNode ;
    first ;
    while not eof do
    begin
      TmpNode  := TreeView.Items.AddChild(TmpNode,Fieldbyname('fl_dalei').asstring) ;//头节点
      EditCount.text := '1' ; //初始为第一级
      TmpNodeTxt := Fieldbyname('fl_dalei').asstring ;//读取该夫接点名称
      TmpNodeTxt := copy(TmpNodeTxt,2,1) ; //换算为字母
      with QueryTemp do
      begin
        close ;
        sql.clear ;
        sql.add(format(' select count(*) tmpcount from DictFlSlave '
                      +' where flmx_flh like ''%s'' ',[TmpNodeTxt+'%']));
        open ;
        Gauge.MaxValue := fieldbyname('tmpcount').asinteger ;
        
        close ;
        sql.clear ;
        sql.add(Format(' select flmx_top,flmx_flh,flmx_flmc from DictFlSlave '
                      +' where flmx_flh like ''%s'' ORDER BY flmx_flh ',[TmpNodeTxt+'%']));
        open ;//读出头接点下的结果集;
        first ;//置顶;
        next ;
        while not eof do
        begin
          FlagLen := Fieldbyname('flmx_top').asinteger ;
          TmpBegin:= Fieldbyname('flmx_flh').asstring ;
          TmpEnd  := Fieldbyname('flmx_flmc').asstring ;
            if FlagLen = Strtoint(EditCount.text) then //如果等于上级接点级别,为同级
              TmpNode := TmpNode.Parent
            else if FlagLen < Strtoint(EditCount.text) then
            for i := 0 to Strtoint(EditCount.text) - FlagLen do  //如果小于上级接点级别,则循环找父级
              TmpNode := TmpNode.Parent ;
            TmpNode := TreeView.Items.AddChild(TmpNode,'['+TmpBegin+']'+TmpEnd) ;//写接点
            EditCount.text := inttostr(FlagLen) ;//记录上一接点的级别
            Gauge.Progress := Gauge.Progress + 1; 
          next ;
        end;
      end ;
      next ;
      TmpNode := TmpNode1 ;//返回最高级 ;
    end;
  end;
end;end.

解决方案 »

  1.   

    怎么最基础的BeginUpdate, endUpdate都不用啊?
      

  2.   

    楼上说的只能改变一时,不能全部啊
    10万条记录,你想想吧,网络传输也得有一会吧
    动态建树吧procedure TMDTreeView.BuildTreeDevice(Node: TTreeNode);
      function getSQL(Node: TTreeNode): string;
      begin
        result := 'SELECT TB1.ID,TB1.NAME,TB1.CODE';
        if Node = nil then
          result := result + ' FROM ' + FMasterTableName + ' TB1 WHERE TB1.PARENTID=-1'
        else
        begin
          result := result + ',TB1.Code  FROM ' + FMasterTableName + ' TB1 WHERE TB1.PARENTID=' + IntToStr(Node.StateIndex);
          if FMasterFilter >= 0 then
            result := result + ' AND TB1.CLASS=' + IntToStr(FMasterFilter);
          if FUseDispIndex then
            result := result + ' ORDER BY TB1.DISPINDEX'
          else
            result := result + ' ORDER BY TB1.ID';
        end;  end;
    var
      lNewNode: TTreeNode;
      lNode: TTreeNode;
      MDData: PMDData;
      str:String;
    begin
      str:=getSQL(node);
      clientDataset.Close;
      clientdataset.CommandText := getSQL(Node);
      clientDataset.Open;
      Items.BeginUpdate;
      while not ClientDataSet.Eof do
      begin
        new(MDData);
        lNewNode := Items.AddChild(Node, ClientDataSet.FieldValues['NAME']);
        MDData^.CODE := ClientDataSet.FieldByname('Code').AsString;
        lNewNode.Data := MDData;
        lNewNode.StateIndex := ClientDataSet.FieldValues['ID'];
        if lNewNode.Parent=nil then
            begin
            LNewNode.ImageIndex :=0;
            LNewNode.SelectedIndex :=0;
            end
            else
            begin
            lNewNode.ImageIndex := MasterStartImage;
            lNewNode.SelectedIndex := MasterStartImage;
         end;
        New(MDData);
        lNode := items.Addchild(lNewNode, 'newnode');
        lNode.Data := MDData;    ClientDataSet.Next;
      end;  items.EndUpdate;
      if items.Count =0 then
      begin
          //new(MDData);
          lNewNode := Items.AddChild(Node, '树');
          items.Addchild(lNewNode, 'newnode');
          lNewNode.StateIndex :=0;
      end;
      if Node = nil then
      begin
        Selected := lNewNode;
        Selected.Expand(false);
      end;
    end;
    用上面的动态的来吧,一层一层的来
      

  3.   

    发完了又看了一编,
    数据库是那位高人设计的啊,
    我的经验是少用like,本身就慢,另外,数据还是是 select * from 增加网络传输压力!3,10万条记录,什么也不错,从头到尾,移动得耗时多少?
    一会给你改造一下!等着!
      

  4.   

    lwk_hlj(阿凯(为双星努力)) :
    这位大哥,你觉得如何改造呢?
    在下洗耳恭听。
      

  5.   

    我的程序是C/S结构,局域网传输。不是B/S结构。
    主表DictFlMaster一共25条纪录,两个字段。
    明细表表结构:
    flmx_flh varchar (50) 主键
    flmx_flmc varchar(100)
    flmx_top int(2)
      

  6.   

    用第三方的VirtualTree组件
    很强的Google可以找到,速度很快的
      

  7.   

    个位都是星星级别的人物了,加载TTreeView怎么还是一次加载啊?
    这个控件中有一个OnExpanded和OnExpanding事件,各位怎么不用呢.
    首先加载根节点,其他不管,加入的时候设置Node的HasChild=true,
    在上面的OnExpandIng事件中在加载该节点的子节点,以此类推.没有必要一次加载嘛,
      

  8.   

    个位都是星星级别的人物了,加载TTreeView怎么还是一次加载啊?
    这个控件中有一个OnExpanded和OnExpanding事件,各位怎么不用呢.
    首先加载根节点,其他不管,加入的时候设置Node的HasChild=true,
    在上面的OnExpandIng事件中在加载该节点的子节点,以此类推.没有必要一次加载嘛,
      

  9.   

    先 Visible = False添加数据然后 Visible = True
    可以提高一定的速度。
      

  10.   

    同意xthmpro_cn
    的意见。
    UP
      

  11.   

    最近我也遇到同样的问题,解决的方法如下:
    判断用户是否在本计算机上第一次登录?
    Y:创建多层分类,以XML格式存放在Appliation path\users\username\category.xml
    N:
     读取Appliation path\users\username\category.xml,得到本地文件日期;
     从数据库中检索,判断是否有更新?
     Y:重新创建分类列表
     N:启动这样不是很适合分类改动特别大的程序。
    这样一来,第一次启动程序的时候会比较慢,以后的启动中,直接读取本地文件会快很多。
    至于数据库的设计,如下:
    CID int 
    CNAME varchar(80)
    PARENTID int读取是循环+递归xml文件片断如下:
    <?xml version="1.0" encoding="GB2312"?>
    <CateGory>
    <DateTag>
    2004-7-16 13:22:10.233
    </DateTag>
    <Tree>
    <!--Category tree-->
    </Tree>
    </CateGory>大概就是这样了,我只是提供了一个思路,具体的代码太长啦。
    顺便提一句,这些代码都是封装在一个TUserSession类中了。