How do I make my user control notified when its form or application gains and loses focus?
I want my control to receive great notifications only when its parent form (not a panel or whatever, just the main form of that control) gains and loses focus. It doesn't matter if focus is switched from another application form or between my application and another application, it should be received for both cases. Is it possible? I want to pause some updates of a control when its form is not active and resume updates when the form is activated.
Edit: In other words, the control should catch ( TForm.OnActivate
+ TApplication.OnActivate
) and ( TForm.OnDeactivate
+ TApplication.OnDeactivate
)
Edit2: If that's not possible, at least if I can get the control to catch events from the TApplication. This is more important than TForm.
source to share
I want to pause some updates of a control when its form is not active and resume updates when the form is activated.
If these updates are ongoing or triggered by a timer or actions, you can do this:
type
TMyControl = class(TControl)
private
procedure PerformUpdate;
end;
procedure TMyControl.PerformUpdate;
begin
if Application.Active and HasParent and GetParentForm(Self).Active then
//...
else
//...
end;
... at least if I can get the control to catch events from the application
Capture TApplication.OnActivate
and TApplication.OnDeactivate
pretty easy with a component TApplicationEvents
:
uses
Vcl.AppEvnts;
type
TMyControl = class(TControl)
private
FActive: Boolean;
FAppEvents: TApplicationEvents;
procedure ApplicationActiveChanged(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
end;
procedure TMyControl.ApplicationActiveChanged(Sender: TObject);
begin
FActive := Application.Active;
end;
constructor TMyControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAppEvents := TApplicationEvents.Create(Self);
FAppEvents.OnActivate := ApplicationActiveChanged;
FAppEvents.OnDeactivate := ApplicationActiveChanged;
end;
... it is more important than those of the form
Capturing (de) activating the parenting form can be done in Application.OnIdle
. All of this combined can lead to something like this:
type
TMyControl = class(TControl)
private
FActive: Boolean;
FAppEvents: TApplicationEvents;
FParentForm: TCustomForm;
procedure ApplicationActiveChanged(Sender: TObject);
procedure ApplicationIdle(Sender: TObject; var Done: Boolean);
procedure UpdateActive;
protected
procedure SetParent(AParent: TWinControl); override;
public
constructor Create(AOwner: TComponent); override;
end;
procedure TMyControl.ApplicationActiveChanged(Sender: TObject);
begin
UpdateActive;
end;
procedure TMyControl.ApplicationIdle(Sender: TObject; var Done: Boolean);
begin
UpdateActive;
Done := True;
end;
constructor TMyControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAppEvents := TApplicationEvents.Create(Self);
FAppEvents.OnActivate := ApplicationActiveChanged;
FAppEvents.OnDeactivate := ApplicationActiveChanged;
end;
procedure TMyControl.SetParent(AParent: TWinControl);
begin
inherited SetParent(AParent);
FParentForm := GetParentForm(Self);
end;
procedure TMyControl.UpdateActive;
var
SaveActive: Boolean;
begin
SaveActive := FActive;
FActive := Application.Active and (FParentForm <> nil) and FParentForm.Active;
if Application.Active then
FAppEvents.OnIdle := ApplicationIdle
else
FAppEvents.OnIdle := nil;
if FActive <> SaveActive then
Invalidate;
end;
Since usage Application.OnIdle
is a pretty strict technique, get rid of using it as I did above, only assigning it as needed and speeding up its implementation by caching the results of a function like GetParentForm
.
source to share