我正在使用Windows 10中的Delphi XE7。我在主要表单和模态辅助表单上都有一个TMainMenuBar。问题是,如果辅助表单还包含TMemo,则辅助表单上的加速键不会激活菜单。例如,如果辅助表单具有“文件”菜单,则Alt + F不会打开文件菜单。但是,如果按下并释放alt,则“文件”突出显示,“F”加下划线,按F将打开菜单。请注意,如果删除TMemo,问题将消失。此外,主窗体上的Tmemo不会导致主窗体上的菜单出现问题。
我搜索了“辅助表单上的TActionMainMenuBar加速键”,但没有一个匹配描述这个特定问题,尽管讨论了此组件和加速键的其他问题。有没有人知道如何在两个表单上使用TActionMainMenuBar时实现所需的行为? (出于各种原因,我宁愿不使用标准的TMenu。)
答案 0 :(得分:5)
这是一个VCL设计问题。 (下面的解释可能有点偏离。我正在跟踪XE2并且行为不完全相同。您可能需要在解决方案部分留下一个消息处理程序。)
菜单栏加速器会生成WM_SYSCOMMAND
条消息。您的确切加速器案例在API documentation中作为示例提供:
如果wParam是 SC_KEYMENU ,则lParam包含的字符代码 与ALT键一起使用的键,用于显示弹出菜单。对于 例如,按ALT + F显示File弹出窗口将导致a WM_SYSCOMMAND ,wParam等于 SC_KEYMENU ,lParam等于'f'。
操作菜单栏是专有的VCL组件。因此,表单的默认窗口过程没有机会为它们处理加速器消息。组件本身具有模拟行为的代码(TCustomActionMainMenuBar.WMSysCommand
),但必须传递消息才能执行此操作。 VCL的设计问题是,只有主表单上的动作菜单栏才有机会。
TWinControl
收到WM_SYSCOMMAND
(辅助表单本身或本例中的备忘录),使其父表单(辅助表单)执行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;