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 事件,而其他菜单项却没有?有没有办法让子菜单项也接收这些事件?

4

3 回答 3

4

顶级OnClick事件由收到WM_INITMENUPOPUP消息触发。即使顶级项目被禁用,也会发送该消息。我不确定为什么在那种情况下发送它,但确实如此。对于有子项的子项也是如此。

但是,对于没有子项的子项,OnClickWM_COMMAND消息触发。但是如果菜单项被禁用,系统甚至不会发送消息。

你试图做的事情不能轻易完成。我能看到你这样做的唯一方法是处理原始的鼠标和键盘事件。就个人而言,我不会考虑这样做。

于 2013-08-07T14:01:57.373 回答
2

TMenuItem 是一个 TComponent,即它不是一个窗口控件并且它没有经典事件。相反,实际窗口控件上发生的单击事件被委托给 TMenuItem 实例。我不知道哪个窗口控件是事件的真正宿主,但即使我知道,我认为也很难确定哪个 TMenuItem 对应于实际的点击点。

我的建议是使用树控件创建一个用于菜单编辑的专用窗口,该树控件通常在运行时根据实际菜单布局填充其项目,然后为反映相应菜单项的树节点提供启用/禁用。然后,您可以保存/加载 menuitem 列表等。这应该更清晰、更容易,然后深入 VCL 的阴暗深处并弄清楚(并覆盖)事件如何从“真实”控件传播到称为TComponents 的设计时表示。 ..

于 2013-08-07T13:36:06.767 回答
0

事实上,你正在努力做到这一点......

解决您的问题的简单方法是覆盖OnDrawItem()您的方法以将TMenuItem其显示为已禁用,并OnClick交替处理该事件。

(不要忘记设置.OwnerDraw菜单的属性以使此解决方案起作用。)

编辑:

根据 Delphi 的帮助,使用该OnAdvancedDrawItem事件使其更容易,因为它提供了有关菜单项本身的信息。

于 2013-08-07T13:36:37.913 回答