Published Property OnClick;
Переопределение события изменяет только его уровень защиты и не изменяет стандартной реакции на это событие.
• Можно переопределить корреспондирующий динамический метод с целью включения в его код действий - общих для всех экземпляров этого класса.
Для изменения стандартной реакции на события всех компонентов одного класса следует сделать замещение корреспондирующего защищенного динамического метода в классе-потомке. При этом следует вызывать унаследованный обработчик. Чаще всего это рекомендуется делать в начале кода замещения метода, хотя могут быть случаи, когда вызывать наследуемый обработчик целесообразно в конце кода. Синтаксически это может выглядеть следующим образом:
Type
<имя класса>=С\&&&(<класс-предок>) Protected
Procedure <метод>;Override; // Замещение метода End;
Procedure <имя класса>.<метод>; II Реализация замещающего метода Begin
Inherited <метод>; II Вызов наследуемого обработчика дополнительный код> II Добавление новых реакций End;
Таким образом, чтобы изменить корреспондирующий метод события, необходимо указать, когда вызывается наследованное поведение, а когда -новое действие.
Рассмотрим пример класса, в стандартную обработку которого добавлен код вывода даты вместо заголовка на кнопке.
Type
TTimeButton=Class(TButton) // Объявление класса-потомка Protected
Procedure Click; Override; // Замещение (переопределение) метода End;
Procedure TTimeButton.Click; // Реализация замещающего метода Begin
Inherited Click; // Выполнение стандартных действий кнопкой II После стандартных действий - вывод даты Caption:=DateTimeToStr(Now);
End;
В отличие от обработчика события, создаваемого для каждого конкретного компонента и влияющего только на его поведение, изменение корреспондирующего метода влияет на поведение всех компонентов этого класса.
Таким образом, стандартные действия всех компонентов созданного нами класса TTimeButton будут заключаться в "утоплении" кнопки после щелчка, выводе даты и времени вместо названия кнопки и вызове обработчика события, если он для кнопки будет создан или делегирован.
В заключение рассмотрения вопроса о переопределении событий следует сказать следующее:
• Переопределять стандартные события Delphi с целью изменения команд доступа к событию невозможно и нецелесообразно:
• Поля для хранения значений стандартных событий определены в разделе Private класса и поэтому невидимы в потомках, а для переопределения необходимо указать событие с одной из команд Read или Write. Поскольку любая из этих команд требует прямого или косвенного доступа к соответствующему полю свойства, то это невозможно.
Если же объявить новое поле, то необходимо будет переопределить корреспондирующий метод и представить его новую реализацию. При этом необходимо будет отка-
-66-
заться от наследования обработчика класса-предка, иначе корреспондирующий метод будет обращаться к обработчикам двух полей - унаследованного и нового.
• Нецелесообразно потому, что принцип использования событий существенно отличается от использования свойств. Если исключить команду Write, то нельзя будет создавать обработчик событий и возможна будет только обработка события, предусмотренная по умолчанию. Однако для этого достаточно переопределить корреспондирующий метод. Если исключить команду Read, то невозможно будет выполнить код обработчика события, и область использования такого события трудно подыскать.
• Переопределение стандартного события с целью изменения типа события потребует объявления в классе нового поля нужного типа, переопределения корреспондирующего метода или объявление нового, а также создание их реализации. Принципиально это возможно. При этом доступ к переопределенному событию возможен с помощью привидения типов. Вопрос заключается в целесообразности.
В качестве примера создадим новый компонент, включающий переопределение события OnClick, заключающееся в изменении его типа (тип TNotifyEvent заменяется на тип TMouseMoveEvent), добавлении нового поля FNewOnClick типа TMouseMoveEvent и замещении метода Click.
Type
TNewButton=Class(TButton) // Объявление нового класса Protected
FNewOnClick: TMouseMoveEvent; // Объявление нового поля Public
Procedure Click; Override; // Замещение метода Property OnClick: TMouseMoveEvent Read FNewOnClick
Write FNewOnClick; // Событие End;
Procedure TNewButton.Click; // Реализация корреспондирующего метода Begin
Inherited Click; // Включен для демонстрации приведения типа IfAssigned(FNewOnClick) Then FNewOnClick(Self, [ssAlt], 50, 50);
End;
Procedure TForml.Button !MouseMove(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
Begin
MessageDlgPos('Move!', mtlnformation, [mbOK], 0,X, Y);
End;
Procedure TForml.Button2Click(Sender: TObject);
Begin
ShowMessage('Click!'); // Для демонстрации приведения типа End;
Создание компонента и делегирование ему события сделаем с помощью виртуального конструктора, который активизируем при открытии формы.
-67-
Procedure TFornil.ForinCreate(Sender: TObject);
Var NewBtn: TNewButton;
Begin
NewBtn :=TNewButton.Create(Self); // Создание кнопки With NewBtn Do Begin Parent:=Self;
SetBounds(10,10, 75,25);
Name:='NewBtn';
Visible:=True;
OnClick:=Buttonl.OnMouseMove; //Новое событие TButton(NewBtn).OnClick:=Button2.0nClick; // Щелчок мыши End;
End;
Приведенный пример позволяет продемонстрировать возможность переопределения типа события и возможность доступа к переопределенному событию предка с помощью приведения типов.
После запуска программы щелкнем мышью по кнопке NewBtn, - появится сообщение "Click!". Щелчок по кнопке ОК формы сообщения (MessageDIg) приведет к появлению сообщения "Move!". Это демонстрация приведения типа.
Если в виртуальном конструкторе удалить последнюю строку или/и строку Inherited Click в реализации метода TNewButton.Click, то щелчок по кнопке NewBtn сразу приведет к появлению сообщения "Move!". Это означает, что событие OnClick переопределено. Уведомительное событие заменено на специализированное и использованы его параметры Х и Y для вывода сообщения.
Выводы
Итак, если подвести итог, то можно сказать следующее:
• Windows является системой ориентированной на события.
• События в Delphi принимают форму сообщений.
• В недрах Windows VCL Delphi сообщения Windows обрабатываются и преобразуются в более простую для программиста форму.
• События в программе на Delphi вызываются не только сообщениями Windows, но и внутренними процессами.
• Обработка событий в Delphi сводится к написанию для каждого компонента своих обработчиков.