- •Основы офисного программирования и язык 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
- •Наследование интерфейсов
- •Полиморфизм семейства классов
- •Проект "Люди и Машины"
Семейство классов и процедуры - свойства
Когда создается семейство классов, без свойств - участников не обойтись. В классах семейства, основанных на механизме встраивания, обязательно есть свойства, представляющие собой объекты. Эти свойства, как и терминальные, обычно, закрываются и для работы с ними используются процедуры - свойства Property Set и Property Get. Иногда приходится передавать и дополнительные параметры при работе с ними. Рассмотрим типичный пример. Ранее мы построили класс "Личность", теперь построим класс "Группа", содержащий группу личностей. При построении этого класса ограничимся минимальными средствами, необходимыми для демонстрации работы со свойствами:
'Класс Группа Личностей
Const РазмерГруппы As Byte = 25
'Свойства
Private Group(1 To РазмерГруппы) As Личность
'Процедуры-свойства
Public Property Get ЧленГруппы(num As Byte) As Личность
'Если номер корректен
If (num >= 1) And (num <= РазмерГруппы) Then
'Если существует в группе личность с таким номером
If Not (Group(num) Is Nothing) Then
Set ЧленГруппы = Group(num)
Else: MsgBox ("В группе нет человека с номером " & num)
End If
Else: MsgBox ("Некорректно задан номер в группе - " & num)
End If
End Property
Public Property Set ЧленГруппы(num As Byte, NewValue As Личность)
'Если номер корректен
If (num >= 1) And (num <= РазмерГруппы) Then
'Если в группе нет личности с таким номером, то она создается
If Group(num) Is Nothing Then
Set Group(num) = NewValue
Else: MsgBox ("В группе уже есть человек с номером " & num)
End If
Else: MsgBox ("Некорректно задан номер в группе - " & num)
End If
End Property
Public Sub Сведения()
Dim i As Byte
For i = 1 To РазмерГруппы
If Not (Group(i) Is Nothing) Then
Group(i).PrintPerson
End If
Next i
End Sub
Пример 4.4. (html, txt)
Массив объектов класса "Личность" является закрытым свойством класса "Группа". Процедуры - свойства Property Get ЧленГруппы и Property Set ЧленГруппы обеспечивают доступ к элементам этого массива. Индекс элемента является дополнительным параметром. Заметьте, процедура Set имеет статус Write-once, - если элемент с заданным номером уже определен в группе, то он не переопределяется. При создании этих процедур, нам, конечно же, пришлось модифицировать стандартные заготовки Let и Get. Для полноты картины приведем процедуру, в которой показано, как работать с группой:
Public Sub WorkWithGroup()
Dim UserOne As New Личность
Dim UserTwo As New Личность
Dim UserThree As New Личность
Dim Знакомые As New Группа
Dim NewUser As New Личность
'Личности
UserOne.InitPerson FN:="Петр", LN:="Петров", DoB:=#1/23/1968#
UserTwo.InitPerson FN:="Анна", LN:="Козлова", DoB:=#7/21/1968#
UserThree.InitPerson FN:="Анна", LN:="Керн", DoB:=#5/17/1803#
'Группа
Set Знакомые.ЧленГруппы(1) = UserOne
Set Знакомые.ЧленГруппы(2) = UserTwo
Set Знакомые.ЧленГруппы(1) = UserThree
Set Знакомые.ЧленГруппы(3) = UserThree
Set NewUser = Знакомые.ЧленГруппы(7)
Set NewUser = Знакомые.ЧленГруппы(3)
Знакомые.Сведения
End Sub
Не останавливаясь на тех диалогах, которые будут появляться по ходу выполнения, приведем результаты печати сведений о наших старых знакомых:
Петр Петров родился 23.01.68
Анна Козлова родилась 21.07.68
Анна Петровна Керн родилась 17.05.1803
Мы уже говорили о том, что классы могут выступать в роли привлекательной упаковки при работе со служебными функциями. Такую же "упаковочную" роль они могут играть и при работе со встроенными объектами. Свойствами такого класса могут быть, например, элементы управления, - списки, кнопки. Класс - упаковка позволит обращаться к методам и свойствам объекта, может быть в более привлекательной для конечного пользователя форме. Кроме того, в классе могут быть определены и дополнительные свойства и методы, расширяющие стандартные возможности.
Без процедур - свойств можно обойтись, заменив их обычными методами класса. Правда, такая замена приведет, обычно, к некоторой потере эффективности. Но методы являются основным способом работы с данными (свойствами), определяя поведение объектов класса.
Методы
Не будем повторяться. О методах было сказано уже достаточно. Любая процедура (Sub) или функция (Function), описанная в разделе методов класса, является его методом. Напомним синтаксис методов класса:
[Private | Public | Friend] [Static] Sub name [(arglist)]
[statements]
[Exit Sub]
[statements]
End Sub
[Public | Private | Friend] [Static] Function name [(arglist)] [As type]
[statements]
[name = expression]
[Exit Function]
[statements]
[name = expression]
End Function
Роль всех ключевых слов в этих определениях уже пояснялась, чуть позже мы подробнее скажем о спецификаторе Friend, который могут иметь методы класса. Сейчас же отметим, что почти каждый класс, независимо от его специфики имеет некоторый "джентльменский" набор методов. В него входит:
-
Один или несколько конструкторов класса, в том числе конструктор по умолчанию, заданный обработчиком события Initialize.
-
Обычно, по паре процедур - свойств, определенных для каждого свойства класса.
-
Метод, задающий печать свойств класса.
-
Метод, позволяющий в диалоге с пользователем определять значения свойств класса, - своеобразный конструктор.
-
Остальные методы, определяющие специфику класса.
Вернемся к проектированию класса Rational. Большую часть джентльменского его набора мы уже определили. Специфика этого класса определяется операциями над рациональными числами. Ограничимся четырьмя основными операциями - сложением, вычитанием, умножением и делением. Добавим к ним еще и метод печати дробей. Вот тексты этих методов, заканчивающих определение нашего класса:
Public Function Plus(a As Rational) As Rational
Dim d As Integer, u As Integer, v As Integer
Dim R As New Rational
u = m * a.Знаменатель + n * a.Числитель
v = n * a.Знаменатель
d = nod(u, v)
R.Числитель = u \ d
R.Знаменатель = v \ d
Set Plus = R
End Function
Public Function Minus(a As Rational) As Rational
Dim d As Integer, u As Integer, v As Integer
Dim R As New Rational
u = m * a.Знаменатель - n * a.Числитель
v = n * a.Знаменатель
d = nod(u, v)
R.Числитель = u \ d
R.Знаменатель = v \ d
Set Minus = R
End Function
Public Function Mult(a As Rational) As Rational
Dim d As Integer, u As Integer, v As Integer
Dim R As New Rational
u = m * a.Числитель
v = n * a.Знаменатель
d = nod(u, v)
R.Числитель = u \ d
R.Знаменатель = v \ d
Set Mult = R
End Function
Public Function Divide(a As Rational) As Rational
Dim d As Integer, u As Integer, v As Integer
Dim R As New Rational
u = m * a.Знаменатель
v = n * a.Числитель
If v = 0 Then
MsgBox ("деление на нуль невозможно")
Else
d = nod(u, v)
R.Числитель = u \ d
R.Знаменатель = v \ d
Set Divide = R
End If
End Function
Public Sub PrintRational()
Debug.Print (m & "/" & n)
End Sub
Пример 4.5. (html, txt)
Замечание:
Внутри класса при реализации операций над рациональными числами доступ к закрытым свойствам объекта, естественно, разрешен, и можно обращаться непосредственно к переменным m и n. Однако нельзя обратиться к закрытым свойствам параметров класса Rational, передаваемых методам Plus, Minus, Mult, Divide. Точно также, нельзя обратиться к свойствам локальных объектов (объекту R), объявленных внутри методов. Единственный выход состоит в том, чтобы использовать для них Public Property Let и Public Property Get. Но тогда и вне класса можно использовать эти процедуры - свойства, изменяя, например, значение знаменателя дроби. Разрешать этого не хотелось бы.
На наш взгляд имеет место концептуальная некорректность поведения закрытых свойств. Внутри класса доступ к ним должен быть открыт не только для самого объекта, но и для объектов этого класса, заданных в качестве параметров методов класса. Точно также доступ должен быть открыт и для локальных объектов. Так поступают в большинстве языков программирования.
Приведем процедуру, которая работает с рациональными числами:
Public Sub WorkWithRational()
Dim a As New Rational, b As New Rational, c As New Rational
a.CreateRational 5, 7
b.CreateRational -12, -18
Set c = a.Plus(b)
c.PrintRational
Set a = c.Minus(b)
a.PrintRational
Set c = a.Mult(b)
c.PrintRational
Set b = c.Divide(a)
b.PrintRational
End Sub
При ее запуске получены следующие результаты:
29/21
5/7
10/21
2/3