3

我的 D2006 应用程序中有一个 OnIdle 处理程序。使用此代码:

procedure TMainForm.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);

begin
Inc (IdleCalls) ;
Sleep (10) ;
Done := False ;
end ;

应用运行流畅,每秒调用空闲处理程序 100 次,CPU 使用率接近于零。

然后我添加了一个 TActionList 并将一些控件连接到操作,编写了一个 Execute 和 Update 处理程序。

procedure TMainForm.ActionNewButtonExecute(Sender: TObject);
begin
DoNewProject ;
end ;

procedure TMainForm.ActionNewButtonUpdate(Sender: TObject);
begin
ActionNewButton.Enabled := AccessLevelIsSupervisor ;
end;

问题。OnUpdate 事件不会触发。凭直觉,我在 OnIdle 处理程序中设置了 Done := true ,然后仅在移动鼠标时才调用 OnIdle 处理程序。并且更新操作仍然没有触发。

为什么更新处理程序可能不会触发,我应该将 Done 设置为 true 还是 false?或两者?

4

3 回答 3

6

使用来源,卢克。:)

Forms单位,具体TApplication.Idle。它部分包含以下内容:

Done := True;
try
  if Assigned(FOnIdle) then FOnIdle(Self, Done);
  if Done then
    if FActionUpdateDelay <= 0 then
      DoActionIdle
  // Excluded to avoid copyright violation
  // See also the else portion, which contains (in part)
  else
    if IdleTimerHandle = 0 then
    begin
      IdleTimerHandle := SetTimer(0, 0, FActionUpdateDelay, IdleTimerDelegate);
      if IdleTimerHandle = 0 then
        DoActionIdle
    end;
finally
  // Omitted
end;

如您所见,DoActionIdle仅在Done = True and FActionUpdateDelay <= 0或时调用IdleTimerHandle = 0DoActionIdle(也是 TApplication 的一部分)称为UpdateAction. 因此,如果上述条件都不满足,则永远不会调用 TAction.OnUpdate。

有一个单独的方法,TApplication.DoMouseIdle您可能还想仔细阅读。

于 2011-03-31T23:45:43.763 回答
3

正如评论中提到的,Sleep在空闲处理程序中不会有任何好处,如果应用程序上没有活动,则免费处理也会停止。

但是,您可以降低 CPU 使用率而不会产生太多干扰:
在处理完所有OnIdle事件后,应用程序将调用WaitMessage(当消息队列为空时它将休眠),如果Done参数是True- 您可以在处理程序中无条件地设置它。

至于后台处理,使用线程并通过回调主线程,Synchronize或者,如果你真的必须,使用计时器并且不要忘记处理重入(两种解决方案都会唤醒应用程序甚至而WaitMessage)。

于 2011-04-01T11:20:08.550 回答
2

摆脱那个 OnIdle 事件处理程序,您接受它以防万一

如果您以后需要执行后台任务,请学习如何使用线程。要获得特定频率,您可以在线程中使用睡眠或任何其他技术。

我的建议是这样,因为如您所见,这种做事方式会干扰您应用程序的其他部分。如果它是 TApplication 中的错误,我不知道,也许是。如果您想进行更多调查,请复制您的项目,检查所有内容,如果您认为这必须以另一种方式工作,请填写有关此的 QC 条目。

我正在查看 XE 源代码,似乎还可以,如果 Idle 事件未完成,他们设置了一个事件来更新操作。我在那里没有看到错误。我没有 2010 年前的现成安装来检查古代版本。

于 2011-04-01T02:25:50.740 回答