Delphi TActionMainMenu辅助窗体上的加速器

Delphi TActionMainMenu辅助窗体上的加速器,delphi,Delphi,我正在Windows10中使用DelphiXe7。我在主窗体和模态次窗体上都有一个TMainMenuBar。问题在于,如果辅助窗体还包含TMemo,则辅助窗体上的加速键不会激活菜单。例如,如果辅助窗体具有“文件”菜单,则Alt+F不会打开“文件”菜单。但是,如果按下并释放alt,文件将高亮显示,F将加下划线,按F将打开菜单。请注意,如果卸下TMemo,问题就会消失。此外,主窗体上的Tmemo不会导致主窗体上的菜单出现问题 我已经在次要表单上搜索了TActionMainMenuBar加速键,但是没

我正在Windows10中使用DelphiXe7。我在主窗体和模态次窗体上都有一个TMainMenuBar。问题在于,如果辅助窗体还包含TMemo,则辅助窗体上的加速键不会激活菜单。例如,如果辅助窗体具有“文件”菜单,则Alt+F不会打开“文件”菜单。但是,如果按下并释放alt,文件将高亮显示,F将加下划线,按F将打开菜单。请注意,如果卸下TMemo,问题就会消失。此外,主窗体上的Tmemo不会导致主窗体上的菜单出现问题


我已经在次要表单上搜索了TActionMainMenuBar加速键,但是没有一个点击描述了这个特定的问题,尽管讨论了这个组件和加速键的其他问题。有人知道如何在两种表单上都使用TActionMainMenuBar的同时实现所需的行为吗?出于各种原因,我不喜欢使用标准TMenu。

这是VCL设计问题。下面的解释可能有点离题。我使用XE2进行跟踪,其行为并不完全相同。您可能需要在解决方案部分省去其中一个消息处理程序

菜单栏加速器生成WM_SYSCOMMAND消息。API中给出了确切的加速器案例:

如果wParam是SC_KEYMENU,则lParam包含 与ALT键一起使用以显示弹出菜单的键。对于 例如,按ALT+F显示文件弹出窗口将导致 WM_SYSCOMMAND,wParam等于SC_键菜单,lParam等于“f”

动作菜单栏是专有的VCL组件。因此,表单的默认窗口过程没有机会为它们处理加速器消息。组件本身有代码来模拟TCustomActionMainMenuBar.WMSysCommand的行为,但必须向其发送消息才能做到这一点。VCL的设计问题是,只有主窗体上的操作菜单栏才有机会

TWinControl接收WM_SYSCOMMAND次窗体本身或本例中的memo,使其父窗体次窗体执行CM_APPSYSCOMMAND。收到消息后,表单会再次将消息发送到应用程序窗口。应用程序的CM_APPSYSCOMMAND处理程序将消息再次转换为WM_SYSCOMMAND并将其发送到主窗体

我只能猜测,但这个设计背后的目的是,能够从没有菜单栏的二级表单访问主菜单

在任何情况下,除了切换到本机菜单外,在VCL处理消息之前,您必须截取消息并将其转发到次窗体上的操作菜单栏。有其他方法可以实现这一点,但我尝试并似乎奏效的是:

type
  TSecondaryForm = class(TForm)
    ...
  protected
    procedure CMAppsyscommand(var Message: TMessage); message CM_APPSYSCOMMAND;
    procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
    ...


procedure TSecondaryForm.CMAppsyscommand(var Message: TMessage);
begin
  if ActionMainMenuBar1.Perform(PMessage(Message.LParam).Msg,,
      PMessage(Message.LParam).WParam, PMessage(Message.LParam).LParam) = 0 then
    inherited;
end;

// you may not need the below handler
procedure TSecondaryForm.WMSysCommand(var Message: TWMSysCommand);
begin
  if ActionMainMenuBar1.Perform(Message.Msg,
      TMessage(Message).WParam, TMessage(Message).LParam) = 0 then
    inherited;
end;

这是一个VCL设计问题。下面的解释可能有点离题。我使用XE2进行跟踪,其行为并不完全相同。您可能需要在解决方案部分省去其中一个消息处理程序

菜单栏加速器生成WM_SYSCOMMAND消息。API中给出了确切的加速器案例:

如果wParam是SC_KEYMENU,则lParam包含 与ALT键一起使用以显示弹出菜单的键。对于 例如,按ALT+F显示文件弹出窗口将导致 WM_SYSCOMMAND,wParam等于SC_键菜单,lParam等于“f”

动作菜单栏是专有的VCL组件。因此,表单的默认窗口过程没有机会为它们处理加速器消息。组件本身有代码来模拟TCustomActionMainMenuBar.WMSysCommand的行为,但必须向其发送消息才能做到这一点。VCL的设计问题是,只有主窗体上的操作菜单栏才有机会

TWinControl接收WM_SYSCOMMAND次窗体本身或本例中的memo,使其父窗体次窗体执行CM_APPSYSCOMMAND。收到消息后,表单会再次将消息发送到应用程序窗口。应用程序的CM_APPSYSCOMMAND处理程序将消息再次转换为WM_SYSCOMMAND并将其发送到主窗体

我只能猜测,但这个设计背后的目的是,能够从没有菜单栏的二级表单访问主菜单

在任何情况下,除了切换到本机菜单外,在VCL处理消息之前,您必须截取消息并将其转发到次窗体上的操作菜单栏。有其他方法可以实现这一点,但我尝试并似乎奏效的是:

type
  TSecondaryForm = class(TForm)
    ...
  protected
    procedure CMAppsyscommand(var Message: TMessage); message CM_APPSYSCOMMAND;
    procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
    ...


procedure TSecondaryForm.CMAppsyscommand(var Message: TMessage);
begin
  if ActionMainMenuBar1.Perform(PMessage(Message.LParam).Msg,,
      PMessage(Message.LParam).WParam, PMessage(Message.LParam).LParam) = 0 then
    inherited;
end;

// you may not need the below handler
procedure TSecondaryForm.WMSysCommand(var Message: TWMSysCommand);
begin
  if ActionMainMenuBar1.Perform(Message.Msg,
      TMessage(Message).WParam, TMessage(Message).LParam) = 0 then
    inherited;
end;

你确定这与备忘录是否存在有关吗?我敢打赌,这取决于备忘录是否有焦点。@Jerrydoge你是对的,问题不在于TMemo本身,而在于存在一个可以
集中注意力。例如,我可以删除TMemo,并使用表单上的组合框或radiogroup获得相同的结果。如果备忘录、组合框或放射组被禁用,问题就会消失。您确定这与备忘录是否存在有关吗?我敢打赌,这取决于备忘录是否有焦点。@Jerrydoge你是对的,问题不在于TMemo本身,而在于是否存在可以聚焦的控件。例如,我可以删除TMemo,并使用表单上的组合框或radiogroup获得相同的结果。如果备忘录、组合框或放射组被禁用,问题就会消失。