加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 在弹出菜单的禁用菜单项上显示工具提示提示

发布时间:2020-12-15 09:30:49 所属栏目:大数据 来源:网络整理
导读:所以我有一个TMenuItem附加到TPopupMenu上的TAction为TDBGrid(实际上是第三方,但你明白了).根据网格中选定的行,启用或禁用TAction.我想要的是能够向用户显示提示,解释禁用该项目的原因. 至于为什么我想要一个关于禁用的菜单项的提示,我们只能说我是in agreem
所以我有一个TMenuItem附加到TPopupMenu上的TAction为TDBGrid(实际上是第三方,但你明白了).根据网格中选定的行,启用或禁用TAction.我想要的是能够向用户显示提示,解释禁用该项目的原因.

至于为什么我想要一个关于禁用的菜单项的提示,我们只能说我是in agreement with Joel.

所有TMenuItem都有一个提示属性,但我最好告诉他们只使用TApplicationEvent.OnHint事件处理程序将提示粘贴在TStatusBar或其他一些特殊处理中. I found an article关于如何为TMainMenu的TMenuItems创建自己的平均窗口,但它不适用于TPopupMenu的TMenuItem.它的工作原理是处理WM_MENUSELECT消息,据我所知,它不是在TPopupMenu上发送的.

解决方法

WM_MENUSELECT确实也用于弹出菜单中的菜单项,但不是由包含(弹出)菜单的窗体的窗口proc处理,而是由Menus.PopupList创建的隐形辅助窗口处理.幸运的是,你可以(至少在Delphi 5下)通过Menus.PopupList.Window获得此HWND.

现在,您可以使用旧式方法对窗口进行子类化,如此CodeGear article中所述,以便为弹出菜单处理WM_MENUSELECT.从创建第一个TPopupMenu到销毁最后一个TPopupMenu对象之前,HWND将有效.

在问题中的链接文章中使用演示应用程序进行快速测试应该会发现这是否有效.

编辑:确实有效.我更改了the linked example以显示弹出菜单的提示.以下是步骤:

为OnDestroy添加一个处理程序,为旧窗??口proc添加一个成员变量,为表单添加一个新窗口proc的方法:

TForm1 = class(TForm)
  ...
  procedure FormCreate(Sender: TObject);
  procedure FormDestroy(Sender: TObject);
  procedure ApplicationEvents1Hint(Sender: TObject);
private
  miHint : TMenuItemHint;
  fOldWndProc: TFarProc;
  procedure WMMenuSelect(var Msg: TWMMenuSelect); message WM_MENUSELECT;
  procedure PopupListWndProc(var AMsg: TMessage);
end;

更改窗体的OnCreate处理程序以子类化隐藏的PopupList窗口,并在OnDestroy处理程序中实现窗口proc的正确恢复:

procedure TForm1.FormCreate(Sender: TObject);
var
  NewWndProc: TFarProc;
begin
  miHint := TMenuItemHint.Create(self);

  NewWndProc := MakeObjectInstance(PopupListWndProc);
  fOldWndProc := TFarProc(SetWindowLong(Menus.PopupList.Window,GWL_WNDPROC,integer(NewWndProc)));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  NewWndProc: TFarProc;
begin
  NewWndProc := TFarProc(SetWindowLong(Menus.PopupList.Window,integer(fOldWndProc)));
  FreeObjectInstance(NewWndProc);
end;

实现子类窗口proc:

procedure TForm1.PopupListWndProc(var AMsg: TMessage);

  function FindItemForCommand(APopupMenu: TPopupMenu;
    const AMenuMsg: TWMMenuSelect): TMenuItem;
  var
    SubMenu: HMENU;
  begin
    Assert(APopupMenu <> nil);
    // menuitem
    Result := APopupMenu.FindItem(AMenuMsg.IDItem,fkCommand);
    if Result = nil then begin
      // submenu
      SubMenu := GetSubMenu(AMenuMsg.Menu,AMenuMsg.IDItem);
      if SubMenu <> 0 then
        Result := APopupMenu.FindItem(SubMenu,fkHandle);
    end;
  end;

var
  Msg: TWMMenuSelect;
  menuItem: TMenuItem;
  MenuIndex: integer;
begin
  AMsg.Result := CallWindowProc(fOldWndProc,Menus.PopupList.Window,AMsg.Msg,AMsg.WParam,AMsg.LParam);
  if AMsg.Msg = WM_MENUSELECT then begin
    menuItem := nil;
    Msg := TWMMenuSelect(AMsg);
    if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then begin
      for MenuIndex := 0 to PopupList.Count - 1 do begin
        menuItem := FindItemForCommand(PopupList.Items[MenuIndex],Msg);
        if menuItem <> nil then
          break;
      end;
    end;
    miHint.DoActivateHint(menuItem);
  end;
end;

这是针对循环中的所有弹出菜单完成的,直到找到第一个匹配项或子菜单.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读