В программе несколько модулей. Есть панель, на которой эти модули отображаются. Их отображением занимается менеджер модулей. Панель занимает почти все рабочее пространоство программы кроме небольшой панели инструментов, которая и обеспечивает навигацию по модулям. Почти в каждом модуле есть кнопки с горячими клавишами. Например кнопки типа Done и Cancel присутствуют почти в каждом модуле. Горячие клавиши у них, естественно одинаковые. Проблема заключается в том, что при нажатии горячих клавиш выполняются действия не того модуля, который отображается в данный момент. Более того, можно нажать горячие клавиши, которые не присутствуют в отображаемом модуле но выполнятся действия другого модуля, ассоциированные с этими клавишами.
Немного о тонкости реализации:
Модули (фреймы) не удаляются из памяти, при выборе очередного модуля, текущий прячется, выполнив необходимые завершающие действия, а на его месте создается (если еще не был создан) и показывается выбранный модуль.
Спасибо за совет.
Здравствуйте, delphinchik, Вы писали:
D>...
Это хорошо что у тебя есть manager модулей

Ладно идея такая (нормальный подход к интерфейсу):
1. Конфликтные горячие клавиши ты должен подключить на главную форму (manager или что у тебя там есть).
2. Создай Actions actDone и actCancel на этой форме и назначь им нужные горячие клавиши.
3. Забери все горячие клавиши для Done и Cancel с модулей.
4. Создай два ининтерфейса IDone и ICancel:
IDone = interface
['{BEB14D0C-20B6-4A33-BDB9-784AC1DA4815}']
function CanBeDone : Boolean;
procedure Done;
end;
ICancel = interface
['{56E27861-FBB4-49FE-BB75-2BAB966FFEAA}']
function CanCancel : Boolean;
procedure Cancel;
end;
5. На этих Экшинах повесь код который запрашивает у активного модуля соответствуюшщий ининтерфейс.
procedure TForm1.actCancelExecute(Sender: TObject);
var
aCancel : ICancel;
begin
if Supports (ActiveModule, ICancel, aCancel) then
aCancel.Cancel;
end;
procedure TForm1.actDoneExecute(Sender: TObject);
var
aDone : IDone;
begin
if Supports (ActiveModule, IDone, aDone) then
aDone.Done;
end;
procedure TForm1.actDoneUpdate(Sender: TObject);
var
aDone : IDone;
begin
(Sender as TAction).Enabled := Supports (ActiveModule, IDone, aDone) and aDone.CanBeDone;
end;
procedure TForm1.actCancelUpdate(Sender: TObject);
var
aCancel : ICancel;
begin
Sender as TAction).Enabled := Supports (ActiveModule, ICancel, aCancel) and aCancel.CanCancel;
end;
6. В своих модулях сделай поддержку нужных интерфейсов ICancel и IDone. Пример:
type
TModule1 = class (TFrame, IDone, ICancel)
...
protected
function CanBeDone : Boolean;
procedure Done;
function CanCancel : Boolean;
procedure Cancel;
end;
implementation
{ TModule1 }
function TModule1.CanBeDone: Boolean;
begin
Result := True; { ставиш условие можно ли Done жать }
end;
function TModule1.CanCancel: Boolean;
begin
Result := True; { ставиш условие можно ли Канселить }
end;
procedure TModule1.Cancel;
begin
{ Cancel }
end;
procedure TModule1.Done;
begin
{ Done }
end;
7.
IDone.Done
Ну тогда можно пойти ещё более простым путём. Сделать два внешних экшена Done и Cancel, которые будут вызывать соответствующие виртуальные методы у активного модуля. А кнопки уже привязывать к этим экшенам.
Здравствуйте, Dimonka, Вы писали:
D>Ну тогда можно пойти ещё более простым путём. Сделать два внешних экшена Done и Cancel, которые будут вызывать соответствующие виртуальные методы у активного модуля. А кнопки уже привязывать к этим экшенам.
Конечно, так я писал когда то

Достоинство приведенного выше метода в том что базоывй класс не перегружается лишними виртуальными методами.
Особенно когда нужно добавить что то более специфическое, напимер invoke Refresh, invoke Properties, invoke Popup, IDBGrid, invoke ManyManyThings

,
Базовый класс становится как ежик напичканый виртуальными методами которые зачастую нужны лиш в одном модуле.