我从 ThoughtCo 网站上得到了下面的代码。(Zarko Gajic) - 当鼠标指针位于菜单项中时,它会在鼠标指针附近显示提示:

但是,它有一个错误:当通过键盘打开菜单时,无论鼠标指针在屏幕上的位置如何,工具提示都会出现在鼠标指针旁边:

我尝试通过添加注释行来修复该错误。现在的错误是,无论您是否快速单击菜单项,提示总是出现。
如何解决这个问题?
procedure TfrmPrincipal.WMMenuSelect(var Msg: TWMMenuSelect);
var
menuItem : TMenuItem;
hSubMenu : HMENU;
hPopupWnd: HWND; // Added
R: TRect; // Added
Pt: TPoint; // Added
begin
inherited;
menuItem := nil;
if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then
begin
if Msg.MenuFlag and MF_POPUP = MF_POPUP then
begin
hSubMenu := GetSubMenu(Msg.Menu, Msg.IDItem);
menuItem := Self.Menu.FindItem(hSubMenu, fkHandle);
end
else
begin
menuItem := Self.Menu.FindItem(Msg.IDItem, fkCommand);
end;
end;
hPopupWnd := FindWindow('#32768', nil); // Added
if hPopupWnd = 0 then Exit; // Added
GetWindowRect(hPopupWnd, R); // Added
GetCursorPos(Pt); // Added
if PtInRect(R, Pt) then // Added
miHint.DoActivateHint(menuItem)
else // Added
miHint.DoActivateHint(nil); // Added
end;
constructor TMenuItemHint.Create(AOwner: TComponent);
begin
inherited;
showTimer := TTimer.Create(self);
showTimer.Interval := Application.HintPause;
hideTimer := TTimer.Create(self);
hideTimer.Interval := Application.HintHidePause;
end;
destructor TMenuItemHint.Destroy;
begin
hideTimer.OnTimer := nil;
showTimer.OnTimer := nil;
self.ReleaseHandle;
inherited;
end;
procedure TMenuItemHint.DoActivateHint(menuItem: TMenuItem);
begin
hideTime(self);
if (menuItem = nil) or (menuItem.Hint = '') then
begin
activeMenuItem := nil;
Exit;
end;
activeMenuItem := menuItem;
showTimer.OnTimer := ShowTime;
hideTimer.OnTimer := HideTime;
end;
procedure TMenuItemHint.HideTime(Sender: TObject);
begin
self.ReleaseHandle;
hideTimer.OnTimer := nil;
end;
procedure TMenuItemHint.ShowTime(Sender: TObject);
var
r : TRect;
wdth : integer;
hght : integer;
begin
if activeMenuItem <> nil then
begin
wdth := Canvas.TextWidth(activeMenuItem.Hint);
hght := Canvas.TextHeight(activeMenuItem.Hint);
r.Left := Mouse.CursorPos.X + 16;
r.Top := Mouse.CursorPos.Y + 16;
r.Right := r.Left + wdth + 6;
r.Bottom := r.Top + hght + 4;
ActivateHint(r,activeMenuItem.Hint);
end;
showTimer.OnTimer := nil;
end;
Run Code Online (Sandbox Code Playgroud)
WM_MENUSELECT告诉您菜单项是通过鼠标还是键盘选择的。
如果该MF_MOUSESELECT标志存在,则使用GetCursorPos()(或 VCL 的TMouse.CursorPos包装器)提供的鼠标坐标,或GetMessagePos()。
如果该标志不存在,则用于GetMenuItemRect()获取指定菜单项的边界矩形的屏幕坐标,然后使用该矩形内所需的任何坐标(中心、底部边缘等)。
您根本不应该尝试直接使用菜单窗口,因此请不要调用FindWindow()、GetWindowRect()和PtInRect()。