1

我想显示一个系统托盘图标事件的表单,它只在任务栏旁边显示一些信息,并在一段时间后自行消失。我遇到的主要问题是以正确位置和可见的方式定位表单。我找到了几种方法来确定图标的位置,但在测试中我发现它们基于操作系统不一致(我在另一个应用程序中尝试过这个并最终放弃并使用居中模式形式)。例如:

procedure GetWorkAreaRect(var outrect: TRect);
// returns the dimensions of the work area.
begin
  Systemparametersinfo(SPI_GETWORKAREA, 0, @outrect, 0);
end;

可行的问题是从那里确定将表单放在哪里(上、下、左、右)。有什么建议么?

编辑:问题在于相对于系统托盘图标定位表单,不一定确定系统托盘图标的位置。我又做了一次尝试,只要满足某些条件,它就可以工作。最值得注意的是,如果任务栏设置为自动隐藏,它就不起作用,因为假设点击是在工作区域之外进行的。当表单设置为自动隐藏时,情况并非如此。

function PositionForm(X, Y, Width, Height: Integer): TPoint;
// receives mouse-click position in X and Y, form width and height in width and height
// returns Left and Top in TPoint.X and TPoint.Y.
var 
  workrect: TRect;
  resrect: TPoint;
begin
  GetWorkAreaRect(workrect);
  if Y > WorkRect.Bottom then  // taskbar is on bottom
    begin
      resRect.X := WorkRect.Right - Width;
      resrect.Y := WorkRect.Bottom - Height;
    end
  else
  if X > WorkRect.Right then   // taskbar is on right
    begin
      resrect.X := WorkRect.Right - Width;
      resrect.Y := WorkRect.Bottom - Height;
    end
  else
  if X < WorkRect.Left then  // taskbar is on left
    begin
      resrect.X := WorkRect.Left;
      resrect.Y := WorkRect.Bottom - Height;
    end
  else
  if Y < WorkRect.Top then   // taskbar is on top
    begin
      resrect.X := WorkRect.Right - Width;
      resrect.Y := WorkRect.Top;
    end;
  Result := ResRect;
end;

所以从表面上看,问题似乎是找到一种独立的方法来确定任务栏所在的位置......或者是否可以将逻辑扩展到上面来解决这个问题?

4

3 回答 3

3

当您的通知图标收到与某个操作对应的消息时,您可以在该点查询以找出屏幕上的关联点。

例如,如果您在图标的消息过程中处理WM_RBUTTONUPWM_CONTEXTMENU,您可以调用GetMessagePos以找出与消息关联的图标上的位置。

我用以下函数将其包装起来,以便我可以将消息解码为TPoint

function MessagePoint: TPoint;
begin
  Result := TSmallPoint(GetMessagePos());
end;

所以你可以做的是,在你的图标的消息过程中,记下这一点。当您需要显示表单时,使用这一点来确定您的图标所在的位置。由于该点可以在任务栏中,因此您需要将其剪辑到工作区中。


在您的问题更新后,您似乎想知道如何找出任务栏的位置。SHAppBarMessage通过调用 pass 来做到这一点ABM_GETTASKBARPOS

于 2013-04-30T07:05:30.550 回答
2

Windows 没有公开查询系统托盘图标位置的本机方式,或者即使它们根本可见。但是您可以使用一些较低级别的 API 技巧手动完成,如下文所示:

CTrayIconPosition - 我的托盘图标在哪里?

这至少适用于 XP,甚至可能适用于 Vista。Windows 7 彻底重新设计了系统托盘的行为方式,所以我不知道这些技术是否仍然有效。

于 2013-04-30T04:13:41.663 回答
0

如果您有和,您可以使用它TJvDesktopAlert来显示简单的通知。JCLJVCL

procedure TForm1.ShowDesktopAlert(const AHeader, AMessage: string);
begin
  with TJvDesktopAlert.Create(nil) do
  begin
    StyleOptions.DisplayDuration := 5000;
    HeaderText := AHeader;
    MessageText := AMessage;
    AutoFree := True;
    Execute;
  end;
end;
于 2013-04-30T12:40:50.650 回答