How can I minimize window minimization before removing the taskbar button when turning on / updating the animation?

I minimize the form in the system tray (display the tray icon), while maintaining its button on the taskbar when it is not minimized. This implies the removal of the taskbar button when the form is minimized and otherwise restored.

The easiest way to achieve this is to hide / show the form, the minimized window does not show.

type
  TForm1 = class(TForm)
    TrayIcon1: TTrayIcon;
    procedure TrayIcon1DblClick(Sender: TObject);
  protected
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.WMSize(var Message: TWMSize);
begin
  inherited;
  case Message.SizeType of
    SIZE_MINIMIZED:
      if not TrayIcon1.Visible then begin
        TrayIcon1.Visible := True;
        Hide;
      end;
    SIZE_RESTORED, SIZE_MAXIMIZED:
      if TrayIcon1.Visible then begin
        Show;
        Application.BringToFront;
        TrayIcon1.Visible := False;
      end;
  end;
end;

procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
  Show;
  WindowState := wsNormal;
end;


The above application introduces a visual crash if the option "Animate windows when minimizing and maximizing" the OS is enabled (available through "SystemPropertiesPerformance.exe"). Minimize window animations skipped. It seems that the animation actually runs after minimizing the window. The window is already hidden in the code.


, . . , , , , - WM_SYSCOMMAND, , ( , ShowWindow ).


, , . SystemParametersInfo . , , , , DWM / DWM. . , 250 . , . , , , ( , , ...).


. : .

+4
1

DrawAnimatedRects ( Aero) , . , DrawAnimatedRects, , , .

, , GWLP_HWNDPARENT SetWindowLongPtr, . , , .

, .

type
  TForm1 = class(TForm)
    TrayIcon1: TTrayIcon;
    Timer1: TTimer;
    procedure TrayIcon1DblClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  protected
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function ShowTaskbarButton(Wnd: HWND; Show: Boolean = True;
    OwnerWnd: HWND = 0): Boolean;
var
  ExStyle, HWndParent: LONG_PTR;
  IsToolWindow: Boolean;
begin
  HwndParent := GetWindowLongPtr(Wnd, GWLP_HWNDPARENT);
  ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE);
  Result := Show = (HWndParent = 0) and (ExStyle and WS_EX_APPWINDOW <> 0);

  if not Result then begin
    IsToolWindow := ExStyle and WS_EX_TOOLWINDOW <> 0;
    if IsToolWindow then begin
      ShowWindow(Wnd, SW_HIDE);
      ShowWindowAsync(Wnd, SW_SHOW);
    end;
    SetLastError(0);
    if Show then
      SetWindowLongPtr(Wnd, GWL_EXSTYLE, ExStyle or WS_EX_APPWINDOW)
    else
      SetWindowLongPtr(Wnd, GWL_EXSTYLE, ExStyle and not WS_EX_APPWINDOW);
    if not IsToolWindow and (GetLastError = 0) then
      SetWindowLongPtr(Wnd, GWLP_HWNDPARENT, OwnerWnd);

    Result := GetLastError = 0;
  end;
end;

procedure TForm1.WMSize(var Message: TWMSize);
begin
  inherited;
  case Message.SizeType of
    SIZE_MINIMIZED:
      if not TrayIcon1.Visible then begin
        if not ShowTaskbarButton(Handle, False, Application.Handle) then
          Timer1.Enabled := True;   // fall back
        TrayIcon1.Visible := True
      end;
    SIZE_RESTORED, SIZE_MAXIMIZED:
      if TrayIcon1.Visible then begin
        ShowTaskbarButton(Handle);
        Application.BringToFront;
        TrayIcon1.Visible := False;
      end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer1.Interval := 250;
  Timer1.Enabled := False;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Hide;
  Timer1.Enabled := False;
end;

procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
  ShowTaskbarButton(Handle);
  if not Showing then   // used timer to hide
    Show;
  WindowState := wsNormal;
end;
+1

Source: https://habr.com/ru/post/1658123/


All Articles