为什么点击"X"按钮后无法再次显示TTS_CLOSE样式的气球ToolTip?这是正确的行为吗?

Why a balloon ToolTip with TTS_CLOSE style cannot be displayed again after the "X" button being clicked? Is this a correct behaviour?

我正在创建一个带有附加样式的气球工具提示 (TTS_BALLOON),使“X”按顺序出现在该气球的右上角关闭它 (TTS_CLOSE).

我正在创建的工具提示类型是“跟踪”,即我通过 TTM_TRACKACTIVATE 消息按需显示工具提示,因为它已得到正确解释在 MSDN 上。工具提示正常工作,在发送消息 TTM_TRACKACTIVATE 时为 displayed/hidden,但是,在显示工具提示并单击“X”后,它被正确隐藏,但是无法再以任何方式再次显示工具提示,甚至不使用 TTM_TRACKACTIVATE ,也不使用 TTM_POPUP .在 Visual Studio 论坛 (https://social.msdn.microsoft.com/Forums/vstudio/en-US/8ff12b85-c0a5-4a69-87d5-0a13ea9c43b0/help-with-ttsclose-style) 上有人提出了类似的问题,但直到今天作者也没有得到答案。

说到 TTM_POPUP 及其对应的 TTM_POP,在发送 TTM_POP 消息,“从屏幕上删除工具提示”,我无法再显示它,使用 TTM_POPUPTTM_TRACKACTIVATE,即TTM_POP和点击“X”的效果是一样的,按我的理解,仅用于破坏工具提示并使其无法使用。

我正在 Pascal (Delphi) 中开发 class 以促进工具提示的创建和操作,现在我正在处理 TTS_CLOSE 我不明白为什么会这样。这是正常的?这是 Windows API 错误吗?

下面是一个示例代码。要重现该问题,请创建类型为 Windows VCL Application 的项目,其唯一的 TForm 名为 Form1 并放置一个名为 BUTNHint 在这个 TForm 中。然后将下面的代码完全粘贴到 TForm 的 Unit 中,然后双击添加的按钮和 TForm 的 OnShow 和 OnCreate 事件以连接处理程序。

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.

当运行程序按下按钮显示工具提示,再次点击隐藏工具提示。请注意,这可以一遍又一遍地完成,但是,如果您通过单击其关闭按钮 (X) 关闭工具提示,工具提示将不再出现,即使单击现有按钮也是如此在 TForm 上多次。

Sertac Akyuz 发现单击具有 TTS_CLOSE 样式集的工具提示气球上的“X”按钮时实际发生的情况后,我能够通过简单地在实际显示之前强制隐藏工具提示来解决问题:

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;

根据Sertac Akyuz的发现,我得出的结论是,当使用“X”关闭气球时,TooTip window是隐藏的,但有一些内部控制,参考TTM_TRACKACTIVATE 消息的处理未更新,这使得工具提示 window 在内部“认为”它已经可见,并简单地忽略了应该显示它的 TTM_TRACKACTIVATE 消息.在显示之前隐藏工具提示 window 会导致实际发生的事情与 window“认为”发生的事情之间的某种同步。

对我来说这是一个错误,因为在官方文档中没有提到单击“X”按钮时会发生什么,如果没有文档说明这是功能,主要是因为它以这种方式工作然后它确实是一个错误,在我看来。