Delphi:菜单提示错误

3
我从ThoughtCo. (Zarko Gajic)的网站中获取以下代码 - 它在菜单项上方的鼠标指针附近显示提示信息:

Submenu opened with hovering mouse cursor, showing item's hint

然而,它有一个bug:当菜单被键盘打开时,无论鼠标指针在屏幕上的位置如何,工具提示都会出现在鼠标指针旁边:

Submenu opened, mouse cursor outside menu item, still showing item's hint

我尝试通过添加注释的行来修复该错误。现在的错误是,无论是否快速单击菜单项,提示都会始终出现。
如何解决这个问题?
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;
1个回答

5
WM_MENUSELECT告诉你菜单项是通过鼠标还是键盘选择的。如果存在MF_MOUSESELECT标志,请使用由GetCursorPos()(或VCL的TMouse.CursorPos包装器)提供的鼠标坐标,或者使用GetMessagePos()。如果不存在该标志,则使用GetMenuItemRect()获取指定菜单项边界矩形的屏幕坐标,然后使用该矩形内的任何坐标(居中、底部边缘等)。您不应该直接操作菜单窗口,因此请删除对FindWindow()GetWindowRect()PtInRect()的调用。

好的 Remy。我会尝试修复它。非常感谢你的回答。 - Adalberto José Brasaca
Remy...我做到了。我按照你说的删除了代码中的注释行,并在“miHint.DoActivateHint(menuItem)”之前添加了一行“if Msg.MenuFlag and MF_MOUSESELECT = MF_MOUSESELECT then”,现在它可以正常工作了!再次感谢。 - Adalberto José Brasaca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接