4

Is it possible to close the TTrayIcon Balloon hint programmatically?

The problem:

I have a timer which checks for messages every minute. When it discovers a message (eg. ABC Service is stopped), it shows the balloon with the message:

procedure TFrmTest.tmrTimer(Sender: TObject);
begin
  tmr.Enabled := False;
  try
    if IsAnyServiceStopped then
      ShowBallon(bfError, 'The ABC Service is stopped. Do something!!!');
  finally
    tmr.Enabled := True;
  end;
end;

procedure TfrmTest.ShowBallon(pFlag: TBalloonFlags; pMessage: string);
begin
  try
    // HERE I'D LIKE TO CLOSE THE BALLOON IF IT'S OPENNED
    TrayIcon.BalloonFlags := pFlag;
    TrayIcon.BalloonHint := pMessage;
    TrayIcon.ShowBalloonHint;
  except
  end;
end;

The TrayIcon BalloonTimeOut is set to 3000 (3 secs). Since the timer triggers the message every minute (when there is any message), if the user does not close it, the system makes a queue of messages. If the user comes back to PC after 30 minutes (for example), they'll close the first message, then immediately the tray icon shows the second message, and the same for the next 28 messages (poor user).

I know the balloon auto closes itself, but it closes only if the user do some input (mouse movement, key press, and the application doesn't need to be focused or even visible). So if the user is away from computer, the balloon stays there forever until the input.

Other solution I tried was to disable the Timer when showing any balloon, and enable it again only when the user closes the current balloon (or it gets auto-closed). But I couldn't find any way to discover when the balloon is closed (the OnBalloonClick event doesn't triggers if the user click on X or it gets auto-closed).

Alisson Reinaldo Silva
  • 10,009
  • 5
  • 65
  • 83
  • 7
    `TrayIcon.BalloonHint := '';` ([`source`](http://stackoverflow.com/a/902804/960757)) – TLama Jul 02 '15 at 12:42
  • 1
    I would suggest ignoring `TTrayIcon` and call the Win32 `Shell_NotifyIcon()` function directly instead. If nothing else, that gives you the ability to receive `NIN_BALLOONSHOW`, `NIN_BALLOONHIDE` and `NIN_BALLOONTIMEOUT` messages. `TTrayIcon` does not expose any events for those messages (though it does process `NIN_BALLOONHIDE` and `NIN_BALLOONTIMEOUT` internally). Otherwise, you would have to derive from `TTrayIcon` and override its virtual `WindowProc()` method to receive those messages in your code. – Remy Lebeau Jul 02 '15 at 17:48
  • 2
    @TLama it worked like a charm. Please, post as answer so I can pick it. Remy, I have the intention of doing like you said, but atm I don't have the knowledge and time for doing that way. My idea is to create a class just to manage these notifications. Thanks for sharing your ideas. – Alisson Reinaldo Silva Jul 02 '15 at 21:11

1 Answers1

3

The reference for the NOTIFYICONDATA structure describes how to hide a balloon hint in the szInfo member description:

To remove the balloon notification from the UI, either delete the icon (with NIM_DELETE) or set the NIF_INFO flag in uFlags and set szInfo to an empty string.

For TTrayIcon component (at least in your Delphi version) is easy to meet the latter option because when the TTrayIcon is showing the balloon notification, the NIF_INFO flag is set, so what remains is setting the szInfo member to an empty string. In TTrayIcon component, the szInfo member can be modified by the BalloonHint property, so to hide a displayed balloon hint you can simply write:

TrayIcon.BalloonHint := '';
TLama
  • 75,147
  • 17
  • 214
  • 392