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



我正在创建一个气球工具提示(TTS_ALLOON(,它具有一个附加样式;X〃;显示在此气球的右上角,以便将其关闭(TTS_close(。

我正在创建的工具提示的类型是";"跟踪";,即我通过TTM_TRACKACTIVATE消息按需显示工具提示,MSDN上对此进行了正确解释。工具提示工作正常,在发送消息TTM_TRACKACTIVATE时显示/隐藏,但是,在显示工具提示并单击";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及其对应的TTP_POP,在发送TTM_POP消息之后;从屏幕上删除工具提示";,无论是用TTM_POPUP还是用TTM_TRACKACTIVATE,我都无法再显示它,也就是说,TTP_POP具有与单击";X〃;,在我看来,这只会破坏工具提示并使其无法使用。

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

下面是一个示例代码。若要重现此问题,请创建一个Windows VCL Application类型的项目,其唯一的TForm名为Form1,并在此TForm中放入一个名为
BUTNInt的TButton。然后将下面的代码完全粘贴到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发现点击";X〃;按钮在带有TTS_CLOSE样式集的工具提示气球上,我可以通过在实际显示之前强制隐藏工具提示来解决问题:

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窗口是隐藏的,但它的一些内部控制(涉及TTM_TRACKACTIVATE消息的处理(没有更新,这使得在内部;认为";它已经是可见的,并且简单地忽略应该显示它的TTM_TRACKACTIVATE消息;认为";正在发生。

对我来说,这是一个错误,因为没有提到当";X〃;在官方文档中点击按钮,如果没有文档说明这是功能,主要是因为它是这样工作的,那么在我看来,这确实是一个bug。

最新更新