Визуальное программирование и MFC

       

Типы событий


С помощью событий элемент управления OLE сообщает контейнеру о том, что “что-то произошло”. Стандартными примерами событий являются ввод данных с клавиатуры, перемещения и щелчки мыши, а также изменение внутреннего состояния элемента управления. Уникальность событий заключается в том, что элемент управления определяет тип события, но обрабатывается оно контейнером.

Доступ к методам обработки событий осуществляется с помощью средств OLE-автоматизации. Это означает, что они: имеют идентификаторы (DISPID); могут иметь произвольное число параметров; могут возвращать определенные значения.

Элемент управления OLE использует события для оповещения о том, что произошло некоторое действие или выполнилось некоторое условие (в библиотеке типов элемента управления следует описать все события, которые может сгенерировать данный элемент). Элемент управления определяет, что именно произошло, и генерирует требуемое событие, а контейнер его распознает и соответствующим образом обрабатывает. Для этого в контейнере должен быть реализован соответствующий набор методов-обработчиков событий.

Для реализации событий элементы управления и их контейнеры используют так называемые точки соединения (connection point). При встраивании элемента управления в контейнер сканирует все точки соединения элемента управления, пытаясь найти ту, которая обозначена как интерфейс диспетчеризации событий IDispatch (эта информация хранится в odl-файле элемента управления). В случае успеха контейнер подключает к ней свой интерфейс IDispatch, устанавливая, таким образом, канал связи.

События можно разделить на несколько видов: базовые события (stock events); события-запросы (request events); события-предупреждения (before events); события-следствия (after events); события-директивы (do events). Независимо от вида, все события различаются по имени и идентификатору (DISPID). Для каждой группы событий действуют свои соглашения о правилах присвоения имен, последовательности вызовов и т.п. Однако, по существу, все события одинаковы.
Все они генерируются (или порождается) элементом управления и через точку соединения попадают в контейнер. Получив событие, контейнер реагирует на него по своему усмотрению.

Так же как и у базовых свойств, у базовых событий есть заранее определенные имена и идентификаторы (DISPID). Приведем список всех базовых событий (их смысл понятен из названия): Click, DblClick, KeyDown, KeyPress, KeyUp, MouseDown, MouseMove, MouseUp, Error. В классе COleControl для генерации событий существуют методы, предназначенные для генерации всех базовых событий, их имена начинаются с Fire (например, FireClick). Для генерации пользовательских событий применяется методв FireEvent. (Пользовательскими называются события, которые сам программист добавляет к элементу управления. Они отличаются от базовых свойств тем, что класс ColeControl не генерирует их автоматически и не имеет стандартных методов оповещения, которые позволяют отслеживать их возникновение).

В классе ColeControl имеется ряд методов оповещения, вызываемых библиотекой MFC при генерации базовых событий: OnClick, OnKeyDownEvent, OnKeyPressEvent, OnKeyUpEvent. Эти методы являются виртуальными, поэтому элемент управления также может перехватывать события и самостоятельно их обрабатывать.

Для того, чтобы дать контейнеру возможность отменить какое-нибудь действие, элемент управления может генерировать события-запросы. Например, если пользователь решил закрыть элемент управления, тот может выдать событие RequestClose. Это позволяет процедуре-обработчику, находящейся в контейнере, отменить закрытие. Иначе говоря, элемент управления запрашивает разрешение сделать что-то, а контейнер должен решить, выполнять этот запрос или нет.

По умолчанию, последним параметром методов, генерирующих события-запросы, является ссылочная переменная типа CancelBoolean (тип данных, определенный в OLE). Эта переменная традиционно имеет имя Cancel, а ее значение указывает, должен ли элемент управления отвергнуть запрошенное действие (Cancel=TRUE) или выполнить его (Cancel=FALSE).



Во время события-запроса происходит следующее. OLE-элемент- управления устанавливает значение переменной Cancel в FALSE, тем самым давая знать контейнеру, что он должен что-то сделать. Элемент управления генерирует событие, вызывая соответствующий метод автоматизации в формате Request<Action>, где <Action> - запрошенное действие. Контейнер, в зависимости от запроса и текущего состояния системы, устанавливает значение параметра Cancel в TRUE (заставляя элемент управления отменить действие) или FALSE (разрешая элементу управления выполнить действие). Когда метод, сгенерировавший событие, завершается, OLE-элемент управления проверяет значение параметра Cancel и предпринимает соответствующие действия.

Перед тем как сгенерировать “настоящее” событие, элемент управления может сгенерировать событие-предупреждение. Это действие называется упреждающим оповещением (prenotification). Оно дает контейнеру возможность подготовиться к тому, что должно произойти. Следует учитывать, что контейнер не может отменить событие-предупреждение. Получив его, он может лишь выполнить какие-нибудь действия.

В соответствии с соглашением, имена методов, генерирующих события-предупреждения, имеют следующий вид: Before<Action>, где <Action> - действие, которое собирается предпринять элемент управления OLE (например, метод BeforeClose()).

После того, как что-то произошло, элемент управления может сгенерировать событие-следствие. Это действие называется последующим оповещением (postnotification). По сравнению с другими типами событий события-следствия являются наиболее распространнеными. Типичными примерами таких событий являются щелчки мыши и изменение свойств. Имена методов, генерирующих события-следствия, не подчиняются соглашениям о правилах присвоения имен. Кроме того, события-следствия не могут отменяться контейнерами.



События-директивы
определяются и реализуются в элементе управления, но могут быть переопределены в контейнере. Они генерируются для того, чтобы дать пользователю возможность переопределить или дополнить код обработчиков событий, реализованных в элементе управления по умолчанию.

Имена методов, генерирующих события-директивы, должны соответствовать следующему соглашению: Do<Action>. Последним параметром методов, генерирующих события-директивы, является булева переменная EnableDefault. Элемент управления устанавливает ее значение в TRUE и вызывает метод. Получив событие, контейнер может в ответ предпринять некоторые действия. Затем он устанавливает значение переменной EnableDefault в TRUE или FALSE, в зависимости от того, хочет ли он, чтобы элемент управления продолжил обработку события. Когда метод генерации сообщения завершается, элемент управления проверяет параметр EnableDefault. Если он равен TRUE, элемент управления вызывает стандартную реализацию метода, а если FALSE, то не вызывает ее.


Содержание раздела