سؤال

I'd like to display a form off of a systray icon event, which just shows some information next to the taskbar and disappears itself after some time. The main issue I'm running into is positioning the form in a way that it is both in the correct position and visible. I found a couple of ways to determine where the icon is, but in testing I found them inconsistent based on OS (I attempted this in another app and ended up giving up and using a centered modal form). For example:

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

The problem when that works is determining from there where to put the form (above, below, left, right). Any suggestions?

Edit: The problem is in positioning the form in relationship to the system tray icon, not necessarily determining where the system tray icon is. I made another attempt and got it working as long as some conditions are met. Most notably, it doesn't work if the taskbar is set to auto-hide, because the assumption is made that the click is made outside of the work area. This is not true when the form is set to auto-hide.

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;

So on the surface, it seems the issue is to find an independent way to determine where the taskbar resides...or could the logic be extended above to take care of this?

هل كانت مفيدة؟

المحلول

When your notification icon receives the message corresponding to an action, you can query at that point to find out an associated point on the screen.

For example if you are handling WM_RBUTTONUP, WM_CONTEXTMENU etc. in your icon's message procedure you can call GetMessagePos to find out the position on the icon associated with the message.

I wrap this up with the following function so that I can decode the message into a TPoint:

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

So what you can do is, in your icon's message procedure, make a note of this point. When you need to show the form, use this point to determine where your icon lives. Since the point can be in the taskbar, you'll need to clip it into the work area.


After your question update it seems you want to know how to find out the location of the taskbar. Do that by calling SHAppBarMessage passing ABM_GETTASKBARPOS.

نصائح أخرى

Windows does not expose a native way to query where system tray icons are positioned, or even if they are visible at all. But you can do it manually with some lower level API trickery, as demonstrated in the following article:

CTrayIconPosition - where is my tray icon?

That works up to XP, at least, maybe even Vista. Windows 7 drastically redesigned the way the system tray acts, so I do not know if these techniques still work anymore.

You can use TJvDesktopAlert to display simple notifications, if you have JCL and JVCL.

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;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top