我将表单最小化到系统托盘(显示托盘图标),同时在未最小化时保留其任务栏按钮。这意味着在窗体最小化时删除任务栏按钮,否则恢复它。
实现此目的的最简单方法是隐藏/显示表单,最小化的窗口无论如何都不会显示。
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;
当操作系统的“最小化和最大化时动画窗口”设置开启时(可通过“SystemPropertiesPerformance.exe”访问),上述应用程序引入了视觉故障。跳过最小化窗口动画。看起来动画实际上是在窗口最小化之后发生的。在代码中,此时窗口已经隐藏。
一个解决方案可能是在窗口管理器完成动画并在之后隐藏表单时发出通知。我找不到任何。例如,当您使用任务栏按钮最小化窗口时,最后发送的消息是 WM_SYSCOMMAND
,如果我移动代码(更不用说窗口可以通过 ShowWindow
和其他方式最小化)。
另一种解决方案可能涉及了解动画发生了多长时间。 SystemParametersInfo
没有。类似问题here尝试处理首次显示窗口时显示的动画,尽管该动画似乎与 DWM 相关,并且最小化/最大化动画先于 DWM。那里也没有决定性的解决方案。就像那个问题一样,250 毫秒的延迟似乎可以正常工作。但我不确定这是普遍存在的声音延迟。我什至不确定离散延迟是否是确定的,也许口吃会导致它达到一定程度(不是很重要,但无论如何......)。
我还尝试在不隐藏表单的情况下实际删除任务栏按钮。但它比较笨拙,它不会改变输出:动画被跳过。
最佳答案
关于 DrawAnimatedRects
(当 Aero 开启时不绘制动画)的评论说服我在有更好的替代方案之前略微未记录。使用 DrawAnimatedRects
的方法必须确定最小化位置,这是它们使用未记录的系统托盘窗口类名的地方。
当删除表单的任务栏按钮时,以下代码未记录,特别是使用 SetWindowLongPtr
的 GWLP_HWNDPARENT
索引时。无论如何,删除任务栏按钮并不像将窗口转换为工具窗口那样笨拙,动画也很流畅。
代码回退到一个隐藏表单的计时器,以防移除任务栏按钮失败。
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;
关于windows - 当最小化/恢复动画打开时,如何在删除任务栏按钮之前平滑地最小化窗口?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40116051/