Вторичный ярлык не срабатывает
Я использую Delpho 2006. Сценарий:
На модуле данных у меня есть ActionList. У одного из действий есть комбинация клавиш Ctrl+F4, и я хочу использовать дополнительную комбинацию клавиш Ctrl+W. Я попробовал все следующее:
Добавление Ctrl + W к списку действий SecondaryShortcut в IDE.
Добавление его в процедуру DataModuleCreate с использованием
ActFileCloseFile.SecondaryShortCuts.Add('Ctrl+W');
или же
ActFileCloseFile.SecondaryShortCuts.AddObject('Ctrl+W',
TObject(Menus.ShortCut(87, [ssCtrl])));
Использование обоих этих методов в процедуре Create или FormShow той формы, в которой он будет использоваться.
Основной ярлык всегда работает, но не вторичный.
Когда я помещаю ActionList в основную форму вместо модуля данных, он работает, просто добавляя Ctrl + W в IDE. Что я делаю не так?
4 ответа
Самое элегантное решение, найденное до сих пор, это:
В форме, которую вы хотите обработать SecondaryShortCut, добавьте это в событие OnShortCut:
procedure TMyForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
Handled := dmDataModule.ActionList1.IsShortCut(Msg);
end;
Альтернатива:
(Это не реальное решение, а обходной путь.)
Поместите в форму список действий, действие которого идентично действию в модуле данных. В своих событиях execute и update он только перенаправляет события в действие модуля данных. Меню в форме используют локальное действие.
В этом случае достаточно добавить Ctrl+W к свойству SecondaryShortCuts, используя IDE.
Очевидно, что когда изменяется действие над модулем данных, мне приходится менять и все локальные действия.
Краткий ответ: ярлыки действий не запускаются автоматически через формы и модули данных.
Если вы будете следовать инструкциям, приведенным в вопросе, вы обнаружите, что даже основные короткие пути не срабатывают. Это потому, что ключевой шаг был исключен из инструкций. Тот, который будет объяснять, почему ОП испытывал первичное короткое замыкание, а не вторичное.
Если вы включите дополнительные шаги:
- Добавьте меню в форму.
- И связать пункт меню с действием.
Тогда основной короткий путь сможет запустить действие. Это связано с тем, что компонент Action переносит свои настройки в пункт меню (включая ShortCut
имущество). Тем не мение, TMenuItem
не реализует концепцию вторичных сокращений. Вот почему один работает, а не другой.
Приостановить рассмотрение приложения с множеством форм и модулей данных; и последствия того, что быстрые сокращения действий могут сработать во всех из них. Должно быть достаточно очевидно, что они не смогут автоматически запускаться без явного кода, разрешающего это. Вы не хотели бы, чтобы фоновая форма выполняла кучу вещей, потому что ее настроенные сочетания клавиш оказывались нажатыми в контексте другой не связанной работы.
Документация указывает на преимущество размещения списков действий на модулях данных. Но, похоже, не предлагает никакого объяснения, как правильно использовать действия с ярлыками для модуля данных. Конечно, ничего не упоминается в ожидаемых местах, а именно: ShortCut и SecondaryShortcuts. (Я был бы разочарован, но мои ожидания в отношении достойной документации оказались довольно низкими.)
Так...
Что нужно сделать, чтобы действия с ярлыками работали между формами и модулями данных?
Я провел небольшое расследование и нашел несколько вариантов. Как всегда, оцените компромисс относительно того, чего вы пытаетесь достичь.
Когда вы удаляете список действий в (неосновной) форме, все ярлыки работают должным образом. Это наиболее распространенный сценарий и применяется, когда действия являются локальными и имеют специфическую форму.
Когда вы отбрасываете список действий в главной форме, все эти ярлыки могут запускаться из любой другой формы. Это отлично подходит для ярлыков во всем приложении, таких как открытие других форм.
ПРИМЕЧАНИЕ. Существует последовательность приоритетов в отношении того, где сначала проверяется сокращение. Таким образом, если активная форма имеет ярлык, совпадающий с соответствующим на главной форме, ярлык будет обрабатываться локально. И основная форма по понятным причинам не получится.
- Когда форма проверяется, чтобы увидеть, обрабатывает ли она ярлык, также проверяются все принадлежащие ей компоненты. (Это на самом деле, почему первые два выше работают.) Это означает, что просто установка
Owner
вашего модуля данных, соответственно, позволит его ярлыки применить к выбранной вами форме.
Т.е. вместо:
Application.CreateForm(TDataModule1, DataModule1);
Вы можете использовать следующее:
DataModule1 := TDataModule1.Create(LocalForm);
Однако, поскольку у каждого экземпляра модуля данных может быть только один владелец: вам придется создать несколько экземпляров, чтобы позволить нескольким формам совместно использовать ярлыки. Будет ли это вариант, зависит от ваших обстоятельств. Тем не менее, вы также можете сделать основную форму владельцем вашего модуля данных, что будет несколько эквивалентно второму варианту выше.
- Последний вариант, обеспечивающий максимальный контроль, - это собственный ответ ОП. Т.е. любая форма, которая должна поддерживать "внешние ярлыки", может обрабатывать событие 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;
Не настоящее решение, но если вы создаете модуль данных из основной формы, он работает:
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;
Я думаю, что ярлыки обрабатываются формой, которая имеет текущий фокус. Так что, вероятно, у вас возникнут те же проблемы, если вы будете использовать их в другой форме.
Действие проглатывается формой... Если вы хотите, чтобы вторичная форма / фрейм / модуль данных обрабатывал действие... Сначала вы должны отключить Список действий из Первичного...
Form1.ActionList1.State: = asSuspended;
DataModule1.ActionList1.State: = asNormal;