为帮助朋友们更好的理解QWorker的使用,今天新增一个示例来演示以下内容:
1、基于信号控制作业的运行状态。主面板上设置了三个按钮:开始、暂停和停止分别控制一个后台作业的状态,而后台作业的实现在另一个窗体单元中实现,是一种松散耦合。
2、基于Delay方法来计划延迟作业,在作业中根据状态重复投寄还是退出执行。
3、窗体释放时清理关联作业。
我们下面说明一下实现的逻辑:
1、主窗体的构造函数中,注册开始、暂停、停止三个状态的信号,并保存其信号编码,以便后面使用。如果不知道相关的编码,可以再次RegisterSignal来获取这个ID。
procedure TfrmMain.FormCreate(Sender: TObject); begin FStartSignal := Workers.RegisterSignal('Work.Start'); FPauseSignal := Workers.RegisterSignal('Work.Pause'); FStopSignal := Workers.RegisterSignal('Work.Stop'); frmWork := TfrmWork.Create(Application); end;
在构造函数的末尾,创建了一个面板窗口,在面板窗口的OnCreate事件中,我们注册了相应信号的处理函数,等待信号的触发。
procedure TfrmWork.FormCreate(Sender: TObject); begin Workers.Wait(DoStartWork, frmMain.StartSignal, True); Workers.Wait(DoPauseWork, frmMain.PauseSignal, True); Workers.Wait(DoStopWork, frmMain.StopSignal, True); end;
2、在按下主窗体的开始、暂停和停止按钮时,直接触发相关的信号,而不需要关心有没有代码去实现它。如果有(我们这里当然有),则相应的处理过程会被触发。
procedure TfrmMain.btnPauseClick(Sender: TObject); begin Workers.Signal(PauseSignal); end; procedure TfrmMain.btnStartClick(Sender: TObject); begin Workers.Signal(StartSignal); end; procedure TfrmMain.btnStopClick(Sender: TObject); begin Workers.Signal(StopSignal); end;
3、很好,现在TfrmWork的DoStartWork/DoPauseWork/DoStopWork相应的信号处理函数就被触发了。
procedure TfrmWork.DoPauseWork(AJob: PQJob); begin Workers.Clear(DoDelayTimer, nil); frmMain.State := wsPaused; end; procedure TfrmWork.DoStartWork(AJob: PQJob); begin Workers.Delay(DoDelayTimer, random(1000), nil,True); if frmMain.State <> wsPaused then begin SetBounds(Screen.WorkAreaRect.Right - Width, Screen.WorkAreaTop, Width, Height); Show; end; frmMain.State := wsRunning; end; procedure TfrmWork.DoStopWork(AJob: PQJob); begin Workers.Clear(DoDelayTimer, nil); FRuns := 0; frmMain.State := wsStopped; Hide; end;
4、DoDelayTimer执行实际的作业处理过程,在其中,我们在其中显示了一些简单的作业信息,然后再次必要时再次重复延迟触发。
procedure TfrmWork.DoDelayTimer(AJob: PQJob); var ANextDelay: Int64; begin ANextDelay := random(1000); Inc(FRuns); Label1.Caption := '运行次数:' + IntToStr(FRuns) + '次,末次延迟:' + IntToStr((AJob.PopTime - AJob.PushTime) div 10) + 'ms,下一延迟:' + IntToStr(ANextDelay) + 'ms'; if (frmMain.State = wsRunning) or (not AJob.IsTerminated) then Workers.Delay(DoDelayTimer, ANextDelay * Q1MillSecond, nil,True); end;
好了,我们现在看看程序的运行结果。
【源码下载】