分享

.基于回调函数的线程定义与GUI界面或其他类对象组合

 aaie_ 2012-10-16

我们经常遇到在Form下操作界面,例如由线程控制的进度条等,让线程的执行可以和Form界面融合,不必传进窗体句柄,这个时候可以用回调函数的方法来定义线程的成员函数。

      注意:原则上Delphi的多线程环境下,对界面的输出不能在其它线程中随意进行,否则会导致与界面(主)线程本身的刷新操作形成冲突,导致一些看似无规律的问题。比较保险的方式就是将要刷新的内容通过消息或其它通信机制传给界面线程,由界面线程去完成实际的刷新操作。

     所以,在我们使用回调函数把线程的可执行代码转移到Tform或其他类下时,只要不是直接操作VCL控件,一般可以参考下面代码,可以安全执行。下面的代码就是一个可以自动执行线程成员事件OnExecute指向的代码片段,你只需要给线程实例对象的OnExecute  赋值即可让其执行。

     用法说明:在Form下定义一个成员函数

                    TForm1= class(TForm)

                     ........

                     public

                            procedure  MyExecuteJob( AThreadSelf:TThread;var State : TJobState);

                    end;

           //实现部分

           procedure  TForm1.MyExecuteJob( AThreadSelf:TThread;var State : TJobState);

   在线程创建的时候;即可赋值,例如:

    var

           AutoChooseThread : TAutoChooseThread ; 

procedure Tfrm_AutoChoose.StartChooseJob;
begin
  if not Assigned(AutoChooseThread) then
  begin
     AutoChooseThread := TAutoChooseThread.Create(True);
     AutoChooseThread.OnJObComplete := OnJObComplete;
     AutoChooseThread.OnBeforeJobRun := OnBeforeJobRun;
     AutoChooseThread.OnProgress := OnProgress;
     AutoChooseThread.OnExecute := MyExecuteJob;
  end;

end;

        以上使用说明,需要完成其他回调只要按照如上方式即可。需要注意到地方。例如:MyExecuteJob函数

在Form1中定义了,那么传入了两个参数,一个是线程本身,一个是线程状态。如果MyExecuteJob函数中有大量循环操作,不能立即返回,需要不断判断线程状态,如果发现是JsStop或JsDestroy那么就需要Exit一下,退出函数。否则调用FreeJob();或StopJob();是不能立即奏效的。

 

  //线程回调函数类型定义
  TJobState = (JsStop,JsRunning,JsComplete,JsCreate,JsDestroy); //枚举任务状态
  TOnJObComplete = procedure (Sender : TObject) of Object; //当完毕
  TOnJObRun = procedure(Sender:TObject) of object; //开始
  TOnProgress = procedure( MaxValue,CurValue:DWORD) of object; //进度
  TOnExecute = procedure( AThreadSelf:TThread;var State : TJobState) of object; //任务执行

  //自动选择任务,线程处理定义,和GUI可以高度融合的方式
    TAutoChooseThread = class(TThread)
     private
        FOnJObComplete : TOnJObComplete;
        FOnJObRun   : TOnJObRun;
        FOnProgress : TOnProgress;
        FOnExecute  : TOnExecute;
        FState      : TJobState;
     public
        property OnJObComplete    : TOnJObComplete read FOnJObComplete write FOnJObComplete;
        property OnBeforeJobRun   : TOnJObRun read FOnJObRun write FOnJObRun;
        property OnProgress : TOnProgress read FOnProgress write FOnProgress;
        property OnExecute  : TOnExecute read FOnExecute write FOnExecute;
        property State      : TJobState read FState;
        procedure StartJob();
        procedure StopJob();
        procedure FreeJob();
        procedure Execute();override;
        constructor Create(isCreateSuspend:Boolean);
        destructor Destroy; override;
  end;
  
  
//线程实现代码  
constructor TAutoChooseThread.Create(isCreateSuspend:Boolean);
begin
  FreeOnTerminate := True;
  FState := JsCreate;
  inherited Create(isCreateSuspend);
end;

destructor TAutoChooseThread.Destroy;
begin

  inherited;
end;

procedure TAutoChooseThread.Execute;
begin
  while not Terminated do
  begin
     //当任务执行前
     if Assigned( FOnJobRun ) then
     begin
        FOnJObRun(Self);
     end;

     //执行任务
     if Assigned( FOnExecute ) then
     begin
        //执行任务
        FState := JsRunning;
        FOnExecute(self,FState);
        //如果任务成功完成
        if FState = JsComplete then
        begin
           if Assigned(FOnJObComplete) then
           begin
              FOnJObComplete(Self);
           end;
        end;

        //如果任务销毁
        if FState = JsDestroy then
        begin
           Exit;
        end;
     end;
     Suspend;
     Sleep(1);
  end;
end;

procedure TAutoChooseThread.FreeJob;
begin
  Terminate;
  FState := JsDestroy;
  Resume();
end;

procedure TAutoChooseThread.StartJob;
begin
  Resume();
  FState := JsRunning;
end;

procedure TAutoChooseThread.StopJob;
begin
  FState := JsStop;
end;


procedure Tfrm_AutoChoose.OnBeforeJobRun(Sender: TObject);
begin
   sGroupBox_Pocessing.Visible := True;
   sGauge1.Progress := 0;
   qry_FactorOfFlower.Close;
end;

procedure Tfrm_AutoChoose.OnExecute(AThreadSelf: TThread; var State: TJobState);
var
  MaxValue,CurValue:DWORD;
begin
  //执行任务
  MaxValue := 1000;
  sGauge1.MaxValue := MaxValue;
  for CurValue := 0 to MaxValue - 1 do
  begin
      if TAutoChooseThread(AThreadSelf).State = JsStop then
      begin
        sGroupBox_Pocessing.Visible := False;
        sPanel_Result.Visible := False;
        qry_FactorOfFlower.Close;
        Exit;
      end;
      sGauge1.Progress := CurValue;
  end;
  State := JsComplete;
end;

procedure Tfrm_AutoChoose.OnJObComplete(Sender: TObject);
begin
  sPanel_Result.Visible := True;
end;

procedure Tfrm_AutoChoose.OnProgress(MaxValue, CurValue: DWORD);
begin

end;

procedure Tfrm_AutoChoose.FormDestroy(Sender: TObject);
begin
  inherited;
  if Assigned( AutoChooseThread ) then
  begin
     AutoChooseThread.FreeJob();
  end;
end;

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多