- •Основы офисного программирования и язык vba
- •Офисное программирование
- •Состав Office 2000
- •Инсталляция Office 2000
- •Содержимое диска "Resource Kit"
- •Документ Issues
- •Документ ork9
- •Папка Tools
- •Содержимое диска "Language Pack"
- •Об этой книге и ...
- •Моя благодарность
- •Vba и объекты. Обзор
- •Библиотека объектов Office 2000 - каркас приложений
- •Встраивание вместо наследования
- •Построение каркаса документа
- •Библиотека объектов Office 2000 и Object Browser
- •Объекты Application
- •Свойства-участники
- •Вторая группа терминальных свойств
- •Методы объектов Application
- •События объектов Application
- •Совместная работа приложений. Создание объектов Application. Раннее и позднее связывание
- •Коллекции в Office 2000
- •Коллекции объектов Office 2000
- •Коллекции Excel: Workbooks, Sheets
- •Коллекция Workbooks
- •Коллекция Sheets
- •Коллекции Word: Documents, Paragraphs и другие
- •Коллекция Documents
- •Коллекция Paragraphs
- •Коллекция Sections
- •Коллекции Characters, Words, Sentences
- •Коллекции и конструкция For Each … Next
- •Объекты Range
- •Что определяет объект Range?
- •Метод Range
- •Объекты Selection
- •Метод Select и свойство Selection
- •Активные объекты и метод Activate
- •Проектирование документов
- •Документ и его программный проект
- •Модули - обработчики событий
- •Стандартные модули
- •Модули классов
- •Модуль макросов
- •Структура модуля. Окно проекта и Окно кода
- •Окно проекта
- •Свойства проекта
- •Имя проекта
- •Защита проекта
- •Окно кода
- •Еще раз о "переиспользовании" модулей
- •Проект и область видимости
- •Система документов и ее проект
- •Организация системы документов
- •Как организуются ссылки между проектами
- •Обмен информацией между документами
- •Система документов One - Two - Three
- •Типы данных
- •Простые типы данных.
- •Объявление переменных и констант простых типов
- •Синтаксис объявления простых переменных
- •Объявления по умолчанию
- •Константы
- •Массивы
- •Динамические массивы
- •Записи и тип, определенный программистом
- •Что можно делать с записями?
- •Раздел объявлений
- •Раздел опций
- •Разделы констант, типов и переменных
- •Раздел Declare
- •Правила именования
- •Типы и классы Еще раз о понятии "класс"
- •Что нового в классах "Office 2000"
- •Создание класса "Личность"
- •Объекты и переменные
- •Объекты, класс которых определен пользователем.
- •Объекты "родного" приложения
- •ActiveX-объекты
- •Модуль класса Свойства
- •Сокрытие свойств
- •Конструкторы и деструкторы. Стандартные события
- •Стандартные события Initialize и Terminate
- •Два конструктора класса Rational
- •Процедуры - свойства
- •Как создаются процедуры- свойства
- •Синтаксис Let, Get и Set
- •Классы, как упаковка
- •Семейство классов и процедуры - свойства
- •Friend методы
- •События
- •Классы, объекты With Events и обработчики событий
- •Модуль класса с объектом WithEvents
- •Объект WithEvents
- •События собственных классов
- •Как создать класс с событиями
- •Как зажигаются события
- •Где и как следует создавать обработчики событий для экземпляров класса
- •Связывание объектов
- •Реальные объекты и инициирование событий
- •Семейство классов и реализация интерфейсов
- •Наследование
- •Виртуальные методы и полиморфизм
- •Абстрактные классы
- •Наследование и полиморфизм в Office 2000
- •Наследование интерфейсов
- •Полиморфизм семейства классов
- •Проект "Люди и Машины"
События собственных классов
Возможность создавать события собственных классов - это новинка Office 2000. Ранее было возможным для классов иметь только два стандартных события - Initialize и Terminate, играющих роль конструктора и деструктора по умолчанию. Теперь можно в классе создать набор событий и для каждого из экземпляров класса написать обработчики любого из этих событий. Тем самым расширяются возможности созданных Вами объектов. Это существенное продвижение в сторону классики объектного программирования. Попробуем разобраться:
-
как создать класс с событиями,
-
как зажигаются события,
-
где и как следует создавать обработчики событий для экземпляров класса,
-
какие действия конечного пользователя (системы) при работе с объектом инициируют событие,
-
как в ответ на событие посылается сообщение объекту и вызывается обработчик события.
Как создать класс с событиями
Первый вопрос, который необходимо решить при создании класса с событиями, лежит вне программирования, прежде всего, нужно решить, каким должен быть набор событий у объектов класса. Если с объектом связан некоторый графический образ, то ситуация более или менее стандартна, всегда разумно иметь события Click, Move, Resize и другие, типичные для графических объектов. Эти события будут возникать, когда пользователь будет работать с графическим образом, выполняя над ним те или иные типичные действия. Во многих случаях, наши объекты могут и не иметь графического образа, но и для них не менее полезно определить события. Общие рекомендации давать трудно, поэтому обратимся к примеру и рассмотрим ранее созданный класс Личность. Какие события разумно было бы определить для объектов этого класса? Учитывая, что свойств у объектов класса не так много, число разумных событий также не велико. Давайте определим два события - ИзменениеФамилии и ДеньРождения. Первое из этих событий возникает в ответ на изменение значения свойства Фамилия, второе, - когда текущая дата отличается от даты дня рождения Личности не более чем на сутки.
Поняв, какие события должен иметь наш класс, рассмотрим, как создать набор событий в классе. Все делается очевидным и естественным образом. Достаточно в разделе объявлений модуля класса объявить каждое из событий, используя ключевое слово Event. Вот как выглядит объявление класса Личность, имеющего два предусмотренных нами события:
Option Explicit
'Класс Личность
'События класса
Public Event ИзменениеФамилии(Fam As String, NewFam As String)
Public Event ДеньРождения(Dat As Date)
'Далее следует уже знакомое определение свойств и методов класса
'Смотри раздел "Создание класса Личность" этой лекции
Итак, чтобы создать класс с событиями просто добавьте список этих событий в объявление класса!
Как зажигаются события
Чтобы событие, связанное с объектом возникло, его нужно зажечь или возбудить (Raise). Зажигается событие специальной процедурой RaiseEvent, имеющей следующий синтаксис:
Sub RaiseEvent имя_события (параметры)
Эта процедура не только возбуждает событие, но и передает некоторые параметры, которые могут быть использованы в обработчике события. Что стоит за терминами "зажечь" ("возбудить") событие? При выполнении этой процедуры операционной системе посылается уведомление о том, что та должна послать объекту сообщение о возникновении события с указанным именем, в ответ на получение которого будет вызван обработчик этого события. Так что при выполнении этой процедуры плавный ход выполнения программы прерывается, происходит обмен сообщениями, вызов обработчика события и только по его завершении будет продолжено выполнение операторов, стоящих после вызова RaiseEvent.
Процедура RaiseEvent должна выполняться в одном из методов класса с событиями. Правильное определение ее места, это также одна из задач, которую нужно решить при проектировании класса, возможно, придется создавать специальный метод для этой цели. Обратимся к нашему примеру, когда и где нужно зажечь событие ИзменениеФамилии. Здесь ответ очевиден, - всякий раз, когда у объекта изменяется значение свойства Фамилия, должно возникать это событие. Но изменять значение для Private свойства следует единственным образом, - вызовом Property Let ВашаФамилия. Поэтому эта процедура именно то место, где должно возбуждаться событие. А в процедуре разумно поставить вызов RaiseEvent непосредственно перед оператором, изменяющим фамилию. Вот как выглядит эта процедура:
Public Property Let ВашаФамилия(ByVal NewValue As String)
'Зажигает событие ИзменениеФамилии
RaiseEvent ИзменениеФамилии(Фамилия, NewValue)
Фамилия = NewValue
End Property
Заметьте, мы передаем обработчику два параметра, старую и новую фамилию. Важно понимать, что можно не только передавать обработчику данные, но и получать информацию от него. Добавим еще один параметр Permission нашему событию, так чтобы обработчик события, проверив допустимость изменения фамилии, мог вернуть разрешение на изменение. Новый вариант события теперь выглядит так:
Public Event ИзменениеФамилии(Fam As String, NewFam As String, _
Permission As Boolean)
Соответственно изменится и процедура - свойство Property Let. Вот другой, более разумный вариант этой процедуры:
Public Property Let ВашаФамилия(ByVal NewValue As String)
'Зажигает событие ИзменениеФамилии
Dim Permission As Boolean 'Разрешение на изменение фамилии
Permission = True
RaiseEvent ИзменениеФамилии(Фамилия, NewValue, Permission)
'Обработчик события может запретить изменение фамилии
If Permission Then Фамилия = NewValue
End Property
Менее ясно, где и когда следует зажигать событие ДеньРождения. Мы решили возбуждать это событие в тот момент, когда пользователь интересуется датой рождения объекта, и вставили соответствующую проверку в Property Get ВашаДатаРождения процедуру:
Public Property Get ВашаДатаРождения() As Date
'Зажигает событие ДеньРождения
'в зависимости от значения текущей даты
If (Month(Now) = Month(ДатаРождения)) And _
(Abs(Day(Now) - Day(ДатаРождения)) <= 1) Then
RaiseEvent ДеньРождения(ДатаРождения)
End If
ВашаДатаРождения = ДатаРождения
End Property
Здесь событие возбуждается при выполнении некоторого условия, - текущая дата отличается от даты дня рождения не более чем на сутки. Дата рождения передается обработчику события, а тот, в свою очередь, может организовать уведомление и поздравление объекта с днем рождения, как это делает, например, Outlook для контактов из списка контактов.
Заметьте, процедура - свойство Property Get, в которой мы разместили оператор RaiseEvent, возбуждающий событие, - это не единственно возможное место для такого оператора. Вообще, одно и то же событие может возбуждаться в разных местах. В данном случае, может быть, имело смысл написать еще и специальный метод для возбуждения события, который вызывался бы пользователем в нужный момент.