Home > front end >  Why a balloon ToolTip with TTS_CLOSE style cannot be displayed again after the "X" button
Why a balloon ToolTip with TTS_CLOSE style cannot be displayed again after the "X" button

Time:03-08

I'm creating a Balloon ToolTip (TTS_BALLOON) with an additional style that makes an "X" appear in the upper right corner of this balloon in order to close it (TTS_CLOSE).

The type of ToolTip I'm creating is "tracking", ie I show the ToolTip on demand, via the TTM_TRACKACTIVATE message, as it is properly explained on MSDN. The ToolTip works correctly, being displayed/hidden upon sending the message TTM_TRACKACTIVATE, however, after displaying the ToolTip and clicking the "X", it is correctly hidden, but it is no longer possible to display the ToolTip again in any way, not even using TTM_TRACKACTIVATE , nor using TTM_POPUP. A similar question was asked on the Visual Studio Forum (https://social.msdn.microsoft.com/Forums/vstudio/en-US/8ff12b85-c0a5-4a69-87d5-0a13ea9c43b0/help-with-ttsclose-style) and not even there the author got an answer to this day.

Speaking of TTM_POPUP and its counterpart, TTM_POP, after sending a TTM_POP message, to "remove the ToolTip from the screen", I could no longer display it, either with TTM_POPUP or with TTM_TRACKACTIVATE, that is, TTM_POP has the same effect as click on the "X", which, in my understanding, only serves to break the ToolTip and make it unusable.

I'm developing a class in Pascal (Delphi) to facilitate the creation and manipulation of ToolTips and now I'm dealing with TTS_CLOSE and I don't understand why this happens. It's normal? Is it a Windows API bug?

Below is an example code. To reproduce the problem, create a project of type Windows VCL Application, whose only TForm is called Form1 and put a TButton named BUTNHint in this TForm. Then paste the code below completely into the TForm's Unit and then double click on the button that was added and on the TForm's OnShow and OnCreate events to connect the handlers.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    BUTNHint: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure BUTNHintClick(Sender: TObject);
  private
    { Private declarations }
    FToolTipWindowHandle: HWND;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.CommCtrl;

{$R *.dfm}

procedure TForm1.BUTNHintClick(Sender: TObject);
var
  ToolInfo: TToolInfo;
begin
  if not (SendMessage(FToolTipWindowHandle,TTM_GETCURRENTTOOL,0,0) > 0) then
  begin
    ZeroMemory(@ToolInfo,SizeOf(TToolInfo));
    ToolInfo.cbSize := SizeOf(TToolInfo);

    SendMessage(FToolTipWindowHandle,TTM_TRACKACTIVATE,WPARAM(True),LPARAM(@ToolInfo));
  end
  else
  begin
    ZeroMemory(@ToolInfo,SizeOf(TToolInfo));
    ToolInfo.cbSize := SizeOf(TToolInfo);

    SendMessage(FToolTipWindowHandle,TTM_TRACKACTIVATE,WPARAM(False),LPARAM(@ToolInfo));
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FToolTipWindowHandle := CreateWindowEx(WS_EX_NOACTIVATE or WS_EX_TOPMOST
                                        ,TOOLTIPS_CLASS
                                        ,nil
                                        ,TTS_NOPREFIX or TTS_ALWAYSTIP or TTS_BALLOON or TTS_CLOSE
                                        ,0,0,0,0
                                        ,TApplication(Owner).Handle
                                        ,0
                                        ,HInstance
                                        ,nil);

  SendMessage(FToolTipWindowHandle,TTM_SETMAXTIPWIDTH,0,500);
  SendMessage(FToolTipWindowHandle,TTM_SETTITLE,TTI_INFO,LPARAM(PChar('Título do ToolTip neste SSCCE')));
end;

procedure TForm1.FormShow(Sender: TObject);
var
  ToolInfo: TToolInfo;
begin
  ZeroMemory(@ToolInfo,SizeOf(TToolInfo));

  ToolInfo.cbSize := SizeOf(TToolInfo);
  ToolInfo.uFlags := TTF_TRACK or TTF_PARSELINKS;
  ToolInfo.lpszText := 'Lorem ipsum dolor <a id="zzz">sit</a> amet, consectetur adipiscing ' 'elit. Nunc eu vulputate ipsum, in dignissim velit. Donec vitae massa rhoncus, tincidunt enim sit amet, venenatis augue. Fusce fringilla pellentesque ligula, ac facilisis enim feugiat a. Nam lacinia eu sed.';

  SendMessage(FToolTipWindowHandle,TTM_ADDTOOL,0,LPARAM(@ToolInfo));
end;

end.

When running the program press the button to display the ToolTip and click it again to hide the ToolTip. Note that this can be done over and over again, however, if you close the ToolTip by clicking its close button (X), the ToolTip will no longer appear, even by clicking the existing button on the TForm several times.

CodePudding user response:

After Sertac Akyuz's discovery of what actually happens when clicking the "X" button on a ToolTip balloon with the TTS_CLOSE style set, I was able to solve the problem by simply forcing the ToolTip to be hidden before actually showing it:

procedure TForm1.BUTNHintClick(Sender: TObject);
var
  ToolInfo: TToolInfo;
begin
  if not (SendMessage(FToolTipWindowHandle,TTM_GETCURRENTTOOL,0,0) > 0) then
  begin
    ZeroMemory(@ToolInfo,SizeOf(TToolInfo));
    ToolInfo.cbSize := SizeOf(TToolInfo);
    // Hide the ToolTip window to somehow "synchronize" the internal state of it with the
    // real visibility state, so, the message to show will be successful
    SendMessage(FToolTipWindowHandle,TTM_TRACKACTIVATE,WPARAM(False),LPARAM(@ToolInfo));
    SendMessage(FToolTipWindowHandle,TTM_TRACKACTIVATE,WPARAM(True),LPARAM(@ToolInfo));
  end
  else
  begin
    ZeroMemory(@ToolInfo,SizeOf(TToolInfo));
    ToolInfo.cbSize := SizeOf(TToolInfo);

    SendMessage(FToolTipWindowHandle,TTM_TRACKACTIVATE,WPARAM(False),LPARAM(@ToolInfo));
  end;
end;

According to what Sertac Akyuz discovered, I came to the conclusion that, when closing the balloon using the "X", the TooTip window is hidden, but some internal control of it, referring to the handling of the TTM_TRACKACTIVATE message is not updated, which makes so that, internally, the ToolTip window "thinks" it is already visible and simply ignores the TTM_TRACKACTIVATE message that should display it. Hiding the ToolTip window before showing it causes a kind of synchronization between what is actually happening and what the window "thinks" is happening.

For me this is a bug, because there is no mention of what happens when the "X" button is clicked in the official documentation and if there is no documentation saying that this is the functionality and, mainly, because it works that way then it is of indeed a bug, in my opinion.

  • Related