Технологии программирования
Шрифт:
8. ОБРАБОТКА СООБЩЕНИЙ
Потребность в динамических методах особенно ощутима при разработке объектов, соответствующих элементам интерфейса Windows, когда каждый из большой иерархии объектов содержит обработчики десятков разнообразных сообщений.
Методы, предназначенные специально дня обработки сообщений Windows, составляют подмножество динамических методов и объявляются директивой message, за которой следует индекс — идентификатор сообщения. Они должны быть обязательно описаны как процедуры, имеющие один var-параметр, который может быть описан произвольно, например:
Для
Необходимости изобретать собственные структуры, по-своему интерпретирующие содержание того или иного сообщения, нет: для большинства сообщений Windows типы уже описаны в модуле MESSAGES.
В обработчиках сообщений (и только в них) можно вызвать метод-предок, просто указав ключевое слово inherited, без указания его имени и преобразования типа параметров: предок будет найден по индексу. Следует напомнить, что система обработки сообщений встроена в Object Pascal на уровне модели объектов, и самый общий обработчик — метод DefaultHandler — описан в классе TObject.
9. СОБЫТИЯ И ДЕЛЕГИРОВАНИЕ
Работать с большим количеством сообщений, даже имея под рукой справочник, нелегко, поэтому одним из больших достижений Delphi является то, что программист избавлен от необходимости работать с сообщениями Windows (хотя такая возможность у него есть). Стандартных событий в Delphi не более двух десятков, и все они имеют простую интерпретацию, не требующую глубоких знаний среды.
Рассмотрим, как реализованы события на уровне языка Object Pascal. События — это свойства процедурного типа, предназначенные для создания пользовательской реакции на те или иные входные воздействия:
Присвоить такому свойству значение — это означает указать объекту адрес метода, который будет вызываться в момент наступления события. Такие методы назовем обработчиками событий. Например:
Это означает, что при каждой активизации Application (так называется объект, соответствующий работающему приложению) будет вызван метод-обработчик MyActivatingMethod.
Внутри библиотеки времени выполнения Delphi вызовы обработчиков событий находятся в методах, обрабатывающих сообщения Windows. Выполнив принципиально необходимые действия, этот метод проверяет, известен ли адрес обработчика, и, если это так, вызывает его:
В зависимости от происхождения и предназначения события имеют разные типы. Общим для всех является параметр Sender, указывающий на объект-источник события. Самый простой тип — TNotifyEvent — не имеет других параметров:
Тип
метода, предназначенный для извещения о нажатии клавиши, предусматривает передачу программисту кода этой клавиши, а передвижение мыши — ее координат и т. п.Все события в Delphi принято именовать с "On": OnCreate, OnMouseMove, OnPaint и т. д. Щелкнув в Инспекторе объектов на странице Events в поле любого события, автоматически получается заготовка метода нужного типа. При этом его имя будет состоять из имени текущего компонента и имени события (без "On"), а относиться он будет к текущей форме. Пусть, например, на форме Form1 есть текст Label1. Тогда для обработки щелчка мышью на нем (событие OnClick) будет создан метод Tform1. Label1Click.
Поскольку события — это свойства объекта, их значения можно изменять во время выполнения программы. Такая замечательная возможность называется делегированием. Можно в любой момент взять способы реакции на события у одного объекта и делегировать их другому:
Но какой механизм позволяет подменять обработчики, ведь это не просто процедуры, а методы? Здесь как нельзя кстати приходится введенное в Object Pascal понятие указателя на метод. Помимо явно описанных параметров методу передается еще и указатель на вызвавший его экземпляр (Self). Вы можете описать тип процедуры, которая будет совместима по присваиванию с методом (т. е. предусматривать получение Self). Для этого в ее описание нужно добавить зарезервированные слова of Object. Указатель на метод — это указатель на такую процедуру:
Как в этом примере, так и повсюду в Delphi за свойствами-событиями стоят поля, являющиеся указателями на метод. Таким образом, при делегировании можно присваивать методы других классов. Здесь обработчиком события OnMyEvent объекта Obj1 по очереди выступают методы SetValue1 и SetValue2 объекта Obj2.