Иллюстрированный самоучитель по Delphi 7 для профессионалов

События

Но какой механизм позволяет подменять обработчики, ведь это не просто процедуры, а методы? Здесь как нельзя кстати приходится существующее в Object Pascal понятие указателя на метод. Отличие метода от процедуры состоит в том, что помимо явно описанных параметров методу всегда неявно передается еще и указатель на вызвавший его экземпляр класса (переменная self). Вы можете описать процедурный тип, который будет совместим по присваиванию с методом (т. е. предусматривать получение self). Для этого в описание процедуры нужно добавить зарезервированные слова of object. Указатель на метод – это указатель на такую процедуру.

type
TMyEvent = procedure(Sender: TObject; var AValue: Integer) of object;
TlstObject = class;
FOnMyEvent: TMyEvent;
property OnMyEvent: TMyEvent read FOnMyEvent write FOnMyEvent;
end;
T2ndObject = class;
procedure SetValuel(Sender: TObject; var AValue: Integer);
procedure SetValue2(Sender: TObject; var AValue: Integer);
end;
…
var
Objl: TlstObject;
Obj2: T2ndObject;
begin
Objl: = TlstObject.Create;
Obj2: = T2ndObject.Create;
Obj1.OnMyEvent: = Obj2.SetValuel;
Obj1.OnMyEvent: = Obj2.SetValue2;
…
end.

Этот пример показывает, что при делегировании можно присваивать методы других классов. Здесь обработчиком события OnMyEvent объекта Obj1 по очереди выступают методы SetValue1 и Setvaiue2 объекта Obj2.

Обработчики событий нельзя сделать просто процедурами – они обязательно должны быть чьими-то методами. Но их можно "отдать" какому-либо другому объекту. Более того, для этих целей можно описать и создать специальный объект. Его единственное предназначение – быть носителем методов, которые затем делегируются другим объектам. Разумеется, такой объект надо не забыть создать до использования его методов, а в конце – уничтожить. Можно и не делать этого, объявив методы методами класса, о которых речь пойдет в одном из последующих разделов.

Мы сейчас решили задачу использования нескольких разных обработчиков того или иного события для одного объекта. Но не менее часто требуется решить обратную задачу – а как использовать для различных событий разных объектов один и тот же обработчик?

Если никакой "персонификации" объекта, вызвавшего метод, не нужно, все делается тривиально и проблемы не возникает. Самый простой пример: в современных программах основные функции дублируются дважды – в меню и на панели инструментов. Естественно, сначала нужно создать и наполнить метод содержимым (скажем, для пункта меню), а затем в Инспекторе объектов указать его же для кнопки панели инструментов.

Более сложный случай, когда внутри такого метода нужно разобраться, кто собственно его вызвал. Если потенциальные кандидаты имеют разный объектный тип (как в предыдущем абзаце – кнопка и пункт меню), то именно объектный тип можно применить в качестве критерия:

If Sender is TMenuItem then ShowMessage('Выбран пункт меню');

Если же все объекты, разделяющие между собой один обработчик события, относятся к одному классу, то приходится прибегать к дополнительным ухищрениям. Типовой прием – использовать свойство Tag, которое имеется у всех компонентов, и, вполне вероятно, именно для этого и задумывалось:

const colors: array[0..7]
of
TColor = clWhite,clRed,clBlue,clYellow,clAqua,clGreen, clMaroon,clBlack);
procedure TForml.CheckBoxClick(Sender: TObject);
begin
with TCheckBox(Sender) do
if Checked
then Color: = Colors[Tag]
else Color: = clBtnFace;
end;

Пусть в форме имеется несколько переключателей. Для того чтобы при нажатии каждый из них окрашивался в свой цвет, нужно в Инспекторе объектов присвоить свойству Tag значения от 0 до 7 и для каждого связать событие onclick с методом CheckBoxClick. Этот единственный метод справится с задачей для всех переключателей.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.