难搞,偶搞了几天了。。情况是这样的:1.主窗体有一个Treeview树。
2.这个树要加载无限下级的部门数据。
3.由于要连到远程SQL,网速慢时显示这个主窗口时假死很久。
4.请问,如何改进这个读取的函数才能假死?
5.要实例代码谢了
部门表结构:
did    Dname   ParentID   Leave  
----- ------- -------- -----------
01 北京公司0 1
0101 市场部 01 2
010101 信息部 0101 3
02 上海公司0 1
0201 业务部 02 2
0202 售后部 02 2
03 深圳公司0 1
0301 生产部 03 2
0302 实验室 03 2
//读取树部门数据的函数
procedure TMainForm.ReadTree(tnode:TTreeNode;Fvalue: String);
Var
i: integer;
Flist:TStringList;
Flist1:TStringList;
str,s:string;
    snode:TTreeNode;
begin
qryTree.close;
qryTree.sql.clear;
qryTree.sql.add('select did,dname,Parentid from depart where isnull(Parentid,'''')='''+Fvalue+''' ');
qryTree.Open;
qryTree.First;
Flist:=TStringList.Create;
Flist1:=TStringList.Create;
while not qryTree.eof do
    begin 
       Flist.Add(trim(qryTree.fieldbyname('dname').asstring));
       Flist1.Add(qryTree.fieldbyname('did').asstring);
       qryTree.next;
    end;
    
    for i:= 0 to flist.Count-1 do
    begin
       s:=flist1.Strings[i];
       str:=flist.Strings[i];
       snode:=Treeview1.items.addchild(tnode,str);
       ReadTree(snode,s);
    end;
flist.free;
flist1.free;
end;

解决方案 »

  1.   

    //调用方法ReadTree(RootNode1,'0');
      

  2.   

    可以用线程,写一条TThread类,在里面做这个事情
      

  3.   

    不要一次性的读取整个tree
    第一次只要显示tree的第一级,在tree的OnExpanded事件中再来显示下级。
      

  4.   

    其实是你的query读数据的时候造成主界面没有响应
    把你的query加载数据的过程放到一个线程里就可以了
    给你写了个小例子
    最好去看看一下多线程的东西
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, IdFTP, IdBaseComponent, IdComponent, IdTCPConnection,
      IdTCPClient, IdHTTP, DB, ADODB, StdCtrls, ActiveX;// 读取数据的线程
    type
      TReadDataThread = class(TThread)
      private
        // 线程执行代码
        procedure Execute; override;
      end;
    type
      TForm1 = class(TForm)
        qryTree: TADOQuery;
        Memo1: TMemo;
        Button1: TButton;
        ADOConnection1: TADOConnection;
        procedure Button1Click(Sender: TObject);
      private
        ReadDataThread: TReadDataThread ;
        procedure RdThreadterminate(Sender: TObject);
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}{ TReadDataThread }procedure TReadDataThread.Execute;
    begin
      inherited;
      // 在线程执行代码里写数据的数据读取过程
      CoInitialize(nil);
      with Form1.qryTree do
      begin
        sql.Text := 'Select top 1000000 * from groupuserinfo';
        Open;
      end;
      CoUninitialize ;
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      // 创建线程,创建为挂起状态
      ReadDataThread := TReadDataThread.Create(True);
      // 线程结束自动释放
      ReadDataThread.FreeOnTerminate := true;
      // 线程结束时在主进程调用的方法(通俗说该事件通知主进程线程结束,内容读取完毕)
      ReadDataThread.OnTerminate := RdThreadterminate;
      // 唤醒线程,使线程开始执行
      ReadDataThread.Resume ;
    end;procedure TForm1.RdThreadterminate(Sender: TObject);
    begin
      // 数据库读取结束后显示数据
      qryTree.First ;
      while not qryTree.Eof do
      begin
        Memo1.Lines.Add(qrytree.fieldbyname('qqname').AsString);
        Application.ProcessMessages ;
        qryTree.Next ;
      end;
    end;end.
      

  5.   

    1、你的数据中已经可以按照did来初始化树了,不必使用递归,did长度是有限制的,即每级占2位,使用一个循环即可初始化完毕:
    (1)取数据时必须按照did排序
    (2)循环数据集:
    var
      ParentNode: TTreeNode;
      ChildNode: TTreeNode;
    while not Qry.Eof do
    begin
      case Length(Qry.FieldByName('did').AsString)/2 of
        1:    //第一级
           begin
            ParentNode := TreeView1.Nodes.Add(nil, ...);
          end;
        2:    //第二级
           begin
            ChildNode := TreeView1.Nodes.Add(ParetNode, ...);
          end;
        3:
           begin
            ChildNode := TreeView1.Nodes.Add(ChildNode, ...);
          end;
        4:
           begin
            ChildNode := TreeView1.Nodes.Add(ChildNode, ...);
          end;
         ...(此处省略)
      end;
      
    end;只是思路,没有上级环境,请自己完善之,此法速度最快,事件复杂性为O(n)。
    2、如果一定要使用递归,请使用数据集的Filter属性,不要每次调用都去服务器取数据,Filter一下比去服务器取一次数据要快很多的;
      

  6.   


    其实问题就在于网速。。如果网速够快的话就不会那样。。因为是ADSL外网连到公网上的SQL服务器有没办法,先下载数据集到本地,再计算?现在就是要多次的进行远程连接SQL,速度这样吗?另,Fitter这个属性如何实现这种查询吗?
      

  7.   

    所以把连接SQL取数据的内容写在这个小线程里就最好了
      

  8.   

    首先,取所有的记录到本地内存——这个如果卡,只能用过线程以背景方式去取
    然后是根据内存里的记录生成树的节点——这个应该不会太慢,如果采用了   TV.Items.BeginUpdate; ... TV.Items.EndUpdate;