我的程序意图很简单,就是form1的界面多个listbox(记录下线程曾经获得的值),和2个edit(分别给起始值和终点值)。噢,有个遗漏就是:还有个执行按钮,吼吼unit Unit2;interfaceuses
  Classes,SysUtils;type
  myFun = class(TThread)
  private
    { Private declarations }
    FStartID,FEndID: Integer;         //定义变量?  和FStartID之间存在某种不正当关系?
    procedure UpdateList;             //定义自己的更新UI函数  protected
    procedure Execute; override;
  public
    property StartID:Integer read FStartID write FStartID;    //定义类的属性StartID ?
    property EndID:Integer read FEndID write FEndID;          //定义类的属性EndID ?
  end;implementation
uses Unit1,Dialogs;//--------好像必须引用Unit1,否则Form1.Listbox1.Items报错 ? 我看笑青天兄弟给人留的代码,就灭有引用,偶不明白究理
{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure myFun.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }{ myFun }procedure myFun.UpdateList;
begin
  case StartID mod 3 of
    1:
      begin
        Form1.Listbox1.Items.Add(IntToStr(FStartID));
        Form1.ListBox1.ItemIndex := Form1.ListBox1.Items.Count - 1;
      end;
    2:
      begin
        showmessage(IntToStr(FStartID));
        Unit1.Form1.Listbox2.Items.Add(IntToStr(FStartID));
        Unit1.Form1.ListBox2.ItemIndex := Unit1.Form1.ListBox2.Items.Count - 1;
        Form1.Edit3.Text := IntToStr(FStartID);
        Unit1.Form1.ListBox2.Refresh;
      end;
  end;
end;procedure myFun.Execute;
begin
  { Place thread code here }
  FreeOnTerminate:=True;  FStartID := StartID;
  while FStartID < EndID do
  begin
    //执行代码
    Synchronize(UpdateList);
    FStartID := FStartID + 100;
  end;end;end.调用线程的代码implementationuses Unit2;//-------------------好像也必须引用,否则myFun.create出错?
{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
var
  Test:myFun;
begin  Test := myFun.Create(True);//创建一个线程,若有多个线程,依次创建
  Test.StartID := StrToInt(Edit1.Text );  //起始值给23
  Test.EndID := StrToInt(Edit2.Text );    //终点值给2000,按想法应该listbox2应该有23,123,223,323……,1923的一个值的列表出来,结果什么都灭有
  Test.Resume;end;
很多疑问都在注释部分描述了,请大侠给偶讲解,100分相酬,偶用的D2007,不知道是否有影响……

解决方案 »

  1.   

    //这样写可能会好一些,LZ可做个参考//线程类
    unit Unit2;interfaceuses
      Classes,SysUtils;type
      TMyFun = class(TThread)
      private
        { Private declarations }
        FStartID,FEndID: Integer;
        FStringList:TStrings;
        procedure UpdateList;
        procedure HookListBox;
      protected
        procedure Execute; override;
      public
        constructor  Create(CreateSuspended: Boolean);
        destructor   Destroy; override;
      published
        property StartID:Integer read FStartID write FStartID;
        property EndID:Integer   read FEndID   write FEndID;
      end;implementationuses Unit1;constructor TMyFun.Create(CreateSuspended: Boolean);
    begin
      inherited Create(CreateSuspended);
      FStringList:=TStringList.Create;end;destructor TMyFun.Destroy;
    begin
      FreeAndNil(FStringList);
      inherited;
    end;procedure TMyFun.Execute;
    begin
      FreeOnTerminate:=True;
      UpdateList;
      Synchronize(HookListBox);
      { Place thread code here }
    end;procedure TMyFun.HookListBox;
    begin
      Form1.ListBox1.Items:=FStringList;
    end;procedure TMyFun.UpdateList;
    begin
      while StartID<EndID do
      begin
         case StartID mod 3 of
          1:
              FStringList.Add(IntToStr(StartID));
          2:
              FStringList.Add(IntToStr(StartID));
         end;
         Sleep(10);
         StartID := StartID + 100;
      end;
    end;end.
    //主程序
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Test:TMyFun;
    begin
      Test:=TMyFun.Create(True);
      Test.StartID:=23;
      Test.EndID:=2000;
      Test.Resume;end;
      

  2.   

    //您这么写我认为不太合理!
    //这样写还不如写在主线程中!procedure myFun.Execute;
    begin
      { Place thread code here }
      FreeOnTerminate:=True;  FStartID := StartID;
      while FStartID < EndID do
      begin
        //执行代码
        Synchronize(UpdateList);
        FStartID := FStartID + 100;
      end;end;
      

  3.   

    唉,等的就是你啊
    吼吼,我看了下delphi开发人员指南的电子书籍,然后也看到了兄弟答复别人的问题中举例的代码
    有些地方不是很明白,所以在注释中给描述了偶的困惑,请兄弟讲解下了?另外,为什么不如写在主线程中呢?我只是举例性质的只产生了一个线程,我最终的想法是多个线程的……请帮忙答疑解惑下偶关于代码中的不解的地方,主要都在注释中给描述了
    谢谢啊
      

  4.   

    问题1
    FStartID,FEndID: Integer;         //定义变量?  和FStartID之间存在某种不正当关系?
    这个是偶的一个困惑,不太明白
    问题2uses Unit1,Dialogs;//--------好像必须引用Unit1,否则Form1.Listbox1.Items报错 ? 我看笑青天兄弟给人留的代码,就灭有引用,偶不明白究理uses Unit2;//-------------------好像也必须引用,否则myFun.create出错?这2个引用的地方,好像构成了循环应用,我看开发指南里面说这种是不提倡的,也就是说肯定不规范了,为什么偶会出现这个问题呢?该如何归还呢?
    问题3而兄弟给别人留的代码里面edit对象是直接个值,为什么listbox就需要多个FStringList函数,多个FStringList---》偶个人看法是就算偶的东西不对
    会导致重复添加listbox里面的item进去,但是也该有个结果啊,兄弟的方法是用FStringList保存了所有的结果,一次性的赋值给了listbox所以,为什么偶的执行结果是messagebox有正确提示值,但是listbox2始终是灭有添加进去,也不报错?
      

  5.   

    纠正下错别字,不好意思
    问题2的最后是想问,该如何来规范它问题3的开始是说兄弟给别人留的代码里面,如果是给edit对象赋值,就直接给的,为什么listbox要多个函数,和多一个FStringList嗯,新手学习过程中,可能让高手感觉幼稚可笑,还请不吝赐教啊,分不是问题,问题是一定要搞个明白
      

  6.   

    实在对不起LZ,由于时间原因,回答可能有些仓促,不过有疑问晚上再仔细探讨!
    1.有点看不懂,我猜你是想问既然有了FStartID为何要用 StartID?因为我是想在类外直接对类内的值进行赋值
    2.
    3.Synchronize是将线程并行转串行的,也就是委托主线程做界面控制的操作,因为VCL大部分控件都是假设单线程访问而设计的,你在向LIST中添加记录时,你的程序写的是直接把循环任务交给主线程干了,这和单线程有什么区别?所以要保证把费时,容易堵主线程的任务交给线程做。要Synchronize的函数只需要做一个界面连接即可,一般情况下做一些数据连接什么的!
      

  7.   


    procedure myFun.Execute;
    begin
      { Place thread code here }
      FreeOnTerminate:=True;  FStartID := StartID;
      while FStartID < EndID do
      begin
        //执行代码
        Synchronize(UpdateList);  //频繁地在子线程与主线程之间切换,效率不同
        FStartID := FStartID + 100;
      end;end;
      

  8.   

    嗯,好的,首先是感谢兄弟第一点,偶还真的猜中了,兄弟果然是希望在外部对内部赋值第二点,先空缺上……呵呵第三点,有些认识了,Synchronize调用的函数尽量只做和界面有关的事情。  基本上有些肤浅的认识了,但是还没有到位,期待晚上获得兄弟的继续指点诚挚的感谢!!!谢谢!
      

  9.   

    现在问题来了,吼吼,就是关于刷新UI的
    假设我创建2个进程,一个算奇数,一个算偶数
    定义部分procedure TMyFun.UpdateList;
    begin
      while StartID<EndID do
      begin
         case StartID mod 2 of
          0:
              FStringList.Add(IntToStr(StartID));
          1:
              FStringList.Add(IntToStr(StartID));
         end;
         Sleep(10);
         StartID := StartID + 2;
      end;
    end;调用部分
    [code=Delphi(Pascal)]
      Test1:=TMyFun.Create(True);
      Test1.StartID:=1;
      Test1.EndID:=999999999999999999999;   //姑且不考虑int的溢出这些问题
      Test1.Resume;  Test2:=TMyFun.Create(True);
      Test2.StartID:=2;
      Test2.EndID:=999999999999999999999;   //姑且不考虑int的溢出这些问题
      Test2.Resume;我这个举例计算的过程相对较长,从1到999999999999999999999  (例子是2个进程,有可能更多)
    我希望能在进度条上比较及时和准确的反馈当前的整体进度(2个线程目前总共完成了整体20% ...30%或者33%)这个又该如何操作了呢?
      

  10.   

    对于用线程做进度条的功能,频繁地用Synchronize来刷新UI是不可行的,这时可能需要考虑一些消息机制来处理!
    如:
    把计算操作放在子线程中:
    1.根据数据量定一个最大值!
    2.每计算一个阶段后,用PostThreadMessage把进度条加1的消息传给UI线程,UI线程根据消息加1后刷新当前进度!
    如果频繁地用Synchronize只会增加系统开销
      

  11.   

    对不起,公司有点事,上CSDN晚了~
    本例来实现用线程做进度条unit Unit2;interfaceuses
      Classes,SysUtils,Windows,CommCtrl;type
      TMyFun = class(TThread)
      private
        { Private declarations }
        FStartID,FEndID: Integer;
        FStringList:TStrings;
        procedure UpdateList;
        procedure HookListBox(Value:Integer);
      protected
        procedure Execute; override;
      public
        constructor  Create(CreateSuspended: Boolean);
        destructor   Destroy; override;
      published
        property StartID:Integer read FStartID write FStartID;
        property EndID:Integer   read FEndID   write FEndID;
      end;implementationuses Unit1;constructor TMyFun.Create(CreateSuspended: Boolean);
    begin
      inherited Create(CreateSuspended);
      FStringList:=TStringList.Create;end;destructor TMyFun.Destroy;
    begin
      FreeAndNil(FStringList);
      inherited;
    end;procedure TMyFun.Execute;
    begin
      FreeOnTerminate:=True;
      UpdateList;
      { Place thread code here }
    end;procedure TMyFun.HookListBox(Value:Integer);
    begin
      PostMessage(Form1.ProgressBar1.Handle,PBM_SETPOS,Value,0);
    end;procedure TMyFun.UpdateList;
    begin
      while StartID<EndID do
      begin
         case StartID mod 3 of
          1:
              FStringList.Add(IntToStr(StartID));
          2:
              FStringList.Add(IntToStr(StartID));
         end;
         Sleep(10);
    //========================
    注意这条语句,要想实时显示进度可以用Synchronize,但如果把该语句放到循环中,你测试一下,主窗体将不能动!
    这是因为进程频繁地在主线程与子线程之间切换,效率很低,如果说极端点,这就相当于在主线程中做了这个工作,
    我不知道我说明白了没有。所以线程也要慎用。
    而用消息机制来处理的话就省去了这些操作,直接在子线程中发送信息给UI线程,由UI线程来控制进度。
    你肯定要问我如何能得知进度条增1或减1的消息,你可以直接查看一下TProgressBar的源码,定位到STEPIT过程,该过程中就是用消息来处理的。
    我不知道这样找正确不正确,反正我是这么找出来的:)
         HookListBox(StartID);
    //========================
         StartID := StartID + 1;
      end;
    end;end.
      

  12.   


    //说错了,是SetPosition的源码
    以上源码可能写的不严密,其侧重点主要是说明用消息来传递的功能
    另:我也是刚学没几天,有不对的地方请大家指正
    procedure TProgressBar.SetPosition(Value: Integer);
    begin
      if not F32BitMode and ((Value < 0) or (Value > Limit16)) then
        ProgressLimitError;
      if HandleAllocated then SendMessage(Handle, PBM_SETPOS, Value, 0)
      else FPosition := Value;
    end;