这个示例主要是演示了Delay函数的用法,示例中用Delay来作一个延迟作业,在每次作业时绘制一段曲线,从而形成动态效果。
程序运行最终的效果如图所示:
首先,我们放置了一个TChart对象,并预定义了两个TLineSeries类型的图表项目,我们在操作时,以线来拟合成正余弦曲线。
当我们点击开始按钮时,我们触发了下面的代码:
procedure TForm6.Button1Click(Sender: TObject); begin slCos.Clear; slSin.Clear; FFlags := 0; Button1.Enabled:=False; if CheckBox1.Checked then begin Chart1.LeftAxis.SetMinMax(-1, 1); Chart1.BottomAxis.SetMinMax(0, 10); end else begin Chart1.LeftAxis.Automatic:=True; Chart1.BottomAxis.Automatic:=True; end; //牵涉到VCL的控件,这两个作业必需在主线程中执行 Workers.Delay(DoSinJob, Q1MillSecond * 50, Pointer(0), True); Workers.Delay(DoCosJob, Q1MillSecond * 50, Pointer(0), True); end;
为了可以重复点击演示,我们先清除了上次的slCos和slSin两条线图的内容,然后设置标志为0,我们定义FFlags是为了确定何时可以重新启用Button1这个按钮,再次点击。CheckBox1是否选择固定坐标范围选项。然后我们分别延迟50ms计划了两个作业DoSinJob和DoCosJob,每次作业只添加一个新的数据点。为了方便,我们直接利用了作业的Data成员来记录上次作业已经进行到第几步,所以这里初始为0。这里要注意ARunInMainThread参数必需设置为True。这是因为我们在这个演示中,在作业中要添加结点时,要操作Chart1这个VCL控件,而VCL不是线程安全的,所以必需在主线程中执行这个作业。
剩下的就是DoSinJob和DoCosJob两个作业了,我们简单看下代码:
procedure TForm6.DoCosJob(AJob: PQJob); var V: Double; begin V := Integer(AJob.Data) / 10; slCos.AddXY(V, cos(V)); //如果绘制未完成,再次延迟触发下一次绘图 if Integer(AJob.Data) < 100 then Workers.Delay(DoCosJob, Q1MillSecond * 50, Pointer(Integer(AJob.Data) + 1), True) else//设置并检查是否两个作业都完成了,如果完成了,更新按钮状态 begin FFlags := FFlags or $01; if FFlags = $03 then Button1.Enabled := True; end; end; procedure TForm6.DoSinJob(AJob: PQJob); var V: Double; begin V := Integer(AJob.Data) / 10; slSin.AddXY(V, sin(V)); //如果绘制未完成,再次延迟触发下一次绘图 if Integer(AJob.Data) < 100 then Workers.Delay(DoSinJob, Q1MillSecond * 50, Pointer(Integer(AJob.Data) + 1), True) else//设置并检查是否两个作业都完成了,如果完成了,更新按钮状态 begin FFlags := FFlags or $02; if FFlags = $03 then Button1.Enabled := True; end; end;
在这里,我们将AJob.Data转换为整数后,然后除以10来得到实际的步进值。当后面再次计算下一次作业时,这个值加了1,也就是说,实际的步长是0.1。在执行100次调用后,我们设置并检查最终的标志位,在检测到两个都完成后,Button1重新启用。如果执行次数小于100次,则再次调用Delay延迟50ms计划下一次调用。最终就形成了50ms/帧的动态演示效果。