Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Прикладное программирование.doc
Скачиваний:
8
Добавлен:
25.12.2018
Размер:
683.01 Кб
Скачать

7.4. Переопределение стандартных событий

При различных изменениях в программах, работающих в Windows, по­сылаются различные сообщения Windows, которых сотни. Работать с таким большим количеством сообщений нелегко, даже имея под рукой справочник. Большим достижением Delphi является избавление программистов от необ­ходимости работать непосредственно с сообщениями Windows, хотя такая возможность у них есть. Вместо обработки большого числа сообщений Delphi предлагает программистам создавать обработчики событий. При этом стан­дартных событий в Delphi не более двух десятков.

События, предусмотренные в Delphi и наследующие наиболее общие случаи, возникающие в Windows, называются стандартными событиями. Как правило, поля для хранения значений этих событий защищены от разработ­чиков, т.е. нет возможности подключать обработчики к ним. При этом вызо­вы обработчиков стандартных событий происходят внутри методов, обраба­тывающих сообщения Windows.

Имеется две категории стандартных событий:

• События, определенные для всех средств управления. Эти события оп­ределены в классе TControl. Список подобных событий включает восемь на­именований и приведен в табл.3.

____ _____Таблица 3

,,—.::;;•::•::;:,::::•:"::;:.;:;..:••:;,:,:;

• наименование^-: i::^.- •^бйдд-пвя^^НУ

^^^^^^^^^^'^^^Назначе^^^ ^-^

OnClick

Пользователь щелкает по элементу управления

OnDragDrop

Завершена операция перемещения

OnEndDrag

Заканчивается или отменяется операция перемещения

OnMouseMove

Пользователь перемещает мышь над объектом

OnDblClick

Пользователь дважды щелкает мышью по элементу управления

OnDragOver

Объект перемещается над нужной областью или объектом управления

OnMouseDown

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

OnMouseUp

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

Эти события доступны во всех элементах управления. Стандартные со­бытия имеют корреспондирующие защищенные динамические методы. Так динамический метод Click вызывается для обработки события OnClick.

• В дополнение к ним определены стандартные события для стандарт­ных средств управления Windows, которые являются уже наследниками клас­са TWinControl. Список этих событий включает пять наименований и приве­ден в табл.4.

Эти события также имеют корреспондирующие методы.

Таблица 4

Наименование события

Назначение события;

OnEnter

Элемент управления получает фокус

OnKeyDown

Пользователь нажимает клавишу

OnKeyPress

Пользователь нажимает символьную клавишу

OnKeyUp

Пользователь отпускает нажатую клавишу

OnExit

Элемент управления теряет фокус

У пользователя есть следующие возможности переопределения событий:

• Можно переопределить событие в разделе с большей видимостью с целью сделать его доступными во время разработки и выполнения програм­мы.

Для того, чтобы сделать событие доступным во время выполнения и раз­работки программы, следует объявить его повторно в разделе Public или Published класса-потомка. Синтаксически это выглядит следующим образом:

Type

<имя класса>=С\а&&(<класс-предок>) Published

Property <имя события>\ II Переопределение события End;

В самой Delphi подобное переопределение сделано неоднократно. На­пример, в модуле Controls объявлен класс TControl, включающий событие OnClick, пример объявления которого в разделе Protected был приведен ранее в §7.1.

В модуле StdCtrls объявлен класс TButton, в котором переопределено это событие следующим образом:

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);