- •Объектно-ориентированное программирование
- •Часть 1 классы и объекты
- •Введение
- •1. Классы и объекты
- •Var aLine: tLine;
- •Var aColorLine: tColorLine;
- •2. Методы
- •2.1. Методы-функции и методы-процедуры
- •2.2. Конструкторы и деструкторы
- •Inherited Create;
- •Var TmpFrm: tForm;
- •Var Mem: tMemo;
- •2.3. Классовые процедуры и функции
- •Var s: String;
- •2.4. Скрытый Self
- •3. Видимость компонентов класса
- •4. Наследование
- •4.1. Основные понятия
- •4.2. Наследование полей
- •4.3. Поведение методов при наследовании
- •Var SomeObject: t1;
- •Virtual;
- •Virtual; Abstract;
- •4.4. Иерархия классов
- •4.5. Rtti
- •4.6. Проверка типа
- •4.7. Приведение типа
- •4.8. Указатели на класс
- •Var ObjRef: tObjRef;
- •Implementation
- •X, y, w, h: Integer): tControl;
- •5. Полиморфизм
- •6. Свойства (properties)
- •6.1. Объявление свойств
- •6.2. Объявления свойств-массивов
- •Var I: Byte;
- •6.3. Раздел Read
- •6.4. Раздел Write
- •Inherited Create;
- •Inherited Destroy;
- •6.5. Команды Default, NoDefault и Stored
- •6.6. Команда Index
- •Var aYear, aMonth, aDay: Word;
- •Var aYear, aMonth, aDay: Word;
- •6.7. Команды DispId и Implements
- •6.8. Переопределение свойств при наследовании
- •7. События (events)
- •7.1. Объявление событий
- •IfAssigned(fOnMouseMove) Then fOnMouseMove(Self, Shift, X, y);
- •Vk_return: NumMemo.DoNumStr(l);
- •Vk_return: PostMessage(NumMemo.Handle, wm_user1,1, 0);
- •7.2. Обработчики событий
- •7.3. Делегирование событий
- •Var Objl: tIstClass;
- •7.4. Переопределение стандартных событий
- •Var NewBtn: tNewButton;
7.3. Делегирование событий
Поскольку события - это свойства объекта, за которыми, естественно, стоят поля, то значения этих полей можно изменять во время выполнения программы. Такая замечательная возможность называется делегированием (delegation). Таким образом, в любой момент можно присвоить событие одного объекта другому объекту, имеющему однотипное событие. Поскольку значениями являются указатели на методы-обработчики событий, то фактически присваиваются (делегируются) способы реакций на однотипные события. Синтаксически это выглядит следующим образом:
<oбъeкmI>.<coбblmue>'.=:<oбьeкm2>.<coбыmlte>;
Когда необходимость в делегировании события отпадает, то достаточно присвоить (делегировать) событию "пустой" указатель:
<обьект>.<событие>:=!^11;
Принцип делегирования позволяет избежать трудоемкого процесса порождения новых дочерних классов для каждого конкретного случая, заменяя его простой подстановкой процедур. Для реализации делегирования как нельзя кстати, подходит введенный в Delphi указатель на метод. Поскольку. помимо явно описанных параметров, методу передается еще и указатель на вызывающий его экземпляр (Self), то можно описать тип процедуру, которая будет совместима по присвоению с методом (т.е. будет предусматривать передачу Self).
Type TAnyEvent=Procedure(Sender: TObject; VarAValue; Integer) Of Object;
TlstClass=Class // Объявление нового класса
FOnMyEvent: TAnyEvent;
Property OnMyEvent: TAnyEvent Read FOnMyEvent Write FOnMyEvent;
End;
T2ndClass=CIass // Класс - носитель методов
Procedure SetValuel(Sender: TObject; Var AValue: Integer);
Procedure SetValue2(Sender; TObject; VarAValue: Integer);
End;
Var Objl: tIstClass;
Obj2: T2ndClass;
Begin
Objl:=TlstClass.Create;
Obj2:=T2ndClass.Create;
Obj 1.0nMyEvent:=Obj2.SetValuel; II Делегирование первого метода
Obj 1.0nMyEnent:=Obj2.SetValue2; It Делегирование второго метода
Obj 1 .OnMyEnent:=Nil; // Отключение всех обработчиков
Напомним, что как в этом примере, так и повсюду в Delphi за свойствами-событиями стоят поля, являющиеся указателями на метод. Таким образом, при делегировании этим полям можно присвоить указатели на методы других классов. Главное, они должны быть одного типа.
Иногда, для уменьшения загромождения главных форм обработчиками событий, объявляют специальный класс - носитель методов соответствующих типов, которые потом делегируются другим объектам по мере необходимости.
Если внутри таких методов, которые используются несколькими объектами, необходимо определить, кто его вызвал, то можно воспользоваться оператором проверки типа Is:
If Sender Is <клас0 Then <onepamop>;
Если объекты относятся к одному классу, то можно использовать свойство Tag компонентов, присвоив им различные целочисленные значения и используя приведение типов:
• If </cnacc>(Sender).Tag==l Then <onepamop>\
• If (Sender As <^acc>).Tag=l Then <onepamop>\
Делегирование стандартных событий между компонентами при разработке программы в среде Delphi выполнить очень просто. Для этого следует выбрать компонент, в инспекторе объектов перейти на страницу Events, выбрать нужное событие и с помощью раскрывающегося списка делегировать обработчик события другого компонента. При этом Delphi автоматически просмотрит все реализованные обработчики и предоставит для доступа список обработчиков только однотипных событий.
Если возникает необходимость удостовериться в том, что в конкретный момент делегирован необходимый метод, можно воспользоваться следующим типовым приемом:
Var AnyEvent, NameEvent: <mun события>;
Begin
AnyVlVeat'.xs:<oб•ьeкm>.<coбыmue>•, NameEvent:=<ayKfl метода>;
If@AnyEvent=@NameEvent Then <onepamop>\
Можно получить адрес и имя метода следующим простым способом:
Var AnyEvent: <mun события>;
Begin
AnyEvent:=<o6'beKm>.<co6btmue>',
Labell.Caption:=MethodName(@AnyEvent); // Имя метода Label2.Caption:=Format('%p', [@AnyEvent]); // Адрес метода
