Delphi:菜单提示错误

Ada*_*aca 3 delphi menu hint

我从 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)

Rem*_*eau 5

WM_MENUSELECT告诉您菜单项是通过鼠标还是键盘选择的。

如果该MF_MOUSESELECT标志存在,则使用GetCursorPos()(或 VCL 的TMouse.CursorPos包装器)提供的鼠标坐标,或GetMessagePos()

如果该标志不存在,则用于GetMenuItemRect()获取指定菜单项的边界矩形的屏幕坐标,然后使用该矩形内所需的任何坐标(中心、底部边缘等)。

您根本不应该尝试直接使用菜单窗口,因此请不要调用FindWindow()GetWindowRect()PtInRect()