首页 > 解决方案 > 如何在 ActionMainMenuBar 中禁用 menuitem 并停止下拉菜单?

问题描述

Delphi 10.4.2 我的 TActionMainMenuBar 有问题。当我在代码中禁用菜单项时,它显示为已禁用,但如果我在它旁边下拉启用的菜单项,然后移动到禁用的菜单项,它的子菜单会下拉!如果这不是错误,是否有办法防止禁用的菜单项下拉?

谢谢托尼

标签: delphimenuitem

解决方案


一个简单的解决方案是在TActionMainMenuBar.OnPopup禁用项目时关闭菜单:

procedure TForm1.ActionMainMenuBar1Popup(Sender: TObject; Item: TCustomActionControl);
begin
  if not Item.Enabled then
    ActionMainMenuBar1.CloseMenu;
end;

但是我不建议这样做,因为它也会退出菜单循环,这可能会导致糟糕的用户体验。

您描述的行为可以被视为缺陷,您可以将其报告给 Embarcadero。要在您的代码中解决此问题,您应该覆盖方法CreatePopupTActionMainMenuBar防止nil为禁用的项目创建弹出菜单(返回)。但是nil在使用该方法打开子菜单时返回该方法会导致另一个问题(访问冲突)↑</kbd> or ↓</kbd> on keyboard. Therefore you should handle that case too by patching WMKeyDown. Ideally you should derive your own class from TActionMainMenuBar or use an interposer class:

type
  TActionMainMenuBar = class(Vcl.ActnMenus.TActionMainMenuBar)
  private
    procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
  protected
    function CreatePopup(AOwner: TCustomActionMenuBar;
      Item: TCustomActionControl): TCustomActionPopupMenu; override;
  end;

{ ... }


function TActionMainMenuBar.CreatePopup(AOwner: TCustomActionMenuBar;
  Item: TCustomActionControl): TCustomActionPopupMenu;
begin
  if Item.Enabled then
    Result := inherited CreatePopup(AOwner, Item)
  else
    Result := nil;
end;

procedure TActionMainMenuBar.WMKeyDown(var Message: TWMKeyDown);
begin
  if Assigned(Selected) and (not Selected.Control.Enabled) and
     (Orientation in [boLeftToRight, boRightToLeft]) and
     (Message.CharCode in [VK_UP, VK_DOWN]) then
    Exit; { do not try to popup disabled items }
  inherited;
end;

推荐阅读