二级快捷键无法触发。

3
我正在使用Delphi 2006。场景如下:
在数据模块中,我有一个ActionList。其中一个操作有一个快捷键Ctrl + F4,我想要一个次要快捷键Ctrl + W。 我尝试了以下所有方法:
1. 在IDE中将Ctrl + W添加到操作的SecondaryShortcut列表中。 2. 使用以下任一DataModuleCreate流程添加它:
ActFileCloseFile.SecondaryShortCuts.Add('Ctrl+W');

或者
ActFileCloseFile.SecondaryShortCuts.AddObject('Ctrl+W',
  TObject(Menus.ShortCut(87, [ssCtrl])));

在使用的窗体的Create或FormShow过程中同时使用这两种方法。

主要的快捷键始终有效,但次要的不起作用。

当我将ActionList放在主窗体而不是数据模块上时,在IDE中只需添加Ctrl + W即可正常工作。我做错了什么?

4个回答

3
到目前为止,最优雅的解决方案如下:
在你想处理 SecondaryShortCut 的表单上,将以下内容添加到 OnShortCut 事件中:
procedure TMyForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Handled := dmDataModule.ActionList1.IsShortCut(Msg);
end;

替代方案:

(这不是一个真正的解决方案,而是一个变通方法。)

在表单上放置一个操作列表,该列表具有与数据模块上相同的操作。在其执行和更新事件中,它只将事件转发到数据模块操作。表单上的菜单使用本地操作。

在这种情况下,只需在IDE中使用SecondaryShortCuts属性添加Ctrl+W即可。

显然,当数据模块上的操作更改时,我也必须更改所有本地操作。


这实际上是一个非常恰当的解决方案(顶部的那一段)。问题在于,动作快捷键不应该在整个应用程序范围内全局使用,因此需要一些显式代码来指示表单可以使用“外部”动作快捷键。 - Disillusioned

1

这不是一个真正的解决方案,但如果你在主窗体中创建数据模块,它就可以工作:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  FDataModule := TMyDataModule.Create(self);
  TMyButton.Action := FDataModule.TheAction;
end;


procedure TMyDataModule.DataModuleCreate(Sender: TObject);
begin
  TheAction.SecondaryShortCuts.Add('Ctrl+W');
end;

我认为快捷键是由当前焦点所在的表单处理的。因此,如果您在另一个表单中使用它们,可能会遇到相同的问题。


有趣的是,即使在没有你的技巧的情况下,主要的快捷方式也可以在数据模块上处理。 - malach
它能够工作,但你的推理是错误的。这与在主表单中创建数据模块无关。如果你写成:FDataModule := TMyDataModule.Create(Application); 或者 FDataModule := TMyDataModule.Create(nil); 它都不会起作用。你可以在任何地方创建数据模块。如果你将它的所有者设置为想要使用快捷方式的表单 - 它们只会对该表单起作用。如果你将它的所有者设置为主表单 - 快捷键也将对其他表单起作用。原因是在检查快捷键时,所有拥有的组件都会递归地进行检查。 - Disillusioned

1
简短回答:操作快捷键不会自动跨表单和数据模块触发。
如果您按照问题中的说明进行操作,甚至主要快捷键也无法触发。这是因为指令中遗漏了一些关键步骤,这可以解释为什么OP经历了主要的快捷键触发而没有次要的快捷键。
如果您包括以下额外步骤:
- 添加菜单到表单中。 - 将菜单项链接到操作。
那么主要的快捷键将能够触发操作。这是因为Action组件将其设置推送到菜单项(包括ShortCut属性)。但是,TMenuItem不实现次要快捷键的概念。这就是为什么一个起作用而另一个不起作用的原因。
请暂停一下,考虑一个具有许多表单和数据模块的应用程序,以及如果操作快捷方式可以跨所有表单和数据模块触发的含义。显然,它们不应该在没有明确允许的代码的情况下自动触发。您不希望背景表单因其配置的快捷键在其他无关工作的上下文中被按下而执行一堆操作。 文档指出将操作列表放在数据模块上的好处。但似乎没有提供如何在数据模块上正确使用带有快捷键的操作的解释。当然,在预期的位置上没有提到任何内容,即:快捷键次要快捷键。 (我会感到失望,但是我对良好文档的期望已经非常低了。)
所以...

如何使跨表单和数据模块的快捷操作正常工作?

我进行了一些调查,并找到了几个选项。像往常一样,要根据您想要实现的目标评估权衡。

  • 当您在(非主)表单上放置动作列表时,所有快捷键都按预期工作。这是最常见的情况,适用于本地和特定于表单的操作。

  • 当您在主表单上放置动作列表时,所有这些快捷键都可以从任何其他表单触发。这对于应用程序范围的快捷方式非常有用,例如打开其他表单。

注意:有一个优先级顺序,确定首先测试快捷方式的位置。因此,如果活动表单具有与主表单上匹配的快捷键,则会在本地处理快捷键。主表单则无法获取它。

  • 当测试表单是否处理快捷键时,所有所属组件也会被检查。(这就是前两个方法有效的原因。) 这意味着简单地设置数据模块的Owner属性为所选表单即可使其快捷键生效。

即:不要这样做:

Application.CreateForm(TDataModule1, DataModule1);

您可以使用以下内容:
DataModule1 := TDataModule1.Create(LocalForm);

然而,由于每个数据模块实例只能有一个所有者:您必须创建多个实例才能让多个表单共享快捷方式。这是否可行取决于您的情况。但是,您还可以将主表单作为数据模块的所有者,这在某种程度上相当于上述第二个选项。
提供最多控制权的最终选项是OP自己的答案。即需要支持“外部快捷键”的任何表单都可以使用以下代码处理OnShortCut事件:
如代码示例所示,您可以根据所选择的优先级委派到不同位置的多个操作列表。
procedure TMyForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Handled := DataModule1.ActionList3.IsShortCut(Msg);
  Handled := Handled or DataModule2.ActionList1.IsShortCut(Msg);
  Handled := Handled or DataModule1.ActionList1.IsShortCut(Msg);
end;

0

操作被表单吞噬了...如果你想让一个次要的表单/框架/数据模块来处理这个操作...你必须先禁用主表单的Actionlist...

Form1.ActionList1.State := asSuspended;

DataModule1.ActionList1.State := asNormal;


在这种情况下,我在窗体上没有ActionList,并且数据模块的ActionList状态为asNormal。但仍然无法捕获SecondaryShortCut,只能捕获主要的ShortCut。 - malach

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