Question

I am using Delpho 2006. The Scenario:

On the data module I have an ActionList. One of the actions has a shortcut Ctrl+F4 and I want to have a secondary shortcut Ctrl+W. I tried all of the following:

Adding Ctrl+W to the actions SecondaryShortcut list in the IDE.

Adding it in the DataModuleCreate procedure using either

ActFileCloseFile.SecondaryShortCuts.Add('Ctrl+W');

or

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

Using both of these methods in the Create or FormShow procedure of the form where it will be used.

The primary shortcut always works, but not the secondary.

When I put the ActionList on the main form instead of the data module, it works by just adding Ctrl+W in the IDE. What do I do wrong?

Was it helpful?

Solution

The most elegant solution found so far is this:

On the form you want to handle the SecondaryShortCut, add this to the OnShortCut event:

procedure TMyForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Handled := dmDataModule.ActionList1.IsShortCut(Msg);
end;

Alternative:

(This is not a real solution, but a workaround.)

Put an action list on the form that has an identical action to the one on the data module. In its execute and update events it only forwards the events to the data module action. The menus on the form use the local action.

In this case it suffices to add Ctrl+W to the SecondaryShortCuts property using the IDE.

Obviously, when the action on the data module changes, I have to change all local actions too.

OTHER TIPS

Not a real solution, but if you create the datamodule from within the mainform it works:

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;

I think the shortcuts are handled by the form that has the current focus. So yo will probably get the same problems if you are using them in another form.

Short Answer: Actions short-cuts do not automatically fire across forms and data-modules.

If you follow the instructions in the question, you'll find that not even the primary short-cut fires. This is because a key step has been left out of the instructions. One that will serve to explain why OP experienced the primary short-cut firing and not the secondary one.

If you include the extra steps:

  • Add a menu to the form.
  • And link a menu-item to the action.

Then the primary short-cut will be able to fire the action. This is because the Action component pushes its settings to the menu item (including the ShortCut property). However, TMenuItem does not implement the concept of secondary short-cuts. Which is why one works and not the other.


Pause to consider an application with many forms and data-modules; and the implication if action short-cuts could fire across all of them. It should be fairly obvious that they should not be able automatically fire without explicit code to permit it. You wouldn't want a background form doing a bunch of things because its configured short-cut keys happen to be pressed in the context of other unrelated work.

The documentation points out the benefit of putting action lists on data-modules. But doesn't seem to offer any explanation how to use actions with short-cuts on a data-module correctly. Certainly nothing is mentioned in the expected places, namely: ShortCut and SecondaryShortcuts. (I'd be disappointed, but my expectations of decent documentation have been dragged quite low.)

So...

What should be done to get actions with short-cuts working across forms and data-modules?

I have done a bit of investigation and found a few options. As always, evaluate the trade-off's relative to what you are trying to achieve.

  • When you drop an action list on a (non-main) form, all the short-cuts work as expected. This is the most common scenario and applies when the actions are local and form specific.

  • When you drop an action list on the main form, all those short-cuts will be able to fire from any other form. This is great for application-wide short-cuts such as opening other forms.

NOTE: There is a prioritisation sequence as to where a short-cut is tested first. So if the active form has a short-cut matching one on the main form, the short-cut will be processed locally. And the main form understandably won't get it.

  • When a form is tested to see if it handles a short-cut, all owned components are also checked. (This is in fact why the first two above work.) This means that simply setting the Owner of your data-module appropriately will allow its short-cuts to apply to your chosen form.

I.e. Instead of:

Application.CreateForm(TDataModule1, DataModule1);

You can use the following:

DataModule1 := TDataModule1.Create(LocalForm);

However, since each instance of a data-module can have only one owner: you would have to create multiple instances to let multiple forms share the short-cuts. Whether this is an option depends on your circumstances. However, you could also make the main form the owner of your data-module which would be somewhat equivalent to the second option above.

  • The final option which provides the most control is OP's own answer. I.e. Any form that needs to support "external short-cuts" can handle the OnShortCut event with the following code:

As can be seen in the code sample you can delegate to multiple action lists in different locations according to the priority you choose.

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;

The action is getting swallowed by the form...If you want a secondary form/frame/datamodule to handle the action...You have to disable the Actionlist from the Primary first...

Form1.ActionList1.State := asSuspended;

DataModule1.ActionList1.State := asNormal;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top