看了DELPHI deoms多线程,看的我非懂似懂的,自己做了个例子也不通!哪位大哥给个这样的例子,
在查询SQL同时,显示进度条!我知道可能用ADO的异步执行,当我这是存储过程,有大量的运算,

解决方案 »

  1.   

    ADO在取數據時進度是沒辦法控制的。
      

  2.   

    用 Delphi 写线程很简单啊,不知为何你的例子跑不通。TThread 的 Execute 只要一执行,线程就跑起来了。你可以在创建线程时把 Suspended 设成 False,也可以用 Resume 来启动 Execute。像你这种应用,线程一跑起来就不能停,得在 Execute 里设置一个死循环,终止条件是 Terminated = False。这样,只要从外部调用 TThread 对象的 Terminate,线程就停了。如果你把 TThread 对象的 FreeOnTerminate 设成 True,线程停止后还能自动释放。这样比较安全。假如 MyThread 是线程对象,大致写成如下样子:procedure MyThread.Execute;
    begin
      FreeOnTerminate := True;
      if not Assigned(OnNotify) then Exit;
      repeat
        Sleep(100);
        OnNotify(Self);
      until Terminated;
    end;其中,OnNotify 是一个事件,可以定义成 TNotifyEvent。也可以用 Synchronize 把它弄成同步调用,这样更安全些。Sleep 是为了不让线程连续调用 OnNotify 事件例程,以减少 CPU 占用,因为你的目的只是隔一段时间刷新一下进度指示。把处理过程都放到事件例程中,这样可样让程序结构清晰。你那些处理过程大约都要和窗口关联,不要把那些代码和线程弄到一起。如楼上所说,显示进度不一定非用线程。用线程的好处是:当某些代码迟迟不返回时,可以让线程显示点什么,说明没有死机。
      

  3.   

      with aa.create(pb1) do
      begin
        resume;
      end;
      Screen.Cursor := crSQLWait;
      qry1.Open;
      Screen.Cursor := crDefault;{Thread}
      constructor aa.create(p:TProgressBar);
         begin
           inherited create(True);
           pb:=p;
         end;procedure aa.Execute;
    var
      i:Integer;
    begin
      { Place thread code here }
      for i:=1 to 100 do
      begin
        Sleep(100);
         pb.Position:=i;
      end;
    end;我想在 qry1.Open;执行时让进度条一直是动的,好让用户知道正在计算,为什么还是qry1.open执行完了才执行 进程aa
      

  4.   

    给你个简单的多线程的例子,你自己看着改一下就行:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Pr1: TProgressBar;
        Pr2: TProgressBar;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      ABC:boolean;
    implementation{$R *.dfm}procedure NEW1_Thread;//线程1函数
    var
     i:integer;
    begin
    abc:=true;
    i:=1;
     while i<100 do
       begin
       if abc then   //如果abc为FALSE则中止滚动
          begin
            form1.Pr1.position:=i;
            sleep(10);
            i:=i+1;
          end;
       if i=100 then i:=1; //如果滚动条到达100,则再次从1开始滚动
       end;
    end;procedure NEW2_Thread;//线程2函数
    var
     i:integer;
    begin
     for i:=1 to 100 do
       begin
       //把下面两句换成你的查询语句
       form1.Pr2.position:=i; 
       sleep(100);            
       end;
     abc:=false;//进度条到达100,设置abc为FALSE
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
    c,d:DWord;
    begin
    CreateThread(nil,0,@New1_Thread,nil,0,c);
    CreateThread(nil,0,@New2_Thread,nil,0,d);
    end;end.此程序的效果是进度条1不断进行滚动(1~100),直到进度条2到达100;
    按照你的想法就是把进度条2的滚动代码换成你的查询语句就OK了;
      

  5.   

    刚才发现了一个问题,上面的代码需要改一下,因为按照上面那种方式,经过多次运行后发现程序的CPU占用会非常高,主要是由于线程没有进行结束的原因。把代码改成以下这样就行了:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Pr1: TProgressBar;
        Pr2: TProgressBar;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      a,b:Thandle;
    implementation{$R *.dfm}procedure NEW1_Thread;
    var
     i:integer;
    begin
    i:=1;
     while i<100 do
         begin
            form1.Pr1.position:=i;
            sleep(10);
            i:=i+1;
            if i=100 then i:=1;
       end;
    end;procedure NEW2_Thread;
    var
     i:integer;
    begin
     for i:=1 to 100 do
       begin
       form1.Pr2.position:=i;
       sleep(100);
       end;
     TerminateThread(a,0);  //结束线程
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
     c,d:DWord;
    begin
    if a<>0 then
        begin
             TerminateThread(a,0);
             a:=0;
        end;
    if b<>0 then
        begin
             TerminateThread(b,0);
             b:=0;
        end;
    a:=CreateThread(nil,0,@New1_Thread,nil,0,c);
    b:=CreateThread(nil,0,@New2_Thread,nil,0,d);end;procedure TForm1.FormCreate(Sender: TObject);
    begin
    a:=0;
    b:=0;
    end;end.
      

  6.   

     jiangfx2001 
    这个线程的定义怎么和书中介绍的不一样。我的那段代码为什么不行呢,错在哪!
    还是没换清楚。我在加分!还望有大虾们指点呀
      

  7.   

    看你的代码,线程中只是在改变一个变量的值,不知进度显示部分在哪里执行。如果是在主线程执行,那么这段代码是如何启动的呢?是从查询一开始就在那里循环吗?如果你的查询是同步函数,它必须得等到查询结束才能继续。这时线程可能已经在运行中,只是结果不能显示而已。你的线程要运行10秒钟才停止。查询需要多久呢?最好在线程中调用一个事件,在事件例程中显示进度。这样,显示是由线程来驱动的,它会和其他线程交错前进。你的程序需要这样改一下:procedure aa.Execute;
    var
      i:Integer;
    begin
      { Place thread code here }
      for i:=1 to 100 do
      begin
        Sleep(100);
        pb.Position:=i;
        if Assigned(OnDisplay) then OnDisplay(Self); // 调用事件例程显示进度
      end;
    end;这里的 Ondisplay 是一个 TNotifyEvent 事件,需要用一个事件例程地址给它赋值。
    线程有时也会暂停,那是由于线程优先级设得很低,被高优先级线程强占了 CPU 时间。
      

  8.   

    看你的代码,线程中只是在改变一个变量的值,不知进度显示部分在哪里执行。如果是在主线程执行,那么这段代码是如何启动的呢?是从查询一开始就在那里循环吗?如果你的查询是同步函数,它必须得等到查询结束才能继续。这时线程可能已经在运行中,只是结果不能显示而已。你的线程要运行10秒钟才停止。查询需要多久呢?最好在线程中调用一个事件,在事件例程中显示进度。这样,显示是由线程来驱动的,它会和其他线程交错前进。你的程序需要这样改一下:procedure aa.Execute;
    var
      i:Integer;
    begin
      { Place thread code here }
      for i:=1 to 100 do
      begin
        Sleep(100);
        pb.Position:=i;
        if Assigned(OnDisplay) then OnDisplay(Self); // 调用事件例程显示进度
      end;
    end;这里的 Ondisplay 是一个 TNotifyEvent 事件,需要用一个事件例程地址给它赋值。
    线程有时也会暂停,那是由于线程优先级设得很低,被高优先级线程强占了 CPU 时间。
      

  9.   


    15楼pb.Position:=i; 这句不就是显示进度吗
      

  10.   

    Ou, 没注意你那是个进度条。如果你确保线程在运行,那可能有两个原因:1. 你的线程被另一个超优先线程暂时挂起,因为你在调用查询。如果不调用查询能恢复正常,就可能是此原因。2. 代码确已执行,但控件没有 Refresh,所以进度条不向前走。线程有时不好跟踪。可以在循环里插入一个 beep 类的东西听响声。也许根本没响声或响一下就停了。