Fabrizio
Fabrizio

Reputation: 8053

How to detect WindowState changes?

How can I detect WindowState changes for a TCustomForm descendant? I would like to be notified at any time the WindowState property is set with a different value.

I've checked if there was an event or a virtual method inside the setter but I didn't found nothing for achieving my goal.

function ShowWindow; external user32 name 'ShowWindow';

procedure TCustomForm.SetWindowState(Value: TWindowState);
const
  ShowCommands: array[TWindowState] of Integer =
    (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED);
begin
  if FWindowState <> Value then
  begin
    FWindowState := Value;
    if not (csDesigning in ComponentState) and Showing then
      ShowWindow(Handle, ShowCommands[Value]);
  end;
end;

Upvotes: 5

Views: 2261

Answers (1)

Sertac Akyuz
Sertac Akyuz

Reputation: 54822

The notification the OS sends to a window when its state has changed is a WM_SIZE message. It's not evident from the code quote you posted but the VCL already listens for WM_SIZE in TScrollingWinControl class (ascendant of TCustomForm) and calls the virtual Resizing procedure while handling the message.

So you can override this method of your form to get notified.

type
  TForm1 = class(TForm)
    ..
  protected
    procedure Resizing(State: TWindowState); override;

....

procedure TForm1.Resizing(State: TWindowState);
begin
  inherited;
  case State of
    TWindowState.wsNormal: ;
    TWindowState.wsMinimized: ;
    TWindowState.wsMaximized: ;
  end;
end;


Note that the notification can be sent multiple times for a given state, for instance while the window is being resized or while visibility is changing. You might need to track the previous value for detecting when the state is actually changed.


Depending on your requirements you can also use the OnResize event of the form. The difference is that, this event is fired before the OS notifies the window about the change. VCL retrieves window state information by calling GetWindowPlacement while TCustomForm is handling WM_WINDOWPOSCHANGING.

Below is an example using a flag to keep track of the previous window state.

  TForm1 = class(TForm)
    ..
  private
    FLastWindowState: TWindowState; // 0 -> wsNormal (initial value)

...

procedure TForm1.FormResize(Sender: TObject);
begin
  if WindowState <> FLastWindowState then
    case WindowState of
      TWindowState.wsNormal: ;
      TWindowState.wsMinimized: ;
      TWindowState.wsMaximized: ;
    end;
  FLastWindowState := WindowState;
end;

Upvotes: 7

Related Questions