即使菜单项未启用,它是否仍然可以接收到OnClick事件?

4

我正在尝试让管理员通过Ctrl + 单击菜单项来启用/禁用我的应用程序的主菜单中的菜单项。为此,我在主窗体中注入了TMenuItem类的自定义版本,并覆盖了Click虚拟方法,如下所示:

uses
  Forms, Menus;

type
  TMenuItem = class(Menus.TMenuItem)
  public
    ControlActivationState: Boolean;
    procedure Click; override;
  end;

  TMyMainForm = class(TForm)

...

procedure TMenuItem.Click;
begin
  if ControlActivationState and IsKeyPressed(VK_CONTROL) then
    Self.Enabled := not Self.Enabled
  else
    inherited;
end;

它可以工作,但仅适用于顶级菜单。为什么即使禁用了顶级菜单项,它们仍然会接收OnClick事件,而其他菜单项却不会呢?有没有办法让子菜单项也接收这些事件?

3个回答

4
顶级的OnClick事件是通过接收WM_INITMENUPOPUP消息触发的。即使顶级项目被禁用,该消息也会被发送。我不确定为什么在这种情况下会发送该消息,但确实如此。对于具有子项的子项也是如此。
然而,对于没有子项的子项,OnClick是通过WM_COMMAND消息触发的。但是如果菜单项被禁用,系统甚至不会发送该消息。
您要尝试的事情无法轻松地完成。我唯一能想到的方法是处理原始的鼠标和键盘事件。个人而言,我不会考虑这样做。

1
我对于在禁用的顶部菜单上发送WM_INITMENUPOPUP消息的原因有些怀疑,因为实际上该菜单并没有弹出。但是我没有更好的解释。 - Sertac Akyuz
@SertacAkyuz 文档中说:当下拉菜单或子菜单即将变为活动状态时发送。这允许应用程序在显示菜单之前修改菜单,而不必更改整个菜单。 - David Heffernan
我并不是故意说话晦涩难懂。只是因为点击一个被禁用的顶部项目不会导致其菜单下拉,因此菜单没有被激活,但消息仍然被发送了。 - Sertac Akyuz
@SertacAkyuz 好的,我明白了。我猜这取决于应用程序是否显示菜单。也许默认行为(DefWindowProc)会显示菜单。 - David Heffernan
1
@SertacAkyuz 哦,好吧。我们只能推测了。 - David Heffernan
显示剩余2条评论

2

TMenuItem是TComponent的一种,即它不是窗口控件,并且没有经典事件。相反,发生在真实窗口控件上的点击事件将被委派给TMenuItem实例。我不知道哪个窗口控件是事件的“真实”主机,但即使我知道,确定对应于实际单击点的TMenuItem也将是困难的。

我的建议是为菜单编辑创建一个专用窗口,其中包含一个树状控件,该控件基于实际菜单布局在运行时通用地填充其项目,然后为反映相应菜单项的树节点提供启用/禁用功能。您可以保存/加载菜单项列表等。这应该比深入VCL的晦涩深处并强制执行如何从“真实”控件传播事件到称为TComponent的设计时表示更加清洁和容易...


1
你的第一段话没有意义。请参考David的答案了解菜单项点击是如何生成的。 - Sertac Akyuz
我的观点是,仅凭TMenuItem实例无法检测到点击,因为它是TComponent,不能直接接收Windows消息。 - Boris B.

0
事实上,你正在用一种困难的方式尝试解决问题...
解决你的问题的简单方法是重写TMenuItemOnDrawItem()方法,使其显示为禁用状态,并使用OnClick事件进行处理。
(不要忘记设置菜单的.OwnerDraw属性,以便使这个解决方案生效。)
编辑:
根据Delphi帮助文件,使用OnAdvancedDrawItem事件会更加简单,因为它提供了有关菜单项本身的信息。

不可能比绘制一个准确主题的控件更难。 - Daniel Santos
更难。如果您想捕获禁用菜单项的消息,您必须检索窗口菜单项的句柄并覆盖其功能。如果要绘制非活动菜单项,则必须将Canvas.Font.Color设置为clInactiveCaption。 - mg30rg
1
绘制一个准确的主题菜单项很难。如果这很容易,那么Emba就能正确地完成它了。这就是为什么我的应用程序不使用有缺陷的Emba代码并让系统绘制主题菜单的原因。系统做得对。 - David Heffernan
作为一种妥协,可以在管理员模式下使用这个技巧。也就是说,只有管理员能够看到那些丑陋的非标准项。 - Uli Gerhardt
那就是计划 @Uri - Daniel Santos
我没有使用你的“解决方案”@mg30rg,我的评论是针对@Uli的,只有管理员才能看到修改后的菜单。实际上,我使用了@Boris的建议(+1),但我仍然决定接受@David的答案,因为我认为这是问题的最佳答案。 - Daniel Santos

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