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.

+3


source to share


1 answer


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

.

+3


source







All Articles