为什么使用 TTF_CENTERTIP 标志会使 ToolTip 气球样式恢复为 Windows XP 样式以及如何解决此问题?

发布于 2025-01-16 05:54:55 字数 4583 浏览 0 评论 0 原文

我注意到,在使用 TTM_ADDTOOL 将工具提示设置添加到具有 TTS_BALLOON 样式的工具提示窗口时使用 TTF_CENTERTIP 标志会导致此工具提示不以 Windows 10 样式出现。换句话说,气球显示为圆形边缘,就像 Windows XP 中气球的样式一样。

如果不使用 TTF_CENTERTIP,气球会以正确的样式显示,如上所示,但是...

使用 TTF_CENTERTIP 时将样式更改为“旧样式”

使用 TTF_CENTERTIP 标志时,样式将更改为“旧样式”。问题很简单,为什么会发生这种情况以及如何根据应用程序运行的操作系统使气球始终具有最新的样式?

下面是示例代码。创建一个 Windows VCL 应用程序项目,其中主窗体称为 Form1,并在此窗体中粘贴两个名为“BUTN1”和“BUTN2”的按钮 (TButton)。完成此操作后,只需将下面的所有代码粘贴到 Form1

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    BUTN1: TButton;
    BUTN2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FHwndTip: HWND;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.CommCtrl;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  TI: TToolInfo;
begin
  FHwndTip := CreateWindowEx(WS_EX_NOACTIVATE or WS_EX_TOPMOST
                            ,TOOLTIPS_CLASS
                            ,nil
                            ,TTS_ALWAYSTIP or TTS_BALLOON
                            ,0,0,0,0
                            ,Self.Handle
                            ,0
                            ,HInstance
                            ,nil);

  SendMessage(FHwndTip,TTM_SETTITLE,TTI_INFO,LPARAM(PChar('Title')));
  SendMessage(FHwndTip,TTM_SETMAXTIPWIDTH,0,300);

  ZeroMemory(@TI,SizeOf(TToolInfo));

  TI.cbSize := SizeOf(TToolInfo);
  TI.hwnd := Self.Handle;

  TI.uId := BUTN1.Handle;
  TI.lpszText := 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tincidunt dictum dui vel luctus. Duis ornare arcu a varius pharetra. Curabitur tempor sit amet dui id malesuada. Aliquam efficitur, massa consectetur tristique iaculis, dolor diam tincidunt.';
  TI.uFlags := TTF_IDISHWND or TTF_SUBCLASS;
  SendMessage(FHwndTip,TTM_ADDTOOL,0,LPARAM(@TI));

  TI.uId := BUTN2.Handle;
  TI.lpszText := 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tincidunt dictum dui vel luctus. Duis ornare arcu a varius pharetra. Curabitur tempor sit amet dui id malesuada. Aliquam efficitur, massa consectetur tristique iaculis, dolor diam tincidunt.';
  TI.uFlags := TTF_IDISHWND or TTF_SUBCLASS or TTF_CENTERTIP;
  SendMessage(FHwndTip,TTM_ADDTOOL,0,LPARAM(@TI));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DestroyWindow(FHwndTip);
end;

end.

Update 1

单元中。为了尝试解决此问题,我转到新的“Microsoft Stack Overflow”并在那里提出了相同的问题。就在那时,我发现问题不在于我的代码,而在于 Delphi 可能做的事情,但是什么?

https://learn.microsoft.com/en-us/answers/questions/786101/why-using-the-ttf-centertip-flag-makes-the-tooltip.html?childToView=786169

一位用户好心地帮助我尝试使用 VS 重现该问题。结果是问题没有发生。会是什么?

更新 2

另一位用户表示,他能够使用与他无法重现该问题的人相同的工具重现该问题 (VS2022)。现在事情变得更加复杂了,因为我依靠这两个人的善意来弄清楚为什么其中一个能够看到问题而另一个却不能。我很确定如果这个“细节”被发现 我将能够在 Delphi

Update 3

中应用该解决方案在多次尝试解决此问题后,我得出的结论是,这确实是 Windows API 中的一个错误。在Microsoft Q&A中一些用户的帮助下,我们发现,当使用CreateDialog函数创建窗口时,使用TTF_CENTERTIP标志使其看起来像Windows XP,但是Delphi没有使用CeateDialog,而是使用CreateWindowEx两者都创建应用程序窗口(TApplication)和主窗体。

在我的一项测试中,我显示了通常隐藏的 TApplication 窗口,我在其中放置了一个按钮,我使用 TTF_CENTERTIP 标志为该按钮创建并配置了一个工具提示窗口,在这种情况下,工具提示正确显示,即,对于使用 CreateWindowEx 创建的 TApplication 窗口有效,但对于同样使用 CreateWindowEx 创建的 TForm1 窗口则不起作用。有什么区别??!!

我认为这可能与窗口样式有关,我将样式从 TApplication 窗口复制到 TForm1,但没有成功。

在另一次找出问题原因的尝试中,我仅使用 Windows API 函数创建了一个应用程序,因此我能够创建 2 个窗口,将工具提示放在第二个窗口中,以检查它是否与“成为某物”有关。放在第二个应用程序窗口中”,但我也没有成功。原始示例(只有一个主窗口)可以在这里找到: https://osdn.net /users/derekwildstar/pastebin/7879

我还完成了第二个示例,使用 CreateDialog 仅使用 API 调用来重现问题。这是这个示例: https://osdn.net/users/derekwildstar/pastebin/7912

嗯,在微软的问答中,有人说他把这个问题转给了“团队”,让我们看看他们是否至少解释一下为什么会出现这种情况,如果这是正常的,那么也许在那之后我可以想出一种方法来解决 Delphi 中的问题

I noticed that using the TTF_CENTERTIP flag when adding a ToolTip setting using TTM_ADDTOOL to a ToolTip window that has the TTS_BALLOON style causes this ToolTip to not appear with the Windows 10 style. In other words the balloon appears with rounded edges, as was the style of balloons in Windows XP.

Without using TTF_CENTERTIP the balloon appears with the correct style

Without using TTF_CENTERTIP the balloon appears with the correct style as seen above, however...

When using the TTF_CENTERTIP flag the style changes to "old style"

When using the TTF_CENTERTIP flag the style changes to "old style". The question is simple, why does this happen and how to make the balloons always have the latest style according to the OS on which the application runs?

Below is sample code. Create a Windows VCL Application project, where the main form is called Form1 and paste in this form two buttons (TButton) named "BUTN1" and "BUTN2". After doing this, simply paste all the code below in the unit of Form1

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    BUTN1: TButton;
    BUTN2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FHwndTip: HWND;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  Winapi.CommCtrl;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  TI: TToolInfo;
begin
  FHwndTip := CreateWindowEx(WS_EX_NOACTIVATE or WS_EX_TOPMOST
                            ,TOOLTIPS_CLASS
                            ,nil
                            ,TTS_ALWAYSTIP or TTS_BALLOON
                            ,0,0,0,0
                            ,Self.Handle
                            ,0
                            ,HInstance
                            ,nil);

  SendMessage(FHwndTip,TTM_SETTITLE,TTI_INFO,LPARAM(PChar('Title')));
  SendMessage(FHwndTip,TTM_SETMAXTIPWIDTH,0,300);

  ZeroMemory(@TI,SizeOf(TToolInfo));

  TI.cbSize := SizeOf(TToolInfo);
  TI.hwnd := Self.Handle;

  TI.uId := BUTN1.Handle;
  TI.lpszText := 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tincidunt dictum dui vel luctus. Duis ornare arcu a varius pharetra. Curabitur tempor sit amet dui id malesuada. Aliquam efficitur, massa consectetur tristique iaculis, dolor diam tincidunt.';
  TI.uFlags := TTF_IDISHWND or TTF_SUBCLASS;
  SendMessage(FHwndTip,TTM_ADDTOOL,0,LPARAM(@TI));

  TI.uId := BUTN2.Handle;
  TI.lpszText := 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tincidunt dictum dui vel luctus. Duis ornare arcu a varius pharetra. Curabitur tempor sit amet dui id malesuada. Aliquam efficitur, massa consectetur tristique iaculis, dolor diam tincidunt.';
  TI.uFlags := TTF_IDISHWND or TTF_SUBCLASS or TTF_CENTERTIP;
  SendMessage(FHwndTip,TTM_ADDTOOL,0,LPARAM(@TI));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DestroyWindow(FHwndTip);
end;

end.

Update 1

In order to try to solve this problem I went to the new "Microsoft Stack Overflow" and asked the same question there. It was then that I discovered that the problem is not with my code, but with something Delphi probably does, but what?

https://learn.microsoft.com/en-us/answers/questions/786101/why-using-the-ttf-centertip-flag-makes-the-tooltip.html?childToView=786169

A user kindly did me the favor of trying to reproduce the problem using VS. The result was that the problem does not happen. What can it be?

Update 2

Another user said he was able to reproduce the problem using the same tool as the one who said he couldn't reproduce it (VS2022). Now it's gotten even more complicated, as I rely on the goodwill of these two individuals to figure out why one of them can see the problem and the other can't. I'm pretty sure that if this "detail" is discovered,
I will be able to apply the solution in Delphi

Update 3

After several attempts to resolve this issue I came to the conclusion that this is indeed a bug in the Windows API. With the help of some users in Microsoft Q&A we were able to discover that when using the CreateDialog function, to create a window, using the TTF_CENTERTIP flag makes it look like Windows XP, however Delphi is not using CeateDialog, it is using CreateWindowEx both to create the application window (TApplication) and the main Form.

In one of my tests I showed the TApplication window, which is normally hidden, I put a button in it, I created and configured a ToolTip window for this button with the TTF_CENTERTIP flag and, in this case, the ToolTip appeared correctly, that is, for the TApplication window created with CreateWindowEx works, but for TForm1 window created also with CreateWindowEx it doesn't work. What is the difference??!!

Thinking it might be something related to the window styles I copied the styles from the TApplication window to TForm1 and was not successful.

In another attempt to find out the cause of the problem, I created an application using only Windows API functions and so I was able to create 2 windows, putting the ToolTip in the second one to check if it had something to do with "being something placed in the second application window", but I didn't succeed either. The original example (with only one main Window) can be found here: https://osdn.net/users/derekwildstar/pastebin/7879.

I've also done a second example, using CreateDialog to reproduce the problem using just API calls. Here is this example: https://osdn.net/users/derekwildstar/pastebin/7912

Well, in Microsoft's Q&A one person said he passed this problem on to "the team", let's see if they at least explain why this occurs, if it's normal, then maybe after that I can come up with a way to solve the problem in Delphi

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文