我正在最小化表单到系统托盘(显示托盘图标),同时在未最小化时保持其任务栏按钮。这意味着在窗体最小化时删除任务栏按钮,否则恢复它。
实现这一目标的最简单方法是隐藏/显示表单,无论如何都不会显示最小化的窗口。
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毫秒的延迟似乎工作得很好。但我不确定这是一个普遍合理的延迟。我甚至不确定一个离散的延迟是肯定的,也许一个口吃会导致它延伸(不是它会很重要,但无论如何......)。
我还试图删除任务栏按钮,而不隐藏表单。但它更笨拙并且不会改变输出:动画被跳过。
答案 0 :(得分: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;