我正在尝试通过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事件,即使它们被禁用而其他菜单项也没有? 有没有办法让子菜单项也接收这些事件?
答案 0 :(得分:4)
通过收到OnClick
消息触发顶级WM_INITMENUPOPUP
事件。即使禁用顶级项目,也会发送该消息。我不确定为什么会在那种情况下发送,但确实如此。对于有孩子的子项也是如此。
但是,对于没有子项的子项,OnClick
由WM_COMMAND
消息触发。但是,如果菜单项被禁用,系统甚至都不会发送消息。
你想做的事情不容易做到。我能看到你这么做的唯一方法是处理原始的鼠标和键盘事件。就个人而言,我不打算这样做。
答案 1 :(得分:2)
TMenuItem是一个TComponent,即它不是一个窗口控件,它没有经典事件。相反,在真实窗口控件上发生的单击事件将委派给TMenuItem实例。我不知道哪个窗口控件是事件的真实主机,但即使我这样做,我认为很难确定哪个TMenuItem对应于实际的点击点。
我的建议是使用树控件创建一个专用的菜单编辑窗口,该控件在运行时根据实际的菜单布局一般填充其项目,然后为树节点提供启用/禁用反映相应的菜单项。然后你可以保存/加载menuitem列表等。这应该更清晰,更容易,然后潜入VCL的阴暗深处,并弄清楚(和重写)事件如何从'真实'控件传播到名为{{的设计时表示1}}Š...
答案 2 :(得分:0)
事实上,你正在努力做到这一点......
解决问题的简单方法是覆盖OnDrawItem()
的{{1}}方法,将其显示为已禁用,并替代处理TMenuItem
事件。
(不要忘记设置菜单的OnClick
属性以使此解决方案有效。)
编辑:
根据Delphi帮助使用.OwnerDraw
事件使其更容易,因为它提供了关于menuitem本身的信息。