I have an OnIdle handler in my D2006 app. With this code:
procedure TMainForm.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
begin
Inc (IdleCalls) ;
Sleep (10) ;
Done := False ;
end ;
the app runs smoothly, the idle handler is called 100 times per second, and the CPU usage is next to zero.
I then added a TActionList and connected up some controls to actions, coded an Execute and Update handler.
procedure TMainForm.ActionNewButtonExecute(Sender: TObject);
begin
DoNewProject ;
end ;
procedure TMainForm.ActionNewButtonUpdate(Sender: TObject);
begin
ActionNewButton.Enabled := AccessLevelIsSupervisor ;
end;
Problem. The OnUpdate event doesn't fire. On a hunch I set Done := true in the OnIdle handler and the OnIdle handler is then only called when I move the mouse. And the Update action still doesn't fire.
Why might the Update handler not be firing, and should I set Done to true or false? Or both?
As mentioned in the comments,
Sleep
in the idle handler will do no good, also the bacground processing will stall if there is no activity on the application.You can however lower the CPU usage w/o much disturbing effects:
After processing all
OnIdle
events, the application will callWaitMessage
(which will sleep while the message queue is empty), if theDone
parameter isTrue
- you can just unconditionally set it in your handler.As for background processing, use either a thread and call back to the main thread via
Synchronize
or, if you really-really have to, use a timer and don't ever forget to handle reentrancy (both solutions will by the way wake the application even whileWaitMessage
).Use the source, Luke. :)
Look at the
Forms
unit, specificallyTApplication.Idle
. It contains, in part, the following:As you can see,
DoActionIdle
is only called when eitherDone = True and FActionUpdateDelay <= 0
orIdleTimerHandle = 0
.DoActionIdle
(also part of TApplication) is what callsUpdateAction
. So if neither of the above conditions are met, TAction.OnUpdate is never called.There's a separate method,
TApplication.DoMouseIdle
, that you may want to peruse as well.Get rid of that OnIdle event handler, you accepted it is there just in case.
If you later need to perform background tasks, learn how to use threads. To get a specific frequency, you're allowed to use sleep or any other technique within a thread.
My advice is in this way because, as you see, that way of do things is interfering with other parts of your application. If it is a bug in the TApplication, I don't know, maybe it is. If you want to investigate more, make a copy of your project, check everything and if you think this have to work another way, fill a QC entry about that.
I was looking the XE source code and it seems Ok, they set an event to update the actions if the Idle event is not done.. I don't see a bug there. I have no pre-2010 ready installations to check ancient versions.