Может ли компонент заменить событие формы владельца (OnClose) своим собственным обработчиком?

Я работаю над компонентом, который размещается в каждой форме моего проекта. Возможно ли, чтобы во время выполнения компонент включал код в обработчик событий OnClose формы владельца. Другими словами, форма будет запускать собственный обработчик события OnClose, но компонент также будет включать дополнительный код обработчика событий для запуска в событии OnClose формы-владельца. (Это то, что называется заменой вектора?) Спасибо.


person user1202134    schedule 07.04.2012    source источник


Ответы (1)


Вам нужно заставить компонент объявить поле для хранения исходного OnClose формы. Затем вы можете сделать в конструкторе компонента:

FOriginalFormClose := (Owner as TForm).OnClose;
(Owner as TForm).OnClose := FormClose;

Тогда FormClose компонента будет читать:

TMyComponent.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // do stuff for this component
  if Assigned(FOriginalFormClose) then
    FOriginalFormClose(Sender, Action);
end;

Естественно, приведение as связывает этот компонент с тем, что он принадлежит формам, но если вам нужна большая гибкость, вы можете легко удовлетворить это.

Это прямой ответ на вопрос, который вы задали, но с моей стороны было бы упущением не подвергнуть сомнению ваш общий дизайн. Если вы хотите, чтобы компонент работал в каждой форме вашего приложения, вам, безусловно, следует создать подкласс TForm, содержащий ваши настройки. Затем сделайте так, чтобы каждая форма в вашем приложении основывалась на этом общем базовом классе формы.

Такой подход имеет много других преимуществ. Например, @LachlanG добавляет следующий очень меткий комментарий, с которым я полностью согласен:

Наличие компонента, вмешивающегося в его форму владения, нежелательно. Подавляющее большинство компонентов должны быть автономными объектами, изменение владельца компонента нарушает ожидаемый контракт компонента Delphi.

Подход с общей базовой формой решает эту проблему, помещая код, который работает с формой, внутрь формы.

Если вы идете по пути создания общей базовой формы, вам следует переопределить DoClose, а не использовать событие OnClose. Всегда используйте обработчики событий DoXXX, а не сами события, когда вы создаете общий базовый класс или компонент.

person David Heffernan    schedule 07.04.2012
comment
Я согласен с Дэвидом в том, что наличие компонента, вмешивающегося в его форму владения, нежелательно. Подавляющее большинство компонентов должны быть автономными объектами, изменение владельца компонента нарушает ожидаемый контракт компонента Delphi. - person LachlanG; 07.04.2012
comment
@LachlanG +1 Я должен был сказать это прямо в ответе, потому что я полностью согласен. Спасибо. - person David Heffernan; 07.04.2012
comment
Спасибо, Дэвид Хефферман, именно то, что я хотел. Правильный ответ. - person user1202134; 08.04.2012
comment
Привет Дэвид, только одно наблюдение с вашим примером. Разве тест «if FORiginalFormClose ‹› nil» не должен быть «if Assigned(FOriginalFormClose) then»? С уважением. - person user1202134; 09.04.2012