Иллюстрированный самоучитель по Outlook2002

         

Добавление кнопки на панель


Для добавления кнопки на панель выполните следующую операцию.

Пример 22.9. Добавление кнопки на панель инструментов

{В диалоговом окне Настройка}

Команды

Катерогии Макросы

Команды BookTask.GenerateTask (рис. 22.12)

Рис. 22.12. Вкладка Команды диалогового окна Настройка

Теперь необходимо перетащить команду из диалогового окна Настройка на панель BookTask. По умолчанию получаются очень длинные кнопки с текстом, которые выглядят как команды меню, а не как кнопки панели инструментов (рис. 22.13).

Рис. 22.13. Кнопка на панели инструментов с контекстным меню

Чтобы панель инструментов приняла привычный для настоящей панели вид, необходимо отформатировать кнопки.

Пример 22.10. Форматирование кнопки пользователя

1R BookTask.GenerateTask

Имя := Назначить задачу писателю

Значок и текст

> Выбрать значок для кнопки > [1,6]

Закрыть

После того как закрыто диалоговое окно Настройка, вы можете перемещать, пристыковывать панель и т. д. Теперь, после щелчка по кнопке Назначить задачу писателю, появится диалоговое окно Задача: Написание книги (рис. 22.14). Неправда ли просто?



Рис. 22.14. Диалоговое окно Задача: Написание книги

Замечание

Помимо создания панелей инструментов и кнопок, можно задавать "горячие" клавиши для вызова макросов пользователей или создавать дополнительные разделы меню.



Добавление полей пользователя


Прежде чем добавить пользовательское поле, необходимо определить, на какой из вкладок мы его будем размещать. Поскольку наши поля достаточно специфические, то для их размещения выберем вкладку (2) и изменим ее название и параметры отображения.

Пример 19.2. Создание вкладки пользователя

{Вкладка (2)}

> Форма > Отображать эту страницу

> Форма > Переименовать страницу.. .

Название := Книги

ОК

Давайте теперь добавим поля название книги и количество страниц. Первый этап — это создание поля.

Пример 19.3. Создание поля пользователя

{Панель Выбор поля}

Создать...

Имя := Название книги 1

Тип Текст

Формат Текст

ок

Создать...

Имя := Кол-во страниц 1

Тип Целое число

Формат 1 234

ОК

Созданные поля помещаются в разделе Поля пользователя в папке (User-defined fields in folder). Тип поля определяет данные, которые могут заноситься в это поле, а формат — представление этих данных. Например, нельзя в поле количество страниц ввести текст или дробное число.

Второй этап — перенос поля на вкладку пользователя. Для этого щелкните по выбранному полю на панели Выбор поля (Field Chooser), а затем, удерживая нажатой кнопку мыши, перенесите его на вкладку формы и отпустите кнопку мыши. Поля добавляются вместе с подписями к ним.

Поскольку предполагается, что контакт может иметь несколько книг, повторите вышеприведенную процедуру, только изменяя значение в поле Имя (Name) на название книги 2, название книги з и т. д.

Замечание

Пользователь может не создавать, а выбирать уже готовые поля на панели Выбор поля.



Инициализация формы


В предыдущем разделе мы говорили о статическом изменении свойств элементов управления, но это лишь первичная настройка объектов формы. Как правило, основные свойства, связанные с инициализацией данных, переносятся в программный модуль формы.

Рассмотрением инициализации подобных свойств мы и займемся в этой главе, но для начала несколько слов о форме как таковой. Если рассматривать форму с позиций программирования, то она представляет собой не что иное, как класс VBA. Членами этого класса являются элементы управления, расположенные на форме, а методами — show (показать форму), Hide (скрыть форму) и т. д. Более того, пользователь может добавлять собственные члены и методы.

Помимо этого форма обладает и рядом процедур реакции на событие, стандартными из которых для всех классов VBA являются initialize и Terminate (см. раздел 20.5 "Классы и объекты").

Вернемся к нашей задаче и вспомним, что нам необходимо проинициализи-ровать три списка нашей формы, а именно: series, author и duration. Если duration фиксирован и состоит из 12 элементов (12 месяцев), то относительно списков авторов и серий так сказать нельзя. Количество членов в группе писателей может увеличиваться и уменьшаться, ровно также дело обстоит и с сериями. Исходя из этого пользователь должен иметь возможность, не модифицируя кода программы, изменить количество элементов любого из списков.

В следующих разделах подробно описываются способы инициализации списков.



Элементы управления


Следующее поле, которое мы будем создавать, — Переплет. Как вы уже знаете, поле переплет может принимать только одно из двух значений: твердый или мягкий. Конечно, это поле можно создать по аналогии с двумя предыдущими и требовать от пользователя ввода его значения. Но гораздо корректнее и рациональнее использовать раскрывающийся список. Раскрывающийся список — это один из стандартных элементов управления, о которых пойдет речь в данном разделе.



Классы и объекты


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

В самом упрощенном понимании объект — это какая-то вещь или материальная сущность реального мира. Оглянитесь вокруг, и вы увидите, что наш мир состоит из бесконечного числа объектов: стол, машина, клавиатура компьютера, дом, человек и т. д. (более того, даже мир — это объект). Если приглядеться, то каждый объект имеет свойства (машина черного цвета) и операции, которые выполняются над этими свойствами (ту же машину можно перекрасить в экзотический металлик). Почти аналогично обстоит дело с объектами в абстрактном мире программ. Например, в качестве объекта можно рассматривать файл, в качестве свойства — его размер или имя, а в качестве операций — чтение или запись.

Рассмотрим еще один пример объекта в абстрактном мире программ — переменную author типа Person CO свойствами name И birthday. Итак, естЬ объект и есть свойства, что же является операцией в данном случае? Любая пользовательская процедура или функция, изменяющая свойства объекта author или просто работающая с ними. Например, процедура инициализации полей записи или процедура вывода на экран значений полей.

А теперь представьте, что код программы испещрен как процедурами, которые относятся к работе с записью author, так и функциями, относящимися к другим переменным, которых тоже не мало. Совсем нетрудно будет заблу диться в подобном хаосе и применять нужную функцию к неверным данным или, наоборот, необходимые данные подставлять не в ту функцию. Возникает естественное желание объединить данные и способы их обработки в одно целое — так, чтобы было ясно, какие процедуры предназначены для обработки каких данных.
Таким образом, мы вплотную подошли к центральным понятиям объектно-ориентированного программирования — понятиям инкапсуляции и класса.

Объектно-ориентированное программирование (ООП) — наиболее популярная в настоящее время методология программирования, являющаяся развитием структурного программирования. Центральной идеей ООП является инкапсуляция, т. е. структурирование программы на модули особого вида, объединяющие данные и процедуры их обработки (вот оно, решение всех проблем!), причем внутренние данные модуля могут быть обработаны только предусмотренными для этого процедурами. В разных вариациях ООП этот модуль называют по-разному: класс, абстрактный тип данных, кластер и др. В VBA принято называть этот модуль модулем класса, или просто классом. Каждый такой класс имеет внутреннюю часть, называемую реализацией, и внешнюю — интерфейс.

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

В случае с записью Person при добавлении к ней двух процедур (persinit, persPrint) мы фактически получили класс, одним из объектов которого будет author. Доступ к свойствам и методам объекта осуществляется (как и в случае с записью) посредством точечной нотации. Например, для того, чтобы вывести на экран свойства объекта author с помощью метода Print, необходимо ввести в программу выражение author. Print ().

Помимо инкапсуляции, ООП VBA характеризуется еще одним немаловажным свойством — встраиванием. Встраивание — это механизм порождения новых классов с использованием существующих.



Пусть построен класс А, тогда при объявлении нового класса В его свойствами могут быть объекты класса А. В этом случае говорят, что класс А встроен в класс В, и класс А является родителем, а класс В — потомком. Встраивание — транзитивное отношение, т. е. можно создать произвольно длинную цепочку вложенных объектов, образующих иерархию родителей и потомков. Так, в новый класс С можно встроить объект класса В, который является объектом класса А.

Для приложений Office XP характерна ситуация, когда необходимо указать шесть-восемь уровней вложенности, чтобы добраться до нужного объекта. Например, чтобы скрыть панель инструментов Стандартная, выполните следующий оператор присваивания:

Outlook.Application.ActiveExplorer.ShowPane (olOutlookBar ,True )

Механизм встраивания очень удобен и естественен. Прародитель семейства классов может задавать некоторые фундаментальные свойства и методы, а многочисленные потомки, имея родительские корни (свойства и методы), привносят собственные узкоспециальные свойства и методы.

Например, создавая класс Book со свойством Author класса Person, мы не только используем фундаментальные свойства и методы класса Person, но и вводим собственные свойства (title) и методы.

Наряду со встраиванием, существует еще один способ использования существующих классов при создании новых, он называется наследование. При наследовании указывается, что вновь создаваемый класс В на основе класса А содержит все (или некоторые) методы и свойства класса А, а также свои собственные методы и свойства. Например, на основе класса Person можно определить класс Author, который содержит все методы и свойства класса Person, а также свои собственные, например список книг данного автора.

Перейдем теперь от теоретического описания канонов ООП к практике их применения в VBA и начнем с синтаксиса. Синтаксически классы в VBA оформляются в виде специальных модулей классов (имя класса — это имя модуля), где в разделе Declarations помещается описание свойств (переменных) класса, а дальше идет описание методов (процедур) класса.


Синтаксически описания свойств и методов практически не отличаются от описания обыкновенных переменных и процедур. Случаи отличия или особенностей употребления будут оговорены отдельно.

Давайте рассмотрим работу с классами на примере класса Person.

Пример 20.1. Создание класса Person

> Insert > Class Module

Properties Name:= Person

Программа 20.21. Создание класса

Public name As String Private birthday As Date Private male As Boolean

Public Sub perslnit( Optional persName As String = "Novikov", Optional persBirth As Date = #10/10/511, Optional persMale As Boolean = True)

name = persName birthday = persBirth male = persMale End Sub

Public Sub persPrint ()

Dim str As String

str = "Person name is " & name & Chr(13) & Ilf(male,"He","She") & " was born in " & birthday

MsgBox(str) End Sub

Перед тем как перейти к описанию синтаксиса объявления объектов класса, мы хотели бы обратить внимание на внутренний процесс их создания. Вообще, объект — это переменная, поэтому, когда он создается, для него выделяется необходимая память (ее размер зависит от типов свойств класса), а имя объекта ссылается на адрес памяти, где расположен объект. А теперь небольшой фокус, невозможный для переменных простых типов. В VBA есть возможность создания только ссылки на объект без фактического его присутствия. Подобная ссылка указывает адрес памяти, где будет храниться объект. Синтаксис объявления ссылок на объект не отличается от объявления простых переменных:

{Dim | Private | Public} имяОбъекта As Object

Если вы обратитесь к таблице встроенных типов (табл. 20.4), то увидите, что для переменных данного типа отводится 4 байта, ровно столько, сколько необходимо для хранения адреса памяти. Конечно, ссылка сама по себе бессмысленна и ее, в конце концов, необходимо будет связать с реально существующим объектом посредством оператора присваивания set, но до этого нужно объявить объект. Синтаксис объявления объектов, класс которых определен пользователем, прост:



(Dim |Private | Public | Static} имяОбъекта As [New] имяКласса

Спецификатор New указывает компилятору, что создается новый объект и под него необходимо выделить память. Использование оператора set позволяет связывать ссылку с реальным объектом:

Set ИмяОбъекта = {[New] объектноеВыраженме | Nothing}

имяОбъекта и объктноевыражение — это ссылки на объект. Таким образом, ссылке слева присваивается значение ссылки справа. Спецификатор Nothing разрывает установленное значение ссылки. Связывание с использованием оператора New называется ранним, с использованием ссылок на объект — поздним.

Рассмотрим объявление объектов класса Person. Сначала создается объект author. Далее посредством метода класса persinit инициализируются свойства объекта: имя, дата рождения и пол. После чего объявляется ссылка на объект, а потом происходит присваивание ссылке he значения ссылки author и в качестве подтверждения того, что все связалось верно, производится вывод свойств объекта he посредством метода persPrint.

Программа 20.22. Объявление объектов класса, определенного пользователем

Sub ObjectExample () Dim author As New Person Dim he As Object

author.perslnit "Novikov", #10.10.51*

Set he = author

he.persPrint End Sub

После объявления объектов, определенных пользователем, уместно рассказать об объявлении нового класса на основе уже созданного. Как мы говорили выше, для этого предусмотрен механизм встраивания объектов родительского класса в новый класс. Таким образом, объект класса родителя становится значением свойства класса потомка. Но объявление такого свойства синтаксически выглядит как объявление объекта класса. Продемонстрируем встраивание классов на примере создания нового класса Book. Для этого сначала проделаем стандартную процедуру создания нового модуля класса и присваивания ему имени Book. Потом встроим объект author класса Person И добавим СВОЙСТВО title И Два метода booklnit И bookPrint.

Метод bookinit инициализирует объект класса Book, в качестве параметров этот метод получает строку для инициализации свойства title и ссылку на объект класса Person для инициализации свойства author.



Программа 20.23. Встраивание классов

Dim author As New Person Private title As String

Public Sub booklnit (str As String, persObject As Person)

title = str

Set author = persObject End Sub

Public Sub bookPrint() Dim str As String

str = "Book title is " & title & Chr(13) & "Written by " & author.name

MsgBox(str) End Sub

Покажем использование объектов класса Book, изменив код программы 20.22 следующим образом:

Программа 20.24. Использование объектов встроенных классов

Sub ObjectExample()

Dim author As New Person

Dim bookObj As New Book

author.perslnit "Novikov", #10/10/1951#

Эта функция также возвращает ссылку на объект ActiveX. Только в этом случае в качестве параметров выступает путь, который указывает полный путь к файлу с объектом. Второй параметр при этом не обязателен.

В нижеприведенной программе мы открываем документ Word двумя разными функциями.

Программа 20.26. Открытие документа

Sub DocOpen1 ()

Dim docObj As Object

Set docObj = CreateObject ("Word.Application")

docObj.Visible = True

docObj.Documents. Add

БлокОператоров

docObj.Quit End Sub

Sub DocOpen2 ()

Dim docObj As Object

Set docObj = GetObject("d:\of200l\62\62.doc") End Sub

Выше мы рассмотрели вопросы объявления класса и использования его объектов вообще. Теперь же перейдем к изучению внутреннего устройства и организации класса более детально, а именно рассмотрим виды процедур класса и их работу со свойствами класса.

В VBA все процедуры класса делятся на три группы:

1. Процедуры-методы.

2. Процедуры-свойства.

3. Процедуры — реакции на событие.

Синтаксис объявления процедур-методов не отличается от стандартного, за исключением возможного использования ключевого слова Friend, о котором говорилось в разделе 20.4 "Структура программы". Настала пора детально рассмотреть возможность его употребления. Ключевое слово Friend, как и ключевые слова Private и Public, предназначено для ограничения области видимости метода.


Если Private делает метод видимым только внутри модуля, a Public — для всех модулей всех проектов, то Friend занимает промежуточную позицию между ними, он делает видимым метод только в том проекте, где был описан класс.

Как известно, определение класса в VBA состоит из двух разделов: реализации и интерфейса. Одна из наиболее трудных задач для программистов-новичков в ООП заключается в определении того, какие члены класса делать закрытыми (включать в раздел реализации), а какие, наоборот, открытыми (включать в раздел интерфейса). Общим правилом можно считать, что

чем меньше программе известно о реализации класса, тем лучше. То есть желательно скрыть посредством ключевого слова Private как можно большее количество свойств класса в разделе реализации, а доступ к свойствам осуществлять через специальные открытые методы (Public), организующие интерфейс класса.

Замечание

Сокрытие информации — это сокрытие деталей реализации функций, класса или даже программы. В условиях сокрытия информации программист работает с функциями и классами, как с черными ящиками. Другими словами, передавая функции некоторое значение в форме входного параметра, программист знает лишь результат, который будет получен на выходе этой функции. Сокрытие информации в реализационную часть класса и доступ к ней через функциональный интерфейс повышают надежность программы.

Например, предположим, что свойство birthday класса Person может принимать значения только в диапазоне от 1900 до 2000. Если это свойство объявлено как Public, то ему можно присвоить недопустимые значения: writer.birthday = #31/12/1899#. Ограничение видимости свойства и использование метода Public дает возможность проверки присваиваемых значений:

Public Sub InitBirthday( bthday As Date)

If bthday > #l/l/1900# and bthday < fl/1/20001 Then

birthday = bthday Else

MsgBox ("You date is out of range") End If End Sub

Таким образом, употребление ключевого слова Public при объявлении свойства name в классе Person также оказывается некорректным.


Но, если отменить глобальную видимость, то станет невозможным употребление функций, напрямую связанных с глобальными свойствами. Например, метод bkPrint класса Book окажется некорректным, т. к. уже нет доступа через author.name. Как же быть? Как тогда получить значение этого свойства?

В VBA предусмотрены специальные процедуры-свойства, которые предназначены для чтения и записи закрытых свойств:

Property Let

Процедура записи позволяет присваивать свойству новые значения

Property Set

Процедура записи позволяет присваивать свойству и свойству-ссылке новые значения. Отдельная процедура нужна, поскольку свойство-ссылка'указыва-ет на объект, а присваивание объектам отличается от присваивания переменным простых типов.

Property Get

Процедура чтения (а точнее функция) позволяет считывать значение свойства. Эта процедура применима как к простым свойствам, так и к свойствам-ссылкам.

Приведем синтаксис каждой из них:

[{Public | Private | Friend}] [Static] Property Let имяПроцедурыСвойства

([списокПараметров] значение)

[блокОператоров 1}

[Exit Property]

[блокОператоров2]

End Property

Синтаксис прост и понятен. Сначала идут операторы объявления видимости процедуры-свойства и необязательное ключевое слово static. Кстати, хотя использование ключевого слова private допустимо, его присутствие сводит на нет смысл процедуры-свойства.

ИмяПроцедурыСвойства — это имя процедуры, изменяющей свойство.

Совет

Желательно, чтобы имя повторялось во всех трех процедурах-свойствах, если они имеют дело с одним и тем же свойством.

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

Значение — это самый важный обязательный параметр, значение которого передается свойству.

Далее идет блокОпера торов, в котором следует произвести присваивание свойству значения фактического параметра значение.



Процедура Property Set имеет следующий синтаксис.

[{Public | Private | Friend}] [Static] Property Set имяПроцедурыСвойства ([списокПараметров] ссылкаНаОбъект) [блокОператоров 1] [Exit Property] [блокОператоров2] End Property

Здесь только одно отличие от предыдущей процедуры: вместо аргумента значение стоит аргумент ссылкаНаОбъект, который представляет имя ссылки на объект, присваиваемый свойству-ссылке.

Осталось рассмотреть функцию чтения значения свойства.

[{Public | Private | Friend}] [Static] Property Get имяПроцедурыСвойства ([списокПараметров]) As ТипДанных [блокОператоров1]

[имяПроцедурыСвойства = выражение] [Exit Property] [блокОператоров2] End Property

Как видно, Property Get — это функция, и для нее действуют все синтаксические правила функций. Напомним лишь одно: тип значения, возвращаемого функцией, должен совпадать с типом значения выражение.

Рассмотрим использование процедур-свойств на нашем примере класса

Person. Поскольку МЫ объявили свойства класса name, birthday И male 3акрытыми, введем процедуры-свойства для работы с ними. В примере отображена только одна пара для свойства birthday, для name и male все строится аналогично.

Программа 20.27. Использование процедур-свойств

Public Property Get prsDateO As Date

prsDate = birthday End Property

Public Property Let prsDate(bthday As Date)

If bthday > #1/1/19001 And bthday < #1/1/20001 Then

birthday = bthday Else

MsgBox ("Incorrect date") End'If End Property

Но вернемся к методу bkPrint класса Book. Сейчас он не работает, поскольку обращение author.name стало бессмысленным. Для правильной работы метода необходимо заменить строку с неправильным оператором на следующую:

str = "Book title is " & title & Chr(13) & _ "Written by " & author.prsName

Таким образом, дойдя до данной строки кода, программа выполнит процедуру-свойство объекта author, т. е. prsName, которая возвращает текущее значения свойства name.

После описания процедур-свойств перейдем к заключительному аккорду в рассмотрении процедур класса: к процедурам реакции на событие.


Выше мы уже упоминали о них. Напомним, что тогда мы приводили пример процедуры реакции на событие Document_ciose (реакция на событие "Закрыть документ"). Как мы упоминали, существует множество событий и множество процедур реакции на них. Но помимо встроенных процедур, пользователь вправе создавать собственные обработчики событий.

Чтобы пояснить сказанное, рассмотрим типовой сценарий жизни объекта от объявления до удаления:

1. Вход в процедуру для работы с объектом.

2. Создание ссылки на объект.

3. Создание нового объекта.

4. Работа с объектом.

5. Выход из процедуры.

Прокомментируем этот сценарий. Для человеческого глаза нет ничего особенного в этой быстротечной жизни, а для системного "всевидящего ока" произошло два очень важных события: создание объекта и его удаление (при выходе из процедуры). Более того, мы не заметили, как были выполнены две процедуры реакции на эти события: initialize и Terminate, которые, соответственно, проинициализировали и уничтожили объект. Рассмотрим их подробнее.

Когда создается объект, вызывается процедура initialize, которая всем свойствам объекта присваивает значения, определенные для них по умолчанию. Данная процедура называется конструктором. Пользователь вправе изменить эту процедуру, указав, как инициализировать свойства объекта при его непосредственном объявлении.

Когда же объект выходит из области своего действия, например из процедуры, в которой он был локально объя-влен, автоматически вызывается процедура Terminate, которая освобождает память, занимаемую объектом и ссылкой на него. Эту процедуру называют деструктором. Пользователь вправе и здесь изменить процедуру, но на практике этой возможностью пользуютсяо-чень редко.

Покажем использование процедур реакции на событие на примере класса Person. Мы ввели конструктор, инициализирующий свойства name, birthday И male.

Программа 20.28. Объявление процедур реакций на событие

Private Sub Class_Initialize()

name = "Novikov"

birthday = #10/10/19511



male = True End Sub

Конечно, это только первичная инициализация, для последующих инициализаций необходимо написать собственный конструктор. В нашем классе Person роль такого конструктора играет метод persinit.

Поздравляем: класс полностью готов к работе! Теперь вы можете использовать его возможности на полную мощность и ощутить всю прелесть ООП.

Попытайтесь самостоятельно встроить в наш класс Person еще несколько свойств и методов, а потом реализовать их.

На этом мы заканчиваем описание классов в VBA. Надеемся, что все описанные выше конструкции и примеры достаточно просты и понятны. Единственное, чему еще хотелось бы уделить особое внимание, — это семейство (collection), структура (класс) VBA, стоящая несколько в стороне от канонического описания, но тем не менее очень важная при реализации ряда задач, а также очень часто используемая в объектной модели Microsoft Office XP.

Давайте рассмотрим следующую задачу: допустим, мы полностью определили класс Book (в качестве домашнего задания исправьте это "допустим" на "с легкостью") и перед нами стоит проблема упорядочения все нарастающих сведений о книгах, да так, чтобы в этой системе можно было легко выполнить поиск, чтение и запись. Конечно, располагая имеющимися на данный момент обучения средствами, мы могли бы создать массив объектов класса Book. Но подобная конструкция не отвечает нашим возросшим требована ям, например добавление и удаление книг, их поиск потребуют специальных средств (создание специальных функций, проверка и т. д.).

Для решения подобной проблемы в VBA присутствует особый класс collection, который позволяет очень быстро и удобно решить проблему построения динамических структур данных.

Семейством (Collection) называется упорядоченный набор объектов. В принципе объекты могут быть разных классов, но, как правило, встречаются семейства однородных объектов. Грубо говоря, семейство представляет собой сплав динамического массива и записи, что позволяет, с одной стороны, перенумеровать все элементы семейства, а с другой, иметь прямой доступ к объектам — элементам семейства — по значению определенного поля, называемого ключом. Ключ — это строковое выражение, которое может быть использовано вместо индекса для доступа к элементу семейства.



Как же устроен этот чудо-класс? Класс collection имеет одно свойство

Count и три метода — Add, Item и Remove.

Свойство count очень простое, оно возвращает количество элементов семейства (то есть количество объектов, включенных в семейство в данный момент).

Метод Add (элемент (, ключ] [, до] [, после}) добавляет объект в семей-ство. Его обязательным аргументом является элемент. Он, как вы можете догадаться, добавляет в семейство элемент. Параметр ключ задает ключ, по которому можно будет произвести поиск этого элемента. Параметры до и после указывают на то, перед каким или после какого элемента добавляется новый. По умолчанию элемент добавляется в конец семейства.

Метод Remove (ключ) удаляет элемент из семейства. Параметр ключ — это ключ или индекс, указывающий на удаляемый элемент. Заметьте, что при удалении элемента из семейства не остается дыр : индексы перенумеровываются, значение свойства count уменьшается на единицу.

Метод item (ключ) возвращает значение элемента семейства с ключом ключ. Как в случае с методом Remove, параметр ключ может быть как ключом, так и индексом.

Давайте запрограммируем решение вышерассмотренной задачи, используя знания о семействе. В этом примере мы объявляем семейство Books и инициализируем его, добавляя три объекта. После того как семейство инициализировано, мы удаляем один элемент и выводим оставшиеся элементы.

Программа 20.29. Объявление семейства

Sub BooksCollection()

Dim Books As New Collection

Dim Novikov As New Person

Dim Vba As New Book

Novikov.perslnit "Novikov", #10/10/1951#, True

Vba.booklnit "VBA и разработка приложений в Office 2000", Novikov

Books.Add Vba, "VBprog"

Dim Office As New Book

Office.booklnit "Microsoft Office 2001 в целом", Novikov

Books.Add Office, "off"

Dim Stroustrup As New Person

Dim С As New Book

Stroustrup.perslnit "Stroustrup", #11/25/1947#

C.booklnit "C++ Programming", Stroustrup

Books.Add C, "Cprog", 2

Books.Remove "Cprog" For i = 1 To Books.Count

Books.Item(i).bookPrint Next i End Sub

На этом мы заканчиваем описание языка VBA, считая, что вы готовы к его полноценному использованию, и переходим к описанию редактора Visual Basic Editor.


Макет


Итак, все намеченные поля нашей формы созданы, и если смотреть на нее с точки зрения функциональности, то можно сказать, что она готова. Однако одним из немаловажных качеств формы является наличие простого и интуитивно понятного интерфейса.

Конструирование легкодоступного и красиво оформленного интерфейса — довольно сложная задача.' Но создание простого интерфейса, не лишенного логики и вкуса, доступно любому пользователю. Более того, использование встроенных средств Outlook позволяет пользователю добиться профессионального оформления форм, диалоговых окон, панелей и т. д.

Начнем с логики в заполнении полей нашей формы. Естественно предположить, что пользователю гораздо удобнее заполнять поля в следующем порядке:

Название книги 1, Кол-во страниц 1, Переплет 1

Название книги 2, Кол-во, страниц 2, Переплет 2 И Т. Д.

Таким образом, необходимо переместить соответствующие поля, расположив их в одной строке. Чтобы переместить элемент, его нужно выделить, а затем, удерживая нажатой левую кнопку мыши, перенести на требуемое место.

По умолчанию элементы создаются с определенными параметрами высоты и ширины (если вы создавали их, просто щелкая по форме, не растягивая). Но, как правило, параметры по умолчанию не удовлетворяют логике поля. Например, стандартное текстовое поле по умолчанию отображает 15 знаков, но поле для ввода количества страниц вряд ли будет содержать значение, имеющее больше 4 символов, а поле для ввода названия книги, скорее всего, будет содержать больше, чем 15. Для изменения размера поля можно либо задать соответствующие параметры на вкладке Оформление "(Display), либо воспользоваться маркерами изменения размера в виде маленьких белых квадратиков, расположенных по углам поля. Щелкнув по маркеру выделения и удерживая нажатой левую кнопку мыши, можно увеличить или уменьшить границы поля.

В крупных компаниях (например, Microsoft) над разработкой интерфейса трудятся специальные отделы дизайнерон.

Если по выделенному элементу щелкнуть еще раз, то он перейдет в режим редактирования, в этом режиме можно, например, изменять параметр Заголовок (Caption) для надписи.
Измените данный параметр для объектов типа Label, удалив цифры из названий.

Вы увидите, что логика оформления формы соблюдена, но стройности и строгости в ее оформлении нет. Следующий этап в работе над интерфейсом формы — выравнивание.

Существует много способов выравнивания, но мы не будем все их подробно здесь рассматривать, т. к. большинство из них интуитивно понятны, а в случае возникновения вопросов вы всегда сможете обратиться к справочной системе Outlook. Здесь будет приведено лишь описание групп команд выравнивания.

Все команды выравнивания находятся в меню Макет (Layout). Существует пять разделов с командами:

выровнять (Align). Команды, связанные непосредственно с выравниванием. Например, по ширине или по краю формы;

группировать (Group). Объединение элементов управления в одну группу;

порядок (order). Отображение объекта на переднем или на заднем плане;

сетка (grid). По умолчанию форма в режиме конструктора отображается с сеткой (маленькие точки). Благодаря сетке можно задавать положение и выравнивание объектов;

последовательность перехода (tab order). Этой командой задается последовательность перехода от поля к полю посредством нажатия клавиши <Таb>.

После того как форма создана, хочется посмотреть на нее в действии, проверить, работают ли текстовые поля, списки, формулы и т. д. Для этого выберите команду > Форма > Выполнить форму.


Объектная модель Office XP


Объекты Microsoft Office используются в иерархической структуре других объектных моделей. Описание основных объектов Microsoft Office, собранных в библиотеке Office, приведено в табл. 21.2.

Таблица 21.2. Описание объектов Microsoft Office XP

Объект

Тип

Описание

Assistant

Объект и семейство

Ссылается на объект, представляющий активного в данный момент Помощника по Office

CommandBar

Объект и семейство

Содержит объекты CommandBar, соответствующие панелям команд приложения-контейнера (это могут быть строки меню, панели инструментов и контекстные меню)

FileSearch

Объект

Реализует функциональность стандартного диалогового окна открытия файла

LanguageSetting Новый объект Предоставляет информацию о языковых настройках приложения семейства Microsoft Office
AnswerWizard Объект Соответствует Мастеру ответов Microsoft Office. Все приложения семейства Microsoft Office имеют один Мастер ответов, поэтому все изменения этого объекта немедленно отразятся на активном приложении
DocumentProperty Семейство Содержит объекты DocumentProperty, каждый из которых представляет собой набор встроенных или определенных пользователем характеристик (свойств) документа-контейнера
HTMLProject Новый объект Представляет собой корень дерева проекта Web-страницы, отображаемого в окне просмотра проекта Project Explorer редактора сценариев Microsoft Script Editor. Этот объект содержит семейство HTMLProjectitems объектов HTMLProjectltem, ссылающихся на элементы иерархической структуры проекта. С помощью этого объекта можно управлять проектом Web-страницы
Script Семейство Содержит объекты Script, соответствующие сценариям, определенным в документе Word, электронной таблице Excel или слайде PowerPoint. С помощью этого объекта можно управлять сценариями документа, например создавать новые сценарии
WebPageFont Семейство Содержит набор объектов WebPageFont, каждый из которых соответствует одному из поддерживаемых национальных стандартов и определяет масштабируемый шрифт и его размер (кегль) и моноширинный шрифт и его размер, которые используются по умолчанию при сохранении документа в формате Web-страницы

COMAddln

Семейство

Содержит объекты COMAddln, соответствующие надстройкам сом (соответствующих спецификации компонентной модели объектов), зарегистрированным в реестре Windows

<
В программе 21. 2 мы рассмотрим объекты Assistant и Balloon, использование которых улучшает взаимосвязь пользователя с приложением. Сначала мы узнали имя текущего Помощника, после чего, воспользовавшись методом объекта Assistant, создали новое окно и вывели в него полученную информацию.

Программа 21.2. Использование объектов Assistant и Balloon

Sub ShowAssistant()

blnName = Application.Assistant.Name

Dim bin As Balloon

Set bin = Application.Assistant.NewBalloon

With bin

.Heading = "Привет!"

.Icon = msoIconTip

.Text = "Меня зовут " + blnName + "."

.Show End With End Sub


Объектная модель Outlook


Итак, после описания языка и работы со средой вы полностью готовы к полноценному программированию на Visual Basic for Application. Одной из важнейших характеристик системы программирования, определяющих ее удобство, является наличие уже готовых библиотек и компонент. В данных библиотеках описаны классы, полезные для решения стандартных задач, встречающихся в соответствующей сфере программирования. Классы Microsoft Office XP являются "золотым фондом" VBA, поскольку именно использование объектов этих классов делает VBA недосягаемым в области офисного программирования.

В этой главе мы описываем только поверхностно объектную модель Outlook 2002 и стандартные классы VBA и Office и не претендуем на подробное, исчерпывающее описание каждого объекта, свойства или метода, на это есть справочная система. Мы просто хотим показать работу с моделью и иерархией "в целом", что достаточно трудно сделать, руководствуясь только справочной информацией.

Далее в этой главе постоянно используется термин объектная модель (object model). Под этим термином подразумевается совокупность взаимосвязанных объектов, которые объединяет нечто общее, например назначение, область применения, принадлежность одной иерархии классов. Рассматривая объектную модель, мы будем приводить небольшие примеры использования ее классов в Outlook, что, надеемся, будет способствовать лучшему пониманию и усвоению излагаемого материала. Но прежде всего несколько общих положений.


Объектная модель Microsoft Outlook реализована в виде набора объектов, собранных в библиотеке Outlook.



Объектная модель VBA


Таблица 21.1. Описание объектов VBA

Объект

Тип

Описание

Collection

Объект из биб-

Упорядоченная совокупность объектов, с


лиотеки VBA

которой можно обращаться как с единым объектом

Debug

Объект

Позволяет выводить текущую информа-



цию в окно отладки непосредственно во



время выполнения кода на VBA

Dictionary

Объект из биб-

Объект, представляющий пару — ключ и


лиотеки Scripting

элемент. Является аналогом ассоциа-



тивной памяти

Drives

Семейство из

Содержит объекты Drive, предоставляю-


библиотеки

щие информацию (только для чтения) обо


Scripting

всех доступных дисках. Является свойст-



вом объекта FileSystemObject

Drive

Объект- из биб-

Предоставляет доступ к свойствам кон-


лиотеки Scripting

кретного локального или сетевого диска

Err

Объект из биб-

Предназначен для обработки ошибок


лиотеки VBA

Automation и ошибок модулей VBA во



время выполнения кода на VBA

Files

Семейство из

Содержит объекты класса File и пред-


библиотеки

ставляет совокупность всех файлов в


Scripting

данной папке. Является свойством объ-



екта FileSystemObject

File

Объект из биб-

Предоставляет доступ ко всем свойст-


лиотеки Scripting

вам файла на диске

FileSystemObject

Объект из биб-

Предоставляет доступ к файловой сис-


лиотеки Scripting

теме компьютера

Folders

Семейство из

Содержит объекты Folder и представ-


библиотеки

ляет совокупность всех папок внутри


Scripting

данной папки. Является свойством объекта Folder (свойство называется



SubFolders)

Folder

Объект из биб-

Предоставляет доступ ко всем свойст-


лиотеки Scripting

вам папки на диске

<
Объект



Тип



Описание



Texts tr earn

Объект из библиотеки Scripting

Обеспечивает последовательный доступ к текстовому файлу

UserForms

Семейство из библиотеки VBA

Содержит объекты Object, соответствующие объектам UserForm, и пред-





ставляет совокупность пользовательских форм, загруженных в данный момент в приложение. Это семейство является свойством объекта Global из библиотеки VBA

UserForm

Абстрактный объект VBA

Object

Представляет форму, являющуюся частью пользовательского интерфейса приложения. Характеристики этого объекта определяются пользователем

Продемонстрируем небольшой пример работы с рядом объектов VBA. Мы хотим вывести в окно Immediate посредством метода Print Объекта Debug

литеры, соответствующие логическим дискам компьютера. Для этого мы указали ссылку на объект, являющийся семейством Drives, после чего, воспользовавшись циклом For Each . .. Next, вывели требуемые значения посредством свойства DriveLetter объекта Drive.

Замечание

Цикл For Each . . . Next очень полезен при работе с семействами, поскольку не требуется знать количество объектов семейства и можно устраивать цикл по всей структуре. В противном случае необходимо было бы воспользоваться свойством count.

Программа 21.1. Использование объектов VBA

Sub ShowDriveList()

Set fsystem = CreateObject("Scripting.FileSystemObject")

Set systemDrives = fsystem.Drives

For Each d In systemDrives

Debug.Print d.DriveLetter

Next End Sub


Объекты MAPIFolderv и Mailltem


Поскольку в примерах этой главы и следующей используются свойства и методы объектов MAPIFolder и Mailltem, мы сочли необходимым привести их краткое описание.

Объект MAPiFoider, как было сказано выше, представляет папку Outlook. Объект MAPiFoider может содержать другие MApiFoider-объекты. В этом случае вы можете управлять доступом к вложенным папкам посредством комбинации Folder (индекс), где индекс возвращает объект MAPiFoider.

Outlook имеет специальный набор папок, которые поддерживают заданную по умолчанию функциональность Outlook. Для доступа к этим папкам следует Использовать метод GetDefaultFolder(индекс), где индекс — одна ИЗ констант olDefauitFoiders, например olFoiderinbox возвращает папку Входящие.

В табл. 21.7 приведены основные свойства объекта MAPiFoider, а в табл. 21.8 — его методы.

Таблица 21.7. Свойства объекта MAPiFolder

Свойство

Описание

Items

Возвращает семейство элементов Outlook в папке

Description Возвращает или устанавливает описание папки
DefaultMessageClass Возвращает заданный по умолчанию класс сообщения для элементов в папке

Таблица 21.8. Методы объекта MAPiFolder

Метод

Назначение

СоруТо

Копирует текущую папку (полностью) в указанную папку. Возвращает MAPiFolder объект, представляющий новую копию

Delete Удаляет объект из семейства папок
Display Отображает новый объект Explorer для папки
MoveTo Перемещает папку в указанную папку

Несколько слов об объекте Mailitem. Он представляет почтовое сообщение в папке Входящие (Inbox). Мы рассмотрим только необходимые для примера свойства и методы этого-объекта.

Свойство Messageciass возвращает или устанавливает класс сообщения для элемента Outlook. Свойство Messageciass связывает элемент с формой, на которой он основан. Когда элемент выбран, Outlook использует класс сообщения, чтобы поместить соответствующую форму и установить свойства элемента.

Свойство RecievedTime возвращает дату и время получения сообщения. Метод Display отображает новый объект inspector для выбранного элемента.


В программе 21. 3 открываются все почтовые сообщения, поступившие за последние сутки.

Программа 21.3. Открытие почтовых сообщений

Sub openLastMail () Dim oa As Outlook.Application

Dim ns As NameSpace ; Dim fl As MAPiFolder Dim ob As Object Dim it As Mailitem

Dim i As integer

Set oa = CreateObject("OutLook.Application") Set ns = oa.GetNamespace("MAPI") Set fl = ns.GetDefaultFolder(olFolderlnbox) For i = 1 To f1.Items.Count Set ob = fl.Items(i) On Error GoTo nextitem If ob.MessageClass = "IPM.Note" Then Set it = ob If it.ReceivedTime > Date - 1 Then

it.Display (False) End If End If nextitem:

Next i End Sub

Замечание

Для семейств Outlook нельзя воспользоваться оператором For Each Next, поэтому применяется цикл For . . . Count.


Объекты приложения Outlook


В табл. 21.3 приведено описание основных объектов из объектной модели Outlook.

Таблица 21.3. Основные объекты Outlook

Объект

Тип

Описание

Application Обьект Ссылается на активное приложение Microsoft Outlook. Используется для управления приложением

NameSpace

Объект

Объект представляет собой абстрактный корневой объект для любого источника данных

AddressLists (AddressLists)

Семейство и объект

Семейство объектов, представляющих адресные книги

Folders (MAPIFolders)

Семейство и объект

Семейство MAPIFolders объектов, которое представляет любую из доступных папок в их подмножестве на одном уровне дерева папок

Items (Item)

Объект

MAPIFolder

Представляет стандартный элемент Outlook, расположенный в данной папке

Links (Link)

Объект Item

Представляет объект item, который связан с другим объектом item

User Proper ties (UserProperty)

Объект Item

Данное семейство хранит информацию о нестандартных свойствах элемента Outlook, созданных пользователем

FormDescription

Объект Item

Этот объект хранит все стандартные свойства элемента Outlook

Actions (Action)

Объект Item

В этом семействе хранится информация об ассоциированных с данным элементом Outlook командах. Обратите внимание на то, что команды можно вывести, раскрыв в режиме конструктора вкладку Команды

Attachments (Attachment)

Объект Item

Семейство представляет все вложения в элементе

Recepients (Recepint)

Объект Item

Это семейство представляет информацию о получателях элемента Outlook

ReccurencePattern

Объект Item

Данный объект задает шаблон повторения для встреч и задач

Proper ty Pages ( Proper tyPage )

Семейство и объект

Семейство объектов PropertyPage, которые содержат специальные вкладки со свойствами, добавленные к диалоговому окну Параметры в Outlook

LanguageSet tings

Объект

Предоставляет информацию о языковых настройках приложения

AnswerWizard

Объект

Соответствует мастеру ответов Microsoft Office. Все приложения Microsoft Office имеют ровно один мастер ответов, поэтому все изменения этого объекта отразятся на активном приложении

<


Объект



Тип



Описание



Assistant



Объект



Ссылается на объект, представляющий активного в данный момент Помощника Office



Search



Объект



Данный объект представляет как простой











поиск, так и расширенный поиск



Reminders



Семейство



Представляет окно Оповещения для всех



(Reminder)



и объект



напоминаний о встречах, задачах и т. д.



Explorers



Семейство



Семейство объектов Explorer — набор



(Explorer)



и объект



всех окон, в которых отображается содер-











жимое папки



Selection



Объект



Семейство всех отображаемых элементов в



(Items)



Explorer



окне просмотра информации



CommandBars



Объект



Представляет обычные и контекстные меню,



(CommandBar)



Explorer



а также панели инструментов объекта







И Inspector



Explorer И Inspector



Panes (Pane)



Объект



Семейство панелей (окон) Outlook для данного







Explorer



объекта Explorer



Inspectors



Семейство



Семейство объектов Inspector — набор



(Inspector)



и объект



всех окон, в которых 'отображаются элемен-











ты Outlook. Элемент (item) — это основной











модуль хранения данных в Outlook (подобно











файлу в других программах). В число эле-











ментов входят почтовые сообщения, встречи, контакты, задачи и т. д. (рис. 21.4)



WordEditor и



Объекты



Представляют объекты, посредством которых



HTMLEditor







выбираются редакторы для объекта











Inspector



Pages (Page)



Объект



Каждый объект inspector связан со своим







Inspector



семейством Pages, в которое входят все











обновленные пользователем страницы формы.











Если в форму для элемента не вноси-











лись изменения, то семейство Pages явля-











ется пустым



Item



Объект



Представляет стандартный элемент Outlook,







Inspector



расположенный в данной папке



MAPIFolder



Объект



Представляет папку Outlook

<


В табл. 21.4—21. 6 представлено описание основных свойств, методов и событий объекта Application.



Рис. 21.1. Объект Inspector (форма элемента)

Таблица 21.4. Основные свойства объекта Application



Свойство





Описание





Session Class



Возвращает объект Namespace для текущего сеанса. Сеанс (session) — это период времени, в течение которого пользователь работает с Outlook

Parent Возвращает константу из перечисления QlObjectClass для указанного объекта. Это целочисленное значение, идентифицирующее класс объекта
Version Возвращает родительский объект для указанного объекта Возвращает или задает номер версии
Таблица 21.5. Основные методы объекта Application



Метод





Назначение





ActiveExplorer



Возвращает головной объект Explorer

Active Inspect or Возвращает головной объект Inspector
ActiveWindow Возвращает объект, представляющий главное окно
Createltem Создает новый элемент Outlook и возвращает его приложения


Метод



Назначение



GetName Space



Возвращает объект NameSpace указанного типа

Quit Закрывает приложение
Таблица 21.6. События объекта Application



Событие



Описание



AdvancedSearchComplete



Происходит, когда Расширенный поиск заканчивает свою работу



ItemSend



Происходит, когда элемент посылается либо посредством Inspector, либо посредством метода Send



MapiLogonComplete



Происходит, когда пользователь входит в систему



NewMail





Происходит, когда одно или несколько почтовых сообщений приходит в папку Входящие



OptionPagesAdd



Происходит, когда открывается диалоговое окно Параметры



Reminder



Происходит непосредственно перед оповещением о встрече, задаче или собрании



Startup



Происходит сразу после загрузки приложения Outlook



Quit



Происходит, когда Outlook закрывается


Общие положения


Любая модель, определенная в VBA, состоит из классов, каждый из которых представляет собой отдельный объект или семейство объектов. Объектов в Office, да и в Outlook достаточно много, но во всех приложениях участвует объект Application, представляющий само приложение. Application — это корневой класс Outlook, в который вложены все остштьные объекты, именно этот первый уровень вложенности мы и будем рассматривать.

Глядя на схему объектной модели, можно определить, какие объекты описывают работу приложения, как они связаны между собой и как составить ссылку для доступа к конкретному объекту. Как вы помните, VBA наряду с наследованием поддерживает встраивание объектов, таким образом, чтобы составить ссылку на объект, нужно проследить путь в иерархии объектов, начиная с объекта Application на первом уровне иерархии до целевого объекта, и записать последовательность имен, находящихся на пути объектов или семейств, отделяя их друг от друга точкой. При этом для семейств, кроме имени, необходимо указать в скобках индекс или имя элемента, т. е. задать конкретный объект в семействе. Например, для указания ссылки на объект, находящийся на третьей ступени иерархии приложения, следует использовать такую запись:

Application.Assistant.Sounds

Доступ к отдельным элементам некоторых семейств можно получить, не указывая индекс или имя объекта. Например, доступ к активному представлению Outlook, который в общем случае вызывается через указатель Application. Explorers, осуществляется с помощью свойства ActiveExpiorer объекта Application. Таким образом, чтобы отобразить панель папок в текущем представлении, следует использовать такую запись:

Application.ActiveExpiorer.ShowPane(olFolderList, True)

Завершая общие положения, нельзя не сказать о справочной информации по объектной модели Outlook, верном спутнике при программировании на VBA. Для отображения иерархии классов воспользуйтесь примером, приведенным ниже.

Пример 21.1. Получение справки об объектной модели Outlook 2002

> Справка > Справка по Microsoft Outlook Содержание


Дополнительные средства настройки

Microsoft Outlook Visual Basic Reference Microsoft Outlook Objects

Также не забывайте об удобном средстве просмотра объектов Object Browser, которое заметно упростит понимание структуры объектной модели. И наконец, в случае серьезных затруднений советуем обратиться за справкой к MSDN (Microsoft Developer Networks), справочной системе, содержащей гигабайты информации, примеров, исходного кода и т. д. Помимо всего прочего, в Интернете можно найти огромное множество как российских, так и зарубежных Web-сайтов, посвященных разработке приложений в Microsoft Office.


Общие сведения


В этом разделе мы приведем ряд сведений общего характера, которые не следует пропускать. Пример в самом начале раздела поможет в дальнейшем по аналогии создавать простые программы, тестирующие приведенные листинги. Условные обозначения помогут разобраться в использовании синтаксиса языковых конструкций. Необходимость описания алфавита и лексики не требует комментариев.

Но, прежде всего, давайте попытаемся привести первое формальное определение VBA. VBA — это визуальный объектно-ориентированный язык программирования высокого уровня.

Язык программирования высокого уровня — это язык программирования, в который введены элементы, допускающие описание программы в наглядном, легко воспринимаемом человеком виде, упрощающие и автоматизирующие процесс программирования. Конструкции языка программирования высокого уровня отражают естественные для человека понятия, а не архитектуру и не систему команд компьютера. Поэтому программа, составленная на языке программирования высокого уровня, сначала особым образом обрабатывается компьютером (транслируется или интерпретируется), а затем выполняется.

В визуальном языке программирования взаимодействие пользователя с системой программирования при составлении и отладке программ реализуется диалоговыми средствами графического интерфейса пользователя (см. раздел 20.6 "Редактор Visaиl Basic for Application").

Объектно-ориентированное программирование (ООП) — наиболее популярная в настоящее время методология программирования. Центральной идеей ООП является инкапсуляция, т. е. структурирование программы на модули особого вида, объединяющие данные и процедуры их обработки, причем внутренние данные модуля могут быть обработаны только предусмотренными для этого процедурами (см. главу "Объектная модель Outlook 2002").

Если после данной расшифровки легче не стало, не волнуйтесь и не откладывайте книгу до лучших времен. В процессе изложения многие термины невозможно определять без ссылок вперед, но и оставлять термин или понятие без какого-либо внимания тоже считается некорректным.
Таким образом, мы сейчас и в дальнейшем будем прибегать к следующему методу изложения: краткое, по возможности формальное определение, отражающее суть предмета, но без особых комментариев и с обязательной ссылкой вперед, где подробно, в доступной форме будет объяснен и термин, и сопутствующий ему материал.

Итак, после исторического экскурса и ряда формальных определений можно было бы перейти к описанию алфавита и лексики языка, но мы решили сделать паузу и привести пример. Для дальнейшего изучения мы сочли необходимым привести пример разработки простейшей программы, начиная с запуска редактора VBE, создания модуля, написания и выполнения кода. Без объяснения конструкций и интерфейса, но с многочисленными ссылками вперед. Это позволит вам на первых порах при необходимости и желании проверить приведенные ниже примеры в действии. Цель данного раздела — создать программу по выводу диалогового окна с надписью "Здравствуй, мир!" Этот пример неслучаен — с написания подобных элементарных программ начинаются многие учебники по языкам программирования, и мы решили не нарушать традицию.

Запустите Microsoft Outlook 2002. Выберите команду > сервис> макрос > Редактор visual Basic или просто нажмите комбинацию клавиш <Alt>+<Fl 1> (Запуск редактора).

В меню редактора выберите команду > insert> Module (Вставка модуля) и введите следующий код:

Программа 20.1. Вывод диалогового окна с надписью "Здравствуй, мир!"

Sub hello <Enter>

<Tab> MsgBox("Здравствуй, мир!")

Замечание

В коде программы есть еще одна строка (End Sub), но она появляется автоматически, вводить ее не нужно.

Программа готова! Осталось ее запустить, нажав кнопку Run Sub/User Form на панели инструментов Стандартная или клавишу <F5> (Запуск строки).

Результат и окно редактора VBA продемонстрированы на рис. 20.1.

Таким образом, для тестирования приведенных ниже примеров использования синтаксических конструкций вам будет достаточно проделать аналогичные операции, только вместо функции MsgBox необходимо будет вставлять код той или иной конструкции, непосредственно беря их из листингов в книге.


При возникновении затруднений при работе с редактором VBA вы всегда можете досрочно обратиться к разделу 20.6 "Редактор Visual Basic for Application". Впрочем, мы надеемся, что данная возможность не будет востребована, поскольку примеры очень просты и, в принципе, не требуют тестирования на компьютере.



Рис. 20.1. Окно редактора и диалоговое окно с надписью "Здравствуй, мир!"

После рассмотрения примера вернемся к описанию языка. Для этого введем условные обозначения для описания языка.

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

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

Синтаксис каждой конструкции объясняется на схематическом примере, с использованием условных обозначений, приведенных в табл. 20.1.

Таблица 20.1. Условные обозначения



Обозначение



Смысл



Прямой шрифт



Данная конструкция остается без изменений (например, ключевые







слова)



Курсив



Конструкция должна быть заменена конкретным текстом



<выражение>



Название используемых конструкций



[Счетчик]



Конструкция не обязательна и может быть опущена







Конструкция аналогична предыдущей (например, грубо говоря и т. д.)



{А, ..., Z}



Множество возможных значений



А|В



А или В

Ключевые слова даются без переводов и пояснений. Мы убеждены, что это единственно правильный метод, т.


к. ключевые слова суть иероглифы, смысл которых задается описанием языка программирования, а отнюдь не тем значением, которое эти слова имеют в естественном языке.

Семантика конструкций объясняется на микропримерах, которые представляют собой небольшие фрагменты кода без глобального контекста. В принципе, они не требуют выполнения на компьютере и предназначены только для чтения, но при необходимости вы можете ввести код по аналогии с вышеприведенным примером "Здравствуй, мир!" и проанализировать работу конструкции с помощью компьютера.

Для обозначения общих понятий информатики мы используем термины, которые уже устоялись в отечественной литературе по программированию, даже если наша терминология расходится с терминологией, использованной при локализации приложений.

Итак, все готово к легкому и непринужденному изучению языка VBA. Не задерживаясь ни на минуту и следуя вышеизложенному плану, приступаем к изучению алфавита и лексики языка.

Как и естественный язык, так и язык программирования имеет некоторую лексическую структуру, которую мы сейчас и опишем. Алфавит языка программирования — это набор символов (разрешенный к использованию и воспринимаемый компилятором), с помощью которого могут быть образованы выражения и операторы данного языка. Под символами мы подразумеваем все, что можно ввести с клавиатуры (буква (А), цифра (7), знак (© — <Alt> + <0169>) и т. д.).

Далее перечислены лексемы и символы, их составляющие.

1. Число

• Цифры от 0 до 9

• Символ точка (.) и буква Е (или е)

2. Имя (идентификатор)

• Латинские строчные и прописные буквы (A— Z, a— z),

• Буквы кириллицы, также строчные и прописные (А— Я, а — я)

• Арабские цифры (0— 9)

• Символ подчеркивания _

• Символы типа @ # & $ % !

3. Строка

• Все символы алфавита

4. Разделители

• Символ пробела

• Символ продолжения строки (_)

• Символы табуляции

• Символ новой строки

5. Специальные символы, служащие для построения различных конструкций:

• <, >, =

Итак, после описания алфавита приведем правила образования слов в VBA.


Всего существует четыре класса слов: имена, ключевые слова, числа и строки. при этом слова отделяются друг от друга разделителями и/или специальными символами, как правило, это пробелы или символы табуляции.

Имя (идентификатор) — это последовательность символов, указанных во втором пункте, длиной не более 255 знаков; первый символ данной последовательности обязан быть буквой; последовательность должна быть отлична от ключевых слов; в конце может стоять символ типа переменной; буквы в верхнем и нижнем регистре не различаются.

Замечание

Дело в том, что за регистр в VBA отвечает встроенный текстовый редактор VBE (Visual Basic Editor), который автоматически меняет регистр при повторном вводе идентификатора. То есть, если при объявлении используется имя fileName, то как бы его потом не вводили filename или FiLEnaME, редактор приведет его к первоначальному виду.

Для построения римских цифр используется латинский алфавит, например XXI (21) — это прописные х, х и i.

Вы можете составлять имена, используя все богатство воображения, но есть ряд правил хорошего тона, которые служат для повышения удобочитаемости программ. Более того, они позволят избежать стандартных ошибок.

Во-первых, имена должны быть не слишком длинными, но отражающими характер их использования в программе. Например, если вы хотите ввести переменную, обозначающую количество проданных издательством "Чародейство и Волшебство" книг, то рекомендуется следующий вариант имени: numbBookSaie. Данное правило сыграет для вас огромную роль при написании больших программ, когда их чтение через год будет таким же легким, как будто вы писали их код вчера.

Во-вторых, рекомендуется начинать имена со строчной, а не с прописной буквы. Поскольку при вводе ключевых слов VBA и имен стандартных объектов первая буква автоматически преобразуется в прописную. Таким образом вы будете избавлены от риска нечаянно использовать запрещенное имя переменной.

В-третьих, при начальном определении имени или процедуры, при обозначении какого-то ключевого момента в программе следует использовать комментарии.


Комментарии строятся следующим образом: после символа (') следует текст комментария. Например:

Программа 20.2. Комментарий

Sub numbBookSaie () 'Процедура подсчета количества проданных книг

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

От описания идентификаторов перейдем к другим лексемам языка — строкам, числам и ключевым словам.

Строка — последовательность символов, заключенная в двойные кавычки ("..."), при этом под символами подразумеваются все вышеуказанные.

Число — это лексема, служащая для записи числовых значений (включая даты). Для записи десятичных чисел используются цифры и точка (123.456), также можно представлять число с помощью экспоненциального представления и символа Е или е. Этот символ указывает на то, что истинное число равно числу, стоящему перед Е (оно называется мантиссой), умноженному на 10 в степени числа, стоящего после Е (оно называется порядком). Например, лексема 1.234Е+6 обозначает число 1234000.

Ключевое слово — это специальная лексема, смысл которой зафиксирован правилами языка и по которой транслятор (и человек) распознает основные языковые конструкции. Ключевыми словами VBA, например, являются True, For, String И Т. Д.


Операторы


Любая программа представляет собой последовательность операторов. Мы уже рассматривали те операторы, которые предназначены для объявления переменных и определения типов. В этом разделе мы расскажем об операторах для выполнения действий с данными и для управления порядком выполнения других операторов. Существует три основных типа операторов: операторы присваивания, условные операторы и операторы цикла. Рассмотрим их по порядку.

Операторы присваивания необходимы для изменения значения переменных. В VBA существует четыре вида операторов присваивания:

Let (прямое присваивание);

LSet (левое присваивание);

RSet (правое присваивание);

set (объектное присваивание).

С оператором прямого присваивания мы уже встречались (=), правда, в несколько укороченном виде.

[Let] имяПеременной = <выражение>

Ключевое слово Let является наследием предшествующих версий языка Basic, его употребление ничего не добавляет и не убавляет. Подобные атавизмы — не редкость в любом языке программирования, они необходимы для совместимости разных версий программного продукта.

С помощью оператора присваивания происходит обычное присваивание значения выражения, стоящего справа от знака =, переменной, имя которой стоит слева от знака =. Причем тип присваиваемого значения должен соответствовать типу переменной. Бессмысленной будет следующая конструкция:

Dim Temp As Integer Temp = "Строка"

Встретив подобное присваивание, компилятор выдаст сообщение об ошибке. Но есть и ряд исключений. В следующей программе сначала рассматривается присваивание переменным встроенных типов стандартных значений. Затем следует объявление трех записей типа Person, после чего идет присваивание значений первым двум записям, но через прямое обращение к полям записей. В последующем же присваивании происходит одновременное присваивание значений всех полей записи peopie2 соответствующим полям записи people3.

Программа 20.7. Присваивание

Sub LetEgual()

Dim age As Integer, str$

Dim peoplel As Person, people2 As Person, peoples As Person


age = 32

str = "Жизнь прекрасна"

peoplel.name = "Александр" people2.name = peoplel.name + "a" Msgbox(people2.name) peoples = people2 Msgbox(peopleS.name) End Sub

Следующий оператор присваивания, который мы рассмотрим в данном разделе, — LSet. Он служит для специфического присваивания строк с одновременным выравниванием слева, а также для присваивания значения записи одного типа записи другого типа.

LSet имяСтроковойПвременной = СтроковоеВыражение LSet имяПеременной! = имяПеременной2

В первом случае результатом присваивания является строка той же длины, что и у значения имяСтроковойпеременной. Если значение выражения СтроковоеВыражение длиннее, то лишние символы справа удаляются, если короче — заполняются пробелами справа.

Во втором случае присваивание аналогично вышеописанному случаю с использованием оператора Let, но только здесь не обязательно, чтобы типы полей совпадали. Конечно, подобное присваивание чревато сообщениями компилятора о несоответствии типов. Мы советуем использовать данную конструкцию с очень большим вниманием.

В программе 20.8 инициализированы две строковых переменных, после чего происходит левое присваивание и вывод значения переменной str1 ("<-Влево").

Программа 20.8. Левое присваивание

Sub LsetEqual()

Dim Strl As String, Str2 As String

Strl = "0123456789"

Str2 = "<-Влево"

Lset Strl = Str2

Msgbox(Strl)

End Sub

Оператор RSet аналогичен оператору LSet, только в данном случае выравнивание происходит справа. Помимо этого, оператор RSet нельзя использовать для присваивания записей.

Последний оператор присваивания — объектное присваивание set. К сожалению, мы еще не рассказывали об объектах и описание этого оператора сейчас будет бессмысленным, но придет время, и о нем будет рассказано (см. раздел 20.5 "Классы и объекты").

После операторов присваивания перейдем к рассмотрению операторов ветвления. Как и во многих языках программирования, в VBA имеются различные управляющие конструкции, позволяющие изменять порядок выполнения операторов программы.


При отсутствии управляющих конструкций операторы программы выполняются последовательно, с первого до последнего. В некоторых простых случаях этого бывает достаточно, но обычно все-таки требуется изменить порядок выполнения операторов при выполнении определенных условий либо пропуская выполнение некоторых операторов, либо, наоборот, многократно повторяя их. Оказывается, для реализации любых алгоритмов достаточно иметь только два вида управляющих конструкций — ветвления и циклы. Первым из рассматриваемых нами операторов ветвления является стандартный условный оператор ветвления if. . .Then.. .Else. Его использование позволяет проверить некоторое условие и в зависимости от его истинности выполнить ту или иную группу операторов.

Замечание

Оператор If. . .Then. . .Else называют также условным оператором.

Для данного оператора есть два варианта синтаксиса — в одну строку и в несколько:

If условие Then [блокОлераторов1] [Else блокОператоров2] ИЛИ

If условие1 Then

[блокОператоров 1] [ElseIf условием Then

[ блокОпера торовN] ... [Else

[блокОператоров_Е1зе]] End If

Но обо всем по порядку. После ключевого слова if стоит условие. В качестве условия можно использовать логическое выражение, возвращающее значение True или False. Также можно использовать арифметическое выражение, в этом случае нулевое его значение эквивалентно False, ненулевое — True. Если условие возвращает True, то выполняется блокоператоровJ, если

False — блокОператоров2, представляющий собой последовательность разделенных двоеточием операторов. Причем необходимо наличие хотя бы одного из блоков операторов.

Такова семантика первой формы записи (в одну строку), являющаяся частным случаем второй. Вторая же форма записи представляет развернутую цепочку ветвления, когда приходится делать выбор одного альтернативного действия из целой группы на основе проверки нескольких различных условий. В подобном случае также необходимо наличие хотя бы одного из блоков операторов.

Вторая схема действует по следующему принципу.


Проверяется условие1. Если оно истинно, то выполняется блокоператоров! и осуществляется переход к оператору, стоящему за ключевым словом End if. Если же оно ложно, то проверяется условие.? и т. д. Если проверка дошла до последнего оператора Eiseif и условием тоже оказывается ложным (то есть все вышестоящие условия ложны ), выполняется блокОператоров_Е1зе.

В программе 20.9 инициализируются три переменные а, ь и с. Далее показывается использование условного оператора в виде одной строки с использованием разделителя операторов — двоеточия. Поскольку проверяемое условие истинно, выполняются присваивание (с = c+1) и вывод (с = и).

В следующей конструкции проверяется условие (с > 20), т. к. условие ложно, то оператор присваивания (с = c+l) не выполняется. Далее проверяется условие (с = -а + b+ 1) — оно истинно, следовательно, выполняется вывод (с = ll). В противном случае вывелось бы "Не может быть" (что исключено).

Программа 20.9. Использование оператора if. . .Then. . .Else !

Sub branch()

Dim a, b, с

a = -10

b= 0

с = 10

If c>a Then c=c+l : MsgBox(c) Else a=a-l : MsgBox(a)

If с > 20 Then

c=c+1

ElseIf с = -a + b + 1 Then

MsgBox (c) Else

MsgBox ("He может быть")

End If

End Sub

Вышерассмотренные цепочки операторов if. . .Then.. .Eiseif обладают большой гибкостью и позволяют решить все проблемы, однако если выбор одной из нескольких возможностей все время основан на различных значениях одного и того же выражения, гораздо удобнее использовать предназна ченный для этого оператор выбора select case, имеющий следующий синтаксис:

Select Case выражение [ Case списокЗначенийN

[блокОператоровN]] ... [ Case Else

[блокОператоров_Е1зе]] End Select

Проверяемое выражение вычисляется в начале работы оператора select case. Это выражение может возвращать значение любого типа — например логическое, числовое или строковое. При выполнении оператора Select case значение проверяемого выражения вычисляется один раз и запоминается.

Далее идет список альтернатив, начинающихся ключевым словом case.


В каждой альтернативе указан список значений, представляющий собой несколько возможных значений, разделенных запятой. При выполнении оператора select Case значение сравнивается со списками значений альтернатив. Элементы списка значений могут иметь одну из следующих форм:

Значение — в этом случае проверяется, совпадает ли значение проверяемого выражения с указанным значением;

Значение1 то Значение2 — проверяется, находится ли значение проверяемого выражения в диапазоне указанных значений;

Is логическаяОперация значение — в данном случае проверяется, удовлетворяет ли значение проверяемого выражения указанному логическому условию.

Вся конструкция работает следующим образом. Если хотя бы один из элементов списка значений соответствует проверяемому выражению, то выполняется соответствующий блок операторов и на этом выполнение оператора Select Case заканчивается. Если же ни один из элементов всех списков альтернатив не соответствует значению проверяемого выражения, выполняется блокОператоров_Е1sе (если, конечно, присутствует ключевое слово Case Else).

В следующем примере при помощи функции inputBox переменной t присваивается некое значение, после чего посредством оператора select Case проверяется положительность значения переменной. Заметьте, что предусмотрен вариант, когда пользователь введет не число 3 .

Программа 20.10. Использование оператора Select Case

Sub branchLinef) Dim t As Integer

Использование оператора GoTo будет рассмотрено чуть ниже.

labelInput: t = InputBox{"Введите число") If (Not (IsNumeric(t))) Then

Call MsgBox("Введено не число", vbCritical)

GoTo labellnput End If

Select Case t Case 0

Msgbox ("Введен 0") Case 1 To 100

MsgBox("Введено положительное число") Case -100 To -1

MsgBox("Введено отрицательное число") Case Is < -100 , Is > 100

MsgBox("Число больше 100 или меньше -100") Case Else

MsgBox("He может быть") End Select End Sub

Подобная конструкция, как упоминалось, возможна и для строковых значений, в таком случае используется лексикографическое упорядочивание.



Помимо условных операторов, в VBA существует оператор безусловного перехода, который также меняет порядок выполнения операторов в программе (безусловно):

GoTo имяМетки

После ключевого слова идет имя метки. Метка — это идентификатор, приписанный оператору программы и используемый в других частях программы для обращения к этому оператору. Метка может быть определена как до, так и после ключевого оператора GOTO, причем она должна отделятся от помеченного ею оператора двоеточием. В примере, приведенном выше, в случае введения нечислового значения, выполняется безусловный переход и пользователю заново предлагается ввести число.

Совет

Применение оператора безусловного перехода нежелательно, поскольку присутствие этого оператора в программе нарушает ее структурную целостность и наглядность. Такую программу трудно читать, отлаживать и модифицировать. Ниже будут рассмотрены операторы циклов, попробуйте изменить данный пример, организовав цикл проверки вместо безусловного перехода.

От операторов ветвления перейдем к рассмотрению операторов цикла. Если бы при выполнении программы каждый оператор выполнялся только один раз, программирование не имело бы особого смысла. Действительно, выполнить вручную какую-нибудь арифметическую операцию наД данными ненамного труднее, чем написать соответствующий оператор присваивания в программе. Весь смысл программирования состоит в том, чтобы поручить компьютеру проведение многочисленных расчетов, записав это поручение в компактной форме. Для решения таких задач существуют операторы цикла. Циклы позволяют многократно выполнять отдельный оператор или группу операторов.

Операторы цикла VBA делятся на три группы:

циклы со счетчиком (For. . .Next);

циклы с условием (Dо. . .Loop);

Циклы по структуре данных (For Each. . .Next).

Первый из рассматриваемых нами операторов цикла — For.. .Next. Данный оператор позволяет выполнять группу операторов (которая называется телом цикла) заранее определенное количество раз, при этом параметр цикла последовательно принимает ряд значений, определенных пользователем в заголовке цикла.



For счетчик = начало То конец [Step шаг]

[блокОператоров1] [Exit For]

[блокОператоров2] Next [счетчик]

Счетчик — это и есть тот числовой параметр цикла, который должен принимать ряд значений от значения начало до значения конец. Причем этот ряд может образовывать как возрастающую, так и убывающую арифметическую прогрессию. Необязательный параметр шаг, при необходимости мог бы указывать, с каким шагом следует пробегать заданный ряд значений (по умолчанию он равен 1).

БлокОператоров! — это блок операторов, который будет выполнен, пока счетчик не пробежит ряд значений до конца. Прервать же данный пробег вправе только оператор Exit For, предназначенный для выхода из цикла, не дожидаясь его завершения и передачи управления оператору, следующему непосредственно за Next. Как правило, оператор используется в тех местах тела цикла, где требуется из него выйти по условию.

В конце цикла ставится заключительный оператор Next, после которого указывается счетчик цикла. Хотя данное указание необязательно, мы рекомендуем всегда его использовать, поскольку программа станет более понятной, особенно в случае большого количества вложенных циклов.

Итак, рассмотрим работу конструкции цикла со счетчиком в целом. Оператор For инициализирует переменную счетчик значением начало, после чего выполняется блокОпера торов 1 до тех пор, пока не встретится оператор Exit For (выход) или оператор Next (следующий). Далее оператор Next проверяет, не достигнуто ли значение конец, и если нет, то прибавляется значение шага к счетчику и процедура повторяется, если да — работа оператора цикла завершается.

В программе 20.11 мы рассмотрим три примера работы с циклом For...Next. В первом примере мы запрограммировали решение задачи о вычислении факториала числа 20 (20!=1*2*3**20), причем значение счетчика явно используется в вычислениях. После чего вывели итоговый результат (~2,432Е+18).

Во втором примере мы показываем, что помимо простых конструкций с циклами существуют более сложные — вложенные циклы. Характерным примером для вложенных циклов является инициализация матрицы (n x m).


Мы проинициализировали все элементы матрицы (6 х 5) единицей.

В последнем примере мы продемонстрируем работу оператора Exit For и счетчика с отрицательным шагом. Допустим, у нас есть проинициализирован-ный массив типа string. Необходимо найти элемент данного массива, равный строке "выход", причем проверка будет происходить с конца массива.

Программа 20.11. Использование оператора For. . .Next

Sub Factorial()

Dim factorial As Variant

factorial = 1

For i = 1 To 20

factorial = factorial * i Next

MsgBox(factorial) End Sub

Sub InitMatrix()

Dim matrix (5,4) As Integer

For i = 0 To 5

For j = 0 To 4

matrix(i, j) = 1

Next j

Next i End Sub

Sub VectorSearch

Dim Vector(7) As String

Инициализация

For i= 7 To 0 Step -1

If (Vector(i) = "Выход") Then

Exit For :

End If Next i End Sub

Теперь допустим, что вы не знаете заранее, сколько раз должно выполниться тело цикла, как в случае с оператором For.. .Next, но знаете условие, при котором цикл должен продолжать или прекращать свою работу. В таком случае и следует употреблять циклы с условием — DO ... Loop. Например, издательству поступают заявки от 25 магазинов на покупку определенного количества книги "Microsoft Office 2001 в целом", но количество книг ограничено (скажем, их всего 5000 экземпляров). Издательство, соответственно, удовлетворяет первые заявки, насколько может (то есть не более того, что есть сейчас на складе). Перед издательством встает задача — определить, заявки скольких первых магазинов оно удовлетворит? Перейдем к математической трактовке поставленной задачи. Заявки от магазинов образуют одномерный массив, элементы которого суть количества заказываемой книги. Таким образом, мы хотим узнать: сколько первых элементов этого массива можно взять так, чтобы их сумма значений была не больше 5000? В данном случае есть цикл и есть условие, но неизвестно, сколько именно раз потребуется выполнять суммирование для выявления необходимого количества элементов. Для решения подобных задач и применяется оператор цикла DO ...


Loop. Существует два вида циклов с условием: с предусловием и с постусловием. Соответственно, и цикл DO ... Loop имеет две синтаксические конструкции, суть различия которых — во времени проверки условия.

/ Предусловие /

Do [{While I Until} условие]

[ блокОператоров 1] [Exit Do]

[блокОператоров2] Loop

/ Постусловие /

Do

[блокОператоров 1] [Exit Do]

[блокОператоров2] Loop [{While | Unti1} условие]

Как упоминалось, различие этих двух конструкций состоит в том, что в первом случае условие будет проверяться до выполнения блока операторов (предусловие), а во втором — после (постусловие).

Теперь о проверке условий. Если в конструкции стоит ключевое слово while, то блок операторов будет выполняться, пока условие остается истинным, если же стоит until, блок операторов будет выполняться до тех пор, пока условие остается ложным. Вообще, исходя из синтаксиса, наличие условия не обязательно. Если его нет, то по умолчанию оно трактуется как False.

Необязательный оператор Exit DO аналогичен оператору Exit For в цикле For. . .Next. Он также прекращает выполнение цикла и передает управление на оператор, следующий непосредственно за Loop.

Давайте на приведенном выше примере рассмотрим работу цикла с условием. Наше условие выглядит так: "сумма > 5000", причем это условие выхода из нашего цикла, т. к. мы найдем искомое число элементов массива. Следовательно, сначала мы должны вычислить сумму (блокОператоров), а потом проверить, не больше ли она 5000 (until sumOfBooks > sooo). Помимо этого надо следить, чтобы мы не вышли за пределы границ массива, для чего используется оператор it.

Во втором примере мы решили ту же самую задачу, но несколько другим способом. Мы запустили, вообще говоря, бесконечный цикл, поскольку условие while 1 всегда истинно. Выходом же из цикла является выполнение

условия sumOfBooks > 5000.

Программа 20.12. Использование оператора Do... Loop

Sub ShopCalculate(}

Dim bookshops(1 To 25} As Integer, sum As Integer

Инициализация booksShops



Первый способ

sumOfBooks = 0

numOfShops = 0

Do

numOfShops = numOfShops + 1

If numOfShops > 25 Then Exit Do

End If

sumOfBooks = sumOfBooks + bookshops(numOfShops) Loop Until sumOfBooks > 5000 MsgBox (numOfShops - 1)

Второй способ sumOfBooks = 0 numOfShops = 0 Do While 1

numOfShops = numOfShops + 1

If numOfShops > 25 Then Exit Do

sumOfBooks = sumOfBooks + bookshops(numOfShops)

If sumOfBooks > 5000 Then Exit Do Loop

MsgBox (numOfShops - 1) End Sub

Последний из рассматриваемых нами операторов — это оператор цикла по структуре. Сразу предупредим, что здесь рассматривается лишь урезанная возможность данного оператора, поскольку мы еще не рассматривали такой тип данных, как семейство. Но мы обязательно расскажем более подробно об этом операторе, когда придет время. Итак, как всегда, начнем с прагматики. Представьте, что необходимо вычислить сумму элементов массива, диапазон изменения индексов которого может со временем измениться, даже более того, может измениться его размерность, а программа содержит очень много процедур, в которые входит суммирование массива. Ни один из вышеприведенных циклов использовать нельзя, поскольку как только изменится размерность, вам придется переписывать эти циклы. Решением явля ется использование оператора For Each. . .Next. В этом операторе отсутствует счетчик, а тело цикла выполняется для каждого элемента в массиве.

For Each элемент In группа

[блокОператоров1] [Exit For]

[блокОператоров2] Next [элемент]

Здесь элемент — это переменная, пробегающая в качестве значений элементы массива. Под группой мы пока будем понимать только массив. Элемент обязан быть переменой типа variant. А дальше все знакомо. Работа цикла происходит следующим образом: блок- операторов выполняется, пока переменная элемент не пробежит все элементы массива.

В следующем примере представим, что мы не знаем точного количества магазинов, они могут присоединиться или, наоборот, отказаться от услуг издательства, но (в данном случае) мы хотим подсчитать, сколько всего поступило заявок издательству.


Тогда с использованием объявления динамических массивов и оператора For Each. . .Next данная проблема решается без затруднений. Заметьте, что не надо менять цикл, даже если вы исправите размерность массива, например на bookshops (25, 2) (заявки на две книги одновременно).

Программа 20.13. Использование оператора For Each. . .Next

Sub RecSum()

Dim bookshops() As Integer

Dim elem As Variant

ReDim bookshops(1 To 25)

Инициализация

sum = 0

For Each elem In bookshops

sum = sum + elem Next

MsgBox (sum) End Sub

На этом мы закончим описание операторов VBA и перейдем к рассмотрению структуры программы.


Опубликование формы


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

Замечание

Еще раз вспомним отличие между формой и элементом. Форма — это специальный шаблон, на основе которого создается некий элемент. Поэтому, открывая, например, форму Контакт, заполняя и сохраняя ее, вы сохраняете не форму, а лишь элемент этой формы.

Применяя вышеописанные способы, пользователь может изменить форму, но выбрав команду > Файл > сохранить, он сохранит не саму измененную форму, а лишь элемент, основанный на ней. Кстати, в случае с формой контакта при подобной попытке появится предупреждение о незаполненном

Применяя вышеописанные способы, пользователь может изменить форму, но выбрав команду > Файл > Сохранить, он сохранит не саму измененную форму, а лишь элемент, основанный на ней. Кстати, в случае с формой контакта при подобной попытке появится предупреждение о незаполненном поле Хранить как (поскольку элемент не заполнялся), что еще раз показывает различие в способах сохранения.

Форму можно опубликовать несколькими способами, но наиболее часто употребляемыми являются:

в качестве шаблона;

в библиотеке форм.

Чтобы сохранить форму в виде шаблона, необходимо выполнить действия, показанные в примере 19.9.

Пример 19.9. Сохранение формы в качестве шаблона

Файл >Сохранить как. . .

Папка <Имя папки>

Имя := <Имя файла>

Тип файла Шаблон Outlook

ОК

Теперь для создания нового элемента на основе этого шаблона достаточно дважды щелкнуть по соответствующему файлу в Проводнике.

Замечание

Если в диалоговом окне Сохранение элемента выбрать в раскрывающемся списке Тип файла не Шаблон Outlook, а любой другой элемент, то Outlook сохранит его с указанным типом. Другое дело, что эти форматы теряют некоторую информацию формы. Например, естественно, что рисунок формы не может храниться в текстовом формате (см.
раздел 17.1.5 "Шаблон Outlook").

Для сохранения формы Outlook в библиотеке личных форм повторите действия, рассмотренные в примере 19.10.

Пример 19.10. Сохранение формы в библиотеке личных форм

Сервис> Формы > Опубликовать форму

Папки Библиотека личных форм (рис. 19.14}

Название := Writer

Имя формы:= Writer

Опубликовать



Рис. 19.14. Диалоговое окно Публикация формы

После того как форма сохранена, ею можно воспользоваться для создания новых элементов.

Пример 19.11. Создание элемента на основе пользовательской формы

> Сервис > Формы > Выбрать форму

Папки Библиотека личных форм

Формы Book

Открыть

На рис. 19.15 изображено диалоговое окно Выбор формы (Choose Form) в представлении по категориям. Обратите внимание на нижнюю часть данного диалогового окна, в котором отображаются контакт, описание и версия формы.

По умолчанию Outlook создает элементы посредством форм из стандартной библиотеки форм. Если вы хотите, чтобы Outlook по умолчанию создавал формы на основе вашей, то необходимо установить соответствующий параметр для свойств папки, хранящей элементы (см. пример 19.12).

Теперь при создании нового элемента в папке Контакты будет использоваться созданная нами форма writer.



Рис. 19.15. Диалоговое окно Выбор формы

Пример 19.12. Задание формы, применяемой по умолчанию

{На панели Outlook} Контакты

Свойства

Общие

Помещая в эту папку использовать Формы...

Папки Библиотек личных форм

Формы Writer

Открыть

ОК (рис. 19.16)

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



Рис. 19.16. Вкладка Общие диалогового окна Свойства папки "Контакты"


Основы VBA


Уважаемый читатель, позвольте перед столь нелегким делом, как почти исчерпывающее описание языка VBA с нашей стороны и кропотливое его изучение — с вашей, сделать небольшое философское отступление на тему: "Что такое язык?" Надеемся, что оно будет способствовать не только пониманию структуры данной главы, но и более глубокому пониманию самого языка Visual Basic for Applications (VBA) как такового. Итак, что же такое язык?

Язык — это знаковая система, предназначенная для хранения и передачи информации. Причем в данном случае, не умаляя общности, можно говорить о том, что не имеет значения, естественный это язык или язык программирования (а может, математический или язык жестов).

Безусловно, языки различны между собой, однако большинству языков присущи общие закономерности и, так сказать, системная организация. То есть для каждого языка определены и приемлемы такие понятия, как:

алфавит, т. е. допустимые символы языка;

лексика, т. е. словарь языка — способы образования слов из символов;

синтаксис, т. е. способы соединения слов в предложения (в VBA это способы соединения ключевых слов и слов пользователя в выражения и программные конструкции);

семантика, т. е. значение отдельных слов, словосочетаний и предложений (в VBA — значение и логический смысл выражений и программных конструкций);

прагматика, т. е. назначение и область применения языка.

В дальнейшем мы будем подходить к описанию структуры языка, исходя из вышеприведенных рассуждений и следующего правила очередности описания как языка в целом, так и любой программной конструкции. Сначала описывается прагматика (то есть ответ на вопрос: "Зачем нужна эта конструкция?"), после чего — лексика и синтаксис (то есть формальное описание того, как записывается эта конструкция) и, наконец, — семантика языка (то есть ответ на вопрос: "Что делает конструкция?"), подкрепленная рядом примеров."

С подобной точки зрения можно рассматривать все языки программирования. Все? Да, их много, и мы не будем вводить читателя в заблуждение, го воря, что VBA — единственный и неповторимый. Но во всем многообразии языков программирования VBA действительно выделяется своей уникальностью с точки зрения разработки офисных приложений. Почти все офисные задачи можно решить посредством VBA естественным путем.



Отладка и тестирование программ


Конечная цель программиста заключается в написании правильно работающей программы, но, к сожалению, в 99 случаях из 100 первая попытка использования программы приводит к появлению предупреждения диалогового окна с кодом ошибки, неверного результата или в худшем случае к зависанию компьютера. Приблизительно так начинается нелегкий путь отладки программы.

Отладка программы — это специальный этап в разработке программы, состоящий в выявлении и устранении программных ошибок, факт существования которых уже установлен. Программные ошибки, как правило, делятся на три вида:

Синтаксическая ошибка. Неправильное употребление синтаксических конструкций, например употребление оператора цикла For без то или Next.

Семантическая ошибка. Нарушение семантики той или иной конструкции, например передача функции параметров, не соответствующих ее аргументам.

Логическая ошибка. Нарушение логики программы, приводящее к неверному результату. Это наиболее трудный для "отлова" тип ошибки, ибо подобного рода ошибки, как правило, кроются в алгоритмах и требуют тщательного анализа и всестороннего тестирования.

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

В каждой современной системе программирования существует специальное средство отладки программ — отладчик (debugger), который позволяет в режиме интерпретации установить контрольные точки, выполнить отдельные участки программы и посмотреть результаты работы операторов. Естественно, что редактор Visual Basic имеет подобное средство, с которым мы сейчас и познакомимся. В вышеописанной программе мы специально допустили ошибки, на примере которых и продемонстрируем работу отладчика VBA.

Замечание

Все ошибки располагаются в процедуре AssignTask, так что перед началом отладки вы можете проверить себя и попытаться отыскать их самостоятельно.


Первый шаг отладки — это запуск компилятора: Debug > compile <имяПроекта>. Компилятор, просматривая код программы, найдет ошибку и выдаст сообщение: sub or Function not defined (Процедура или функция не определены), выделив место ошибки (creatitem) в теле процедуры.

Итак, допущена синтаксическая ошибка, мы сделали опечатку (вместо createitem ввели creatitem), и компилятор стал расценивать это как вызов процедуры пользователя, которая нигде не объявлена. Быстро исправим эту оплошность, добавив злополучную е в код:

Set tsk = Createltem(olTaskltem)

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

Замечание

Вообще же, в VBA нельзя говорить о запуске программы как таковой, поскольку в отличие от других языков программирования, в которых существует предопределенный способ определения того, с чего будет начинаться выполнение программы, в VBA такого предопределения нет. В VBA никакая процедура не является главной по умолчанию, нужно как-то указывать, с чего должно начинаться выполнение программы. Типовое решение автоматического запуска программы VBA — связывание "главной" процедуры с событием открытия документа, в котором находится проект.

Запуск программы в VBA осуществляется разными способами. Уже упоминалась возможность запуска программы посредством нажатия клавиши <F5> или с помощью команды Run Sub\UserForm меню Run. Однако при таком вызове запускается активная процедура, т. е. процедура, в которой находится курсор. Другим Способом является вызов диалогового окна Macros из меню Tools. В этом окне можно выбрать запускаемую процедуру, не делая ее активной.

Итак, мы запустили программу. Что же происходит? Сразу после запуска появляется диалоговое ОКНО об ошибке: Object variable or With block variable not set (объектная переменная или переменная блока with не определена) и четыре варианта продолжения работы с программой (рис. 22.6):



Continue. Продолжить выполнение программы.

End. Закончить выполнение программы.

Debug. Прервать выполнение программы и перейти в режим отладки.

Help. Вывести подробную справку об ошибке.

Замечание

Хотя в данном случае кнопка Continue не активна, она бывает очень полезна в ряде случаев. Например, при прерывании хода программы комбинацией клавиш <Ctrl>+<Break> только для проверки контрольных значений в окне Immediate, когда нет необходимости переходить в режим отладки, если все значения удовлетворительны. Кнопка End используется для окончательного прерывания хода программы, как правило, когда ошибка сразу видна и не требует отладочных средств.



Рис. 22.6. Диалоговое окно Run-time error '91'

Выберем Debug. В этом случае окно с кодом программы становится активным и в нем выделяется (по умолчанию желтым цветом) оператор, на котором прервалось выполнение программы. Мы выбрали Debug, поскольку имеем достаточно большой опыт и по краткому описанию ошибки можем понять, в чем дело. Но вам мы советуем до определенного момента обращаться за разъяснением к справке, в которой подробно и на примерах описана ошибка, вызвавшая прерывание хода программы.

В нашем же случае произошла семантическая ошибка: неправильное присваивание переменной значения ссылки на объект. Для устранения этой ошибки необходимо добавить оператор присваивания set перед переменной tsk. Давайте еще раз запустим программу. На этот раз она успешно завершилась, дойдя до конца и выдав сообщение "Задача успешно поручена".

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

Как видите, все параметры верны, кроме загадочного срока окончания задачи, который истекает через 5 дней, в то время как в диалоговом окне продолжительность проекта была равна 5 месяцам!!!

Итак, наша программа фактически работает, собирает данные из разных источников, создает задачу и даже назначает ее, но неверно устанавливает срок ее окончания.


Надо констатировать, что мы столкнулись с последним типом ошибки — логическим. Компилятор не может отследить подобного рода ошибки автоматически, но это может сделать программист, используя, конечно, всевозможные способы и средства отладки.

Для отлова логических ошибок выполняется трассировка программы, т. е. выполнение программы или ее участка, сопровождающееся выводом в хронологической последовательности информации о событиях, связанных с выполнением программы. Давайте задумаемся, информацию о каких событиях мы хотели бы получить? Мы хотели бы получить и наблюдать измене ние переменных после выполнения операторов программы, причем желательно в пошаговом режиме, чтобы видеть процесс выполнения программы и иметь возможность тут же его исправить. Однако наблюдение всех переменных хоть и возможно, но малоэффективно.



Рис. 22.7. Сгенерированная задача

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

Чтобы создать точку останова, следует в отлаживаемой процедуре установить точку ввода в любом месте строки кода VBA, перед выполнением которой вы хотите остановить выполнение процедуры. Затем нужно выбрать команду > Debug > Toggle Breakpoint или просто нажать клавишу <F9>. При этом строка будет выделена коричневым цветом, а на левом поле окна кода появится жирная коричневая точка. Для снятия точки останова нужно еще раз повторить те же действия. Если напротив оператора стоит точка ос танова, это означает, что выполнение программы будет приостановлено перед выполнением этого оператора.

Замечание

Есть и более простой и, на наш взгляд, естественный способ установки точек останова: достаточно просто сделать щелчок мышью по серой полоске у левого края соответствующей строки кода.


Снять эту точку можно повторным щелчком по жирной коричневой точке. Наконец, если вы хотите снять все ранее поставленные точки останова, вовсе необязательно снимать все эти точки поодиночке. Достаточно воспользоваться командой меню > Debug > Clear All Breakpoints.

Наши подозрения вызвали следующие места программы, в которых мы и расставили точки останова (рис. 22.8).

Инициализация переменной tsk (чему равняется значение по умолчанию).

Вызов стандартной функции NOW (действительно ли возвращается текущее время).

Установка даты окончания задачи (правильно ли происходит суммирование).

После расстановки точек останова необходимо, как было сказано, указать, значения каких переменных мы хотели бы наблюдать. Естественно, что мы выбрали значения полей tsk.startoate и tsk.DueDate. Для наблюдения за несколькими свойствами или переменными существуют специальные окна Locals Window и Watch Window. Эти окна можно открыть с помощью соответствующих кнопок на панели Debug или команд меню View.

В окне локальных переменных можно наблюдать за значением всех локальных переменных выполняемой в данный момент процедуры, а окно контрольных значений предназначено для постоянного наблюдения за выбранными пользователем переменными или свойствами. Чтобы определить контрольное значение, достаточно выделить в окне модуля любую переменную, выражение или свойство и нажать кнопку Quick Watch на панели инструментов Debug. При этом появится диалоговое окно, в котором указано имя подпрограммы, само выражение, а также его текущее значение (рис. 22.8).

Нажав на расположенную в правой части диалогового окна кнопку Add, можно переместить это выражение в список наблюдаемых контрольных значений в окне Watch. При этом в момент останова отлаживаемой программы весь список наблюдаемых выражений и их значения будут сразу же видны в соответствующем подокне, располагающемся обычно в нижней части экрана. Добавим переменную tsk. star toate вышеописанным способом. Чтобы наблюдать значение переменной, необходимо выполнить следующее действие.





Рис. 22.8. Точки останова и диалоговое окно Quick Watch

Пример 22.8. Добавление переменной в окно Add Watch

{ В окне Watch} 1R Add Watch... (рис. 22.9)

Expression := tsk.StartDate

Procedure AssignTask

OK

Итак, точки останова расставлены, окно Add Watch с наблюдаемыми переменными активно, следовательно, с замиранием сердца переходим к трассировке программы. Итак, нажимаем клавишу <F5>, как и предполагалось, перед инициализацией переменной происходит останов программы. Все правильно. Теперь давайте посмотрим, как изменились значения переменных В окне Add Watch: tsk.StartDate = 01:01:4501, tsk.StartDate = 01:01:4501, a duration = 5.



Рис. 22.9. Диалоговое окно Add Watch

Для единичного просмотра значения переменной можно просто подвести к ней указатель мыши, и вы увидите всплывающую подсказку. Например, duration = 5.

Для дальнейшего пошагового выполнения программы можно воспользоваться одним из трех способов:

Step Into. При нажатии клавиши <F8> выполняется очередной оператор, после чего выполнение программы приостанавливается и программа становится доступна для корректировки.

Step Over. Нажатие комбинации клавиш <Shift>+<F8> осуществляет вызов вспомогательных процедур и функций за один шаг, что дает возможность не задерживаться на их выполнении.

Step Out. Данная комбинация клавиш <Ctrl>+<Shift>+<F8> позволяет выйти из выполняемой вспомогательной процедуры, не дожидаясь конца ее пошагового выполнения.

Итак, нам необходимо нажать клавишу <F8> и посмотреть, чему стало равно значение tsk.startDate. Как и следовало ожидать, переменной было присвоено значение 21.08.01. (текущая дата 21 августа 2001 года). Следовательно, функция Now работает корректно.

Далее мы попадаем на следующую точку останова — присваивание значения переменной tsk.DueDate. После очередного нажатия клавиши <F8> проверим значения текущих переменных и окончательно обнаружим ошибку.

Значение переменной duration равно 5, прибавляя его к значению текущей даты, мы прибавляем не месяцы (как хотелось бы), а дни.


Исправим эту ошибку, изменив код ошибочной строки на следующий:

.DueDate = DateAdd("m", duration, .StartDate)

Замечание

Встроенная функция DateAdd предназначена для добавления или вычитания из даты указанного числа временных интервалов.

В конце рассказа об отладчике мы решили на рис. 22.10 показать панель инструментов Отладка (Debug) с кнопками, используемыми при отладке, а в табл. 22.1 привести краткую справку по всем использованным и неиспользованным средствам отладчика.



Рис. 22.10. Кнопки панели Отладка

Таблица 22.1. Средства отладчика

Команда



Назначение



Compile

Компиляция программы

Run Sub/UserForm

Запуск процедуры или формы

Break

Прерывание выполнения программы <Ctrl>+<Break>

Reset

Остановка выполнения программы

Toggle Breakpoints

Установить точку останова

Clear All Breakpoints

Снять все точки останова

Step Into

Шаг с заходом во вспомогательные процедуры

Step Over

Шаг с обходом вспомогательных процедур

Step Out

Шаг с выходом из вспомогательной процедуры

Step to Cursor

Шаг до курсора. Запускает программу на выполнение до строки с курсором

Set Next Statement

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

Show Next Statement

Показывает следующий выполняемый оператор

К сожалению, не все приемы отладки можно рассмотреть на нашем простейшем примере.

Команда

Назначение

Immediate Window

Отображает окно отладочных результатов вычисления

Locals Window

Отображает окно локальных переменных процедуры

Watch Window

Отображает окно контрольных выражений программы

Add Watch

Добавляет выражение в окно Watch

Edit Watch

Исправляет выражение в окне Watch

Quick Watch

Просматривает значение выделенного выражения

Call Stack

Позволяет показать стек вызовов процедур в текущий момент. Эта кнопка очень полезна при работе с рекурсивными процедурами

Comment Block

Позволяет закомментировать выделенный блок операторов

Uncomment Block

Отменяет сделанные комментарии

Toggle Bookmarks

Устанавливает закладку

Clear All Bookmarks

Снимает все установленные закладки

Find

Вызывает диалоговое' окно поиска, посредством которого можно найти ту или иную переменную, выражение и т. д.


Подробные свойства


Более подробные свойства для объекта управления можно задать в диалоговом окне Свойства (Properties). В приведенной ниже программе зададим специальный эффект для отображения раскрывающегося списка, а также укажем на изменение указателя мыши при наведении на данный элемент управления.

Рис. 19.6. Панель Свойства элемента управления

Пример 19.6. Задание дополнительных свойств элемента управления

{ Элемент управления }

Дополнительные свойства (рис. 19.6)

Свойство SpecialEffeet

Apply 6-Bump

Apply

Свойство MousePointer

Apply 10-UpArrow

Apply



Постановка задачи


Работая над задачей любой сложности, необходимо четко представлять ее условия, цель, а также возможные способы решения. Ибо несогласованность и абстрактность требований может привести к затягиванию сроков реализации проекта или просто его к невыполнению. Итак, обозначим наши условия

Условие. Есть редактор издательства, одной из частных задач которого является подписание договора с автором и отслеживание хода его работы над книгой. Помимо этого, известно, что существует четыре серии книг, причем их названия могут изменяться. Также известно, что для всех писателей имеются контакты, хранящиеся в папке "Писатели".

Цель. Автоматизировать процесс работы редактора.

Способы решения. Одним из возможных способов решения является использование задач Outlook, которые абсолютно вписываются в рамки поставленного условия. Но создание однотипных задач вручную ведет к появлению ошибок и неоднозначности. Таким образом, ограничивая, с одной стороны, редактирование задачи и беря контроль над ее созданием, мы, с другой стороны, унифицируем процедуру работы редактора.

На рис. 22.1 изображена панель задач с однотипными задачами, сгенерированными нашим приложением.

Рис. 22.1. Сгенерированные задачи

Итак, задача поставлена, и мы переходим к ее программной реализации. Начнем, с разработки формы (диалогового окна).



Проектирование диалогового окна


Для создания задачи и заполнения ее информационных полей необходимо открыть диалоговое окно, с помощью которого можно будет указать тип серии, выбрать автора, а также задать название книги и срок ее написания.

Для проектирования диалогового окна нам потребуется создать пользовательскую форму, на которую помещаются нужные элементы управления — раскрывающиеся списки, поля вода, кнопки, а затем написать процедуры обработки событий, связанных с этими элементами управления: что должно происходить при открытии окна, при вводе данных в поле ввода, при нажатии кнопки, при выборе элемента раскрывающегося списка и т. д.

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

Начнем с того, что откроем проект VBA и вставим в него новую пользовательскую форму.

Пример 22.1. Создание пользовательской формы

> Сервис > Макрос > Редактор Visual Basic...

{В окне VBE}

> Insert > UserForm

При этом открывается окно разработки пользовательской формы с пустой пока пользовательской формой. Теперь предстоит подобрать нужные размеры будущего диалогового окна и поместить на него нужные элементы управления. Для этого откройте соответствующую панель инструментов.

Пример 22.2. Открытие панели инструментов Too/box (Элементы управления)

> View > Toolbox

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

После того как элемент управления помещен в кадр диалога, вы можете перемещать его, изменять его размеры или даже удалить его.
Щелчок по элементу управления выделяет его, после чего можно воздействовать на выделенный элемент. Если удерживать нажатой клавишу <Ctrl> во время выполнения щелчков по элементам управления, то таким образом можно будет выделить несколько элементов управления одновременно. Если же во время щелчков мышью вы будете удерживать нажатой клавишу <Shift>, то выделятся сразу все элементы управления, расположенные между теми двумя, по которым сделаны щелчки. Наконец, можно просто растянуть рамку выделения над теми элементами управления, которые вы хотите выделить.

Перетаскивание элемента управления (или сразу нескольких выделенных элементов) перемещает его в пределах пользовательской формы. Перетаскивание одного из маркеров выделения позволяет изменить размеры выделенного элемента или сразу нескольких выделенных элементов. Например, если выделить несколько элементов управления, а затем установить указатель мыши над правым маркером выделения и протащить его чуть дальше вправо, можно увеличить размеры всех выделенных элементов разом на одинаковую величину. Наконец, нажатие клавиши <Delete> удаляет все выделенные элементы.

Попробуйте подготовить представленную на рисунке пользовательскую форму для диалогового окна (рис. 22.2). Для этого надо поместить в диалоговое окно два раскрывающихся списка (comboBox), одно поле ввода (TextBox), один рисунок (image), одну кнопку(CommandButton) и наконец десяток текстовых надписей (Label), служащих для пояснения назначения активных элементов управления, на которые может воздействовать пользе-, ватель во время работы программы.



Рис. 22.2. Проектируемое диалоговое окно

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

Можно также изменить текст надписи с помощью панели свойств элементов управления — таким же образом, как и многие другие свойства этих элементов.


Однако изменение свойств элементов управления с помощью панели свойств заслуживает особого разговора — мы посвятим этому следующий раздел.

Для четкой расстановки элементов управления можно воспользоваться как сеткой диалогового окна, так и командами меню Format. Например, в приведенном ниже примере мы выровняли все текстовые поля и поля редактирования по левому краю.

Пример 22.3. Форматирование элементов управления

Номер главы

<Ctrl> + Серия

<Ctrl> + Раскрывающийся список

<Ctrl> + Название

<Ctrl> + Длительность проекта

{Трое из элементов имеют черные маркеры выделения, а "Длительность" —

былые. Именно по этому полю будет происходить выравнивание}

> Format > Align > Lefts

Когда все будет готово, вы можете посмотреть на то, как разработанное вами диалоговое окно будет выглядеть во время выполнения программы: для этого нажмите клавишу <F5>. Завершить тестовый просмотр диалогового окна позволяет кнопка закрытия в правом верхнем углу диалога.


Программирование в Outlook


Microsoft Outlook является поистине всеохватывающим приложением в области управления информацией. Вы можете месяцами изучать его различные компоненты, исследовать новые возможности, так никогда и не столкнувшись с разработкой собственных форм и созданием макросов. Однако, если вы хотите получить от Microsoft Outlook максимум возможного, существенно облегчить выполнение своих повседневных задач, избавившись от многократного повторения одних и тех же процедур или от введения специфической информации нестандартными путями, то умение разрабатывать формы и использовать макросы вам совершенно необходимо.

Microsoft Outlook, как и любое другое приложение Microsoft Office, допускает два разных уровня использования:

применение Outlook как готового к употреблению универсального инструмента для решения стандартных задач управления информацией. Этой возможности Outlook были посвящены три предыдущих части;

применение Outlook как инструментальной среды для разработки собственных приложений, решающих специфические задачи пользователя более эффективным способом. Об этой возможности и пойдет дальше речь.

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

Не бойтесь, если какой-либо факт вызовет с первого раза непонимание или какая-либо возможность будет описана не полностью, поскольку вопрос разработки форм и программирования настолько широк, что заслуживает отдельной книги. Здесь же дается всего лишь попытка в доступной, понятной и как можно более полной форме рассмотреть основы программирования в Outlook. Надеемся, что полученные знания помогут вам в разработке собственных небольших приложений с достаточной степенью легкости.

В заключительной части книги будут рассмотрены следующие аспекты программирования в среде Outlook:

Разработка форм. В данной главе будут изложены основы разработки форм Outlook, использования полей пользователя и элементов управления.



Основы VBA. Приводится почти полное описание языка программирования Visual Basic for Application (VBA), посредством которого можно записывать макросы и создавать пользовательские приложения Outlook.

Объектная модель Outlook 2002. В настоящей главе описывается иерархия объектов Outlook 2002. Кроме того, рассматриваются основные классы, используемые при реализации приложений Outlook.

Разработка приложения. В последней главе будет приводится пример разработки простого пользовательского приложения Outlook, на котором будет продемонстрировано использование классов объектной модели Outlook 2002 и VBA.

 

Работа с файлами


Следующий список, который необходимо инициализировать, — series. В отличие от duration, как было отмечено выше, этот список может изменяться, поэтому мы решили хранить список с названием серий в специальном файле bookseries.ini и забирать информацию для инициализации именно оттуда.

Рис. 22.4. Архитектура файла bookseries.ini

Таким образом, пользователю необходимо лишь добавить название новой серии в данный файл, как сделанные изменения тут же отобразятся в форме. Архитектура файла инициализации показана на рис. 22.4.

Итак, перейдем непосредственно к написанию кода процедуры. Для ввода кода программы опять необходимо перейти в окно редактора кода, для чего выделите форму и нажмите клавишу <F7>.

Программа 22.3. Работа с файлами

Sub Init_Series()

Dim inifile As Integer

Dim srv As String

inifile = FreeFile

iniPath = "C:\bookseries.ini" 'Открываем файл для чтения

Open iniPath For Input As tinifile

Do

Input tinifile, tmp series.Addltem tmp 'Цикл до конца файла

Loop Until EOF(inifile)

series.Listlndex = 0 End Sub

Прокомментируем эту программу. Сначала объявляется переменная inifile, с которой будет отождествлен файл. Далее открывается файл bookseries. ini (хранящийся в корне диска С), после чего в цикле от начала до конца файла считываются построчно значения для списка серий.

Естественно, что и вызов процедуры init_Series необходимо поместить в тело конструктора userForm_initialize, который теперь будет выглядеть следующим образом.

Программа 22.4. Вызов процедуры lnit_Series из конструктора

Private Sub UserForm_Initialize()

Init_Duration

Init_Series End Sub



Раскрывающийся список


Создадим раскрывающийся список Переплет и соответствующую надпись к нему.

Пример 19.4. Добавление элементов управления

> Форма >> Элементы управления

Toolbox Label {На форме}

{На элементе Надпись} Свойства

Оформление

Заголовок := Переплет:

ОК

Toolbox ComboBox {Ha форме}

{Ha элементе Список} (рис. 14.3)

Рис. 19.3. Добавление элементов управления



Разработка форм


Рассматривая ранее работу с элементами Outlook, мы постоянно встречались с заполнением форм всевозможной природы (сообщение, встреча, задача и т. д.). Использование форм является стандартным электронным средством сбора и классификации данных. Простой графический интерфейс (поля, списки, кнопки) и подключенные к форме специальные команды дают возможность пользователю легко и непринужденно вносить в форму данные.

Но как быть в случае, если форма не содержит необходимого для вас поля? Существует множество некорректных способов выхода из подобной ситуации, например значения для несуществующего поля заносить в существующее, но неиспользуемое поле (постоянно держа в голове, что же действительно в нем хранится). Еще одним из способов является вложение в элемент файла с дополнительной информацией по этому полю и т. д. Поверьте опыту писателя, который видел множество примеров глумления над Outlook, в то время как решение этих проблем лежит на поверхности, а именно заключается в разработке собственной формы, содержащей все требуемые поля.

Чтобы не быть голословным, давайте рассмотрим разработку формы пользователя на конкретном примере. Допустим, что сотрудник отдела кадров издательства "БХВ-Петербург", работая с Microsoft Outlook, сталкивается с проблемой, что в форме Контакт нет полей, отображающих специфику контакта-автора, а именно:

Книги. Книги, написанные этим автором;

Страницы. Количество страниц для каждой из этих книг;

Общее кол-во страниц. Общее количество страниц, написанных автором;

Переплет. Один из возможных вариантов переплета: твердый или мягкий для книги.



Разработка приложения


В предыдущих главах мы познакомились с разработкой форм, основами языка программирования VBA и объектной моделью Outlook. Знание этих азов необходимо для создания приложений Outlook, но без хорошего практического примера, закрепляющего и подтверждающего теорию, все это теряет смысл.

Теперь пришла пора приступить к созданию своих собственных приложений на VBA с использованием Microsoft Outlook в качестве среды их разработки. Одним из наиболее простых и эффективных способов научиться программированию является знакомство с подходящими примерами — небольшими задачами, на которых видны основные приемы решения типичных проблем разработки приложений.

В этой главе мы познакомимся с таким примером — простым приложением для создания типовой задачи Outlook редактором издательства. Нам предстоит написать несколько программ на VBA. В то же время нам не придется программировать все необходимое для работы приложения "с нуля": окна, панели инструментов, отправку сообщений — это будет возложено на стандартные средства Outlook. Мы же продемонстрируем, как разрабатывается пользовательский интерфейс приложения — диалоговые окна, содержащие самые различные элементы управления: поля ввода, раскрывающиеся списки, кнопки и т. д.



Редактор Visual Basic for Application


Любая система программирования, помимо основной части — транслятора (то есть компилятора или интерпретатора) языка программирования, должна включать среду программирования, обеспечивающую автоматизированную разработку и выполнение программ на данном языке, и подготовку соответствующей документации. Как правило, все современные системы программирования имеют хороший инструментарий для корректного напи сания программы, ее форматирования, редактирования и отладки, встроенный в удобный и интуитивно понятный интерфейс, способствующий всесторонней поддержке программирования.

В этом разделе мы рассмотрим редактор VBA, работу со справочной системой и, наконец, расскажем о ведении проекта, его свойствах и интеграции с другими проектами.

Итак, вся разработка и отладка программ ведется с помощью Редактора Visual Basic (Visual Basic Editor, VBE). Запуск редактора для приложений Microsoft Office осуществляется следующим образом > Сервис > макрос > Редактор visaul Basic (<Alt>+<F11>) (см. раздел 21.1 "Общие положения").

Обычно в окне редактора используются три панели (три отдельных окна). На самом деле окон может быть и больше и меньше, и скоро вы узнаете обо всех, но это — основные окна, открывающиеся по умолчанию (рис. 20.2):

Project (Окно проекта);

Properties (Окно свойств);

Code (Окно кода).

Итак, первое окно, которое мы рассмотрим, — окно проекта, обычно располагающееся в верхнем левом углу редактора (рис. 20.3). Если оно не активно, выберите команду > view > Project Explorer либо нажмите комбинацию клавиш <Ctrl>+<R>.

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

В нашем случае в окне проекта открыт только один проект — Проект 1.

Каждый проект содержит пять папок с модулями:

Microsoft Outlook Objects — папка с объектом приложения ThisOutlookSession;



Forms — папка содержит пользовательские модули форм (userForm. — см. главу 22 "Разработка приложения")',

Modules — папка содержит стандартные модули пользователя;

Class Modules — папка содержит пользовательские модули классов;

References — папка содержит ссылки на объекты из внешних библиотек и список модулей этих библиотек.

Если окно кода не активно, выберите команду > View > Code или нажмите клавишу <F7>.



Рис. 20.2. Редактор Visual Basic for Application

О добавлении, удалении и переименовании модулей в проекте будет рассказано ниже.

Помимо области, где отображаются документы, на панели проекта располагаются три кнопки.

View Code. После нажатия на данную кнопку указатель перемещается в окно кода, где отображается код выделенного объекта.

View Object. При нажатии этой кнопки показывается реализация выделенного объекта. Например, если выделен Лист2, то при нажатии кнопки View Object вы увидите второй лист рабочей книги Excel.

Toggle Folders. При нажатой кнопке отображаются элементы проекта в соответствующих кнопках, при отжатой — элементы проекта располагаются просто в алфавитном порядке.

Перейдем теперь к рассмотрению окна свойств, обычно располагающегося под окном проектов. Данное окно позволяет просматривать и изменять свойства различных объектов, входящих в проект. Для отображения свойств

объекта его необходимо выделить. Объект можно выделить на панели проектов, на пользовательской форме. Кроме того, можно выделять объекты, подчиненные выделенным объектам. Так, например, для модуля доступно только свойство Name. Более эффективен этот прием при работе с многочисленными объектами, подчиненными пользовательским формам.

Чтобы изменить значение свойства объекта, необходимо: Выделить имя свойства в левой колонке.

Изменить значение этого свойства в правой колонке либо введя его с клавиатуры, либо выбрав из раскрывающегося списка.

Безусловно, окно свойств — очень полезный инструмент, поскольку сразу видны почти все свойства объекта и их допустимые значения.


Но изменение свойств объекта посредством панели статично и не обладает программной динамикой. Подобная панель удобна для задания начальных или постоянных значений свойств объекта, таких как имя листа или цвет пользовательской формы. Мы изменили имя первого модуля Moduiei на Test (рис. 20.3).



Рис. 20.2. Окно проекта



Рис. 20.3. Окно свойств

Кстати, свойства можно отображать как в алфавитном порядке, так и по категориям, посредством выбора соответствующих вкладок Alphabetic или Categorized. Следующая рассматриваемая нами панель — панель кода. Это окно занимает большую часть экрана. Данная панель — это не просто "чистый лист", предназначенный для ввода кода, а специализированный высокоинтеллектуальный текстовый редактор, существенно облегчающий введение, форматирование и редактирование кода VBA. Окно кода напрямую связано с модулем проекта и открывается при двойном щелчке мышью по необходимому модулю в окне проекта.

Замечание

Вообще говоря, окно кода является "многодокументным", т. е. можно открыть одновременно несколько окон данного типа для разных модулей. На рис. 20.10 каскадно отображены три окна трех модулей соответственно. Для изменения отображения окон можно воспользоваться командами меню Window.

Здесь мы опишем главные возможности редактора кода VBA:

Автоматическое завершение ввода стандартных лексем языка. Например, после ввода ключевого слова sub имяПроцедуры и нажатия клавиши <Enter> VBA автоматически добавляет скобки и строку End Sub.

Автоматическое выравнивание и отступ. К примеру, после ввода оператора присваивания р=р+1 и нажатия клавиши <Enter> редактор вставит пробелы: р = р + 1.

Автоматическое выделение цветом лексических и синтаксических конструкций. Ключевые слова VBA выделяются синим цветом, ошибочные конструкции — красным, а комментарии — зеленым.

Автоматическая проверка правильности семантики и синтаксиса конструкций. Если вы введете inputBox () и забудете присвоить значение этой функции переменной (потеря семантики), автоматически появится предупреждение об ошибке.



Автоматический вывод списка компонентов. . Позволяет избежать ошибок при вводе наименований свойств объектов, встроенных констант, типов переменных. Особенно полезна эта функция при установке свойств объекта, т. к. дает возможность не только вспомнить правильное имя свойства, но и увидеть, какие свойства объекта доступны в данный момент.

Автоматический вывод кратких сведений. Показывает в виде подсказки синтаксис встроенных процедур и функций. По мере ввода очередной параметр выделяется жирным шрифтом.

Если вы тестировали примеры предыдущего раздела, то не раз должны были встречаться со всеми свойствами редактора. Неправда ли, он умен? Но это только внутренняя часть окна кода, рассмотрим теперь его интерфейс.

В левом верхнем углу окна кода размещается раскрывающийся список Object (Объект), содержащий объекты выделенного модуля. Понятно, что для стандартного модуля этот список отсутствует, но, скажем, для модуля Этакнига данный список содержит объект workbook, для которого можно написать процедуры реакции на событие. Но и тут "умное" окно кода приходит на помощь. В правом верхнем углу в раскрывающемся списке Procedure (Процедура) содержатся все стандартные процедуры реакции на события для этого объекта. В случае со стандартным модулем этот список содержит все процедуры модуля, а также общий раздел объявлений Declarations (Объявления), в котором описываются переменные уровня модуля. При этом, выбрав одну из процедур в этом списке, вы автоматически попадете на ее начало.

С помощью кнопок в левом нижнем углу окна можно выбрать один из двух видов представления кода в окне:

представление процедуры, когда в окне отображается только выбранная процедура;

представление полного модуля, когда в окне отображается сразу несколько процедур, которые отделены друг от друга тонкой линией (см. рис. 20.4).



Рис. 20.4. Окно кода

Для более детальной настройки интерфейса всегда можно воспользоваться диалоговым окном Options (Опции) меню Tools (Инструменты). В нем вам предоставляется возможность изменить такие установки, как автоматическая проверка и помощь при вводе кода, разделение процедур тонкой чертой, изменение параметров шрифта кода, размещение окон редактора и т.


д. Настройка редактора достаточно проста, и мы не будем подробно ее описывать. Если же у вас возникнут вопросы по назначению того или иного параметра, вы всегда можете обратиться к справочной системе VBA, о работе с которой и пойдет сейчас речь.

Современные системы программирования отличаются от систем программирования прежних лет:

очень богатым набором готовых программных компонент, которые можно использовать в программах (об этом пойдет речь в главе 21 "Объектная модель Outlook 2002");

очень развитой системой получения информации о среде программирования непосредственно из самого редактора (об этом рассказывается в настоящем разделе).

Нельзя объять необъятное, а точнее, невозможно (да и не нужно) в рамках этой книги описать весь VBA. Наша цель, как было сказано, краткое изложение полного вводного курса в VBA. Однако всего не опишешь. Поэтому мы советуем вам за ответом на тот или иной появившейся вопрос обращаться к встроенной справочной системе VBA. Умение пользоваться ею — это необходимое условие работы программиста и, мы думаем, не стоит уделять внимание обсуждению вопроса, насколько необходимо это условие, ибо без навыков работы со справочной системой невозможно быстрое и полноценное программирование.

Пример 20.2. Вход в справочную систему

Help > Справка по Microsoft Visual Basic {или нажмите клавишу <F1>}

Давайте рассмотрим работу со справочной системой на примере поиска информации об объекте Application. Поиск требуемой информации мы начали с вывода объектной модели Microsoft Outlook. Ее диаграмма, содержащая объект Application и подчиненные объекты, дает общее представление о составе и структуре объектной модели приложения и позволяет получить справку о каждом объекте (рис. 20.5). На этой диаграмме представлены объекты и семейства объектов в виде прямоугольников разного цвета (голубого и желтого, соответственно). Для семейства, кроме имени в скобках, указано имя объекта — элемента семейства. Иногда справа от прямоугольников отображается значок красной стрелки.


Щелчок по ней позволяет спуститься на более низкие уровни иерархии объектов; щелчок по любому из прямоугольников — получить справку по этому объекту.

Пример 20.3. Получение справки

Мастер ответов

Выберите действие := Outlook Objects Найти

Выберите раздел := Microsoft Outlook Objects

Application



Рис. 20.5. Окно справки с объектной моделью Microsoft Outlook

Мы рассмотрели вариант получения информации об объектной модели и ее элементах с помощью справочной системы, но помимо этого существует специальный помощник — гид в мире объектов приложений — Object Browser (Окно просмотра объектов). Окно просмотра объектов представляет собой специальное средство редактора Visual Basic, позволяющее просматривать содержимое библиотек объектов и производить поиск справочной информации о предоставляемых ими объектах.

Пример 20.4. Запуск Object Browser

Object Browser {На панели Standard или}

View > Object Browser {или}

<F2>

Окно просмотра объекта состоит из нескольких частей:

Поле со списком Project/Library (Проект/Библиотека), расположенное в верхнем левом углу окна. Этот список предназначен для выбора одной из библиотек открытого проекта приложения. В нем отображаются только те библиотеки, на которые были установлены ссылки в приложении.



Рис. 20.6. Окно просмотра объектов

Поле со списком Search Text (Образец поиска), расположенное под списком Project/Library. Позволяет ввести текст для поиска компонентов в доступных библиотеках. После ввода образца поиска необходимо нажать кнопку Search (Поиск). Так, например, на рис. 20.6 отображен результат поиска по слову Application для всех доступных библиотек приложения Outlook.

Окно Search Result (Результат поиска). В этом окне отображается результат поиска в трех списках: Library (Библиотека), Class (Класс) и Member (Компонент). Каждый элемент списка соответствует найденному компоненту — классу или элементу класса, и содержит (справа налево) название найденного компонента, название класса, которому принадлежит этот компонент, и название библиотеки, которой принадлежит этот класс.


Поиск по образцу происходит без учета регистра. Для обозначения типа компонента объектной модели в Microsoft Office введена специальная система значков, представленная на рис. 20.7.



Рис. 20.7. Значки типов компонентов объектной модели

Список Classes (Классы). Содержит список объектов, типов данных и перечислений (списков констант), принадлежащих конкретной библиотеке или проекту. Содержимое этого списка соответствует элементу, выбранному в раскрывающемся списке Project/Library, или элементу, выделенному в окне Search Result, как в нашем случае (см. рис. 20.12).

Список Members of <Class> (Компоненты, класса). Содержит список выбранного класса: свойства (переменные и константы), методы и события. По умолчанию компоненты отсортированы по имени, для удобства поиска возможна сортировка по типу:1R Group Members.

Окно Details (Описание). В нижней части окна просмотра объектов выводится краткое описание выбранного объекта. Описание проекта приложения включает полный путь и имя файла приложения. Описание библиотеки включает полное ее название, а также полный путь и имя соответствующего файла. Описание объекта включает его имя и имя библиотеки, которой он принадлежит. Описание компонента включает его тип, если это функция, сигнатуру (тип возвращаемого значения и список аргументов), имя, возможно, значение по умолчанию и название объекта и библиотеки, которым он принадлежит. Название объекта или библиотеки в окне описания выделяется особым стилем. Щелкнув по ним мышью, можно выбрать соответствующую библиотеку или объект в окне просмотра объектов.

Панель инструментов окна просмотра объекта. Содержит следующие кнопки:

Кнопка Search (Поиск) предназначена для поиска компонентов по образцу, введенному в поле Search Text.

Кнопка Show/Hide search results (Скрыть/показать результаты" поиска) используется для отображения или скрытия списка найденных компонентов.

Кнопки навигации Go Back (Назад) и Go Forward (Вперед) применяются для перехода к предыдущему или следующему компоненту в той последовательности, в которой пользователь к ним обращался.



Кнопка Copy to Clipboard (Копировать в буфер обмена) позволяет скопировать в буфер обмена имя выделенного компонента.

Кнопка View Definition (Описание) дает возможность перейти к исходному коду определения объекта, свойства или метода. Если приложение содержит много функций и процедур в нескольких модулях, поиск нужного места в программе становится затруднительным. В этом случае с помощью окна проектов и кнопки View Definition задача поиска заметно облегчается.

Кнопка Help (Спра-вка) отображает окно справочной системы, содержащее подробное описание выделенного компонента.

Закончим рассказ об Object Browser получением справки о методе persInit нашего класса Person. Конечно, вы сможете получить эту информацию только, если документ с определением класса активен. Заметьте, что классы и методы пользователя выделяются жирным шрифтом.

Пример 20.5. Поиск в Object Browser

Project/Library All Libraries

Search Text := persinit

После этого в окне Details появится описание нашего метода.

Справочная система — очень сильное оружие, но в некоторых руках оно может быть неэффективным если пользователь не знает, где и что искать. Мы.советуем вам посвятить несколько часов своеобразной тренировке по поиску той или иной информации. Это поможет попять работу справки — куда она ссылается, какой род информации выдает и т. д. Умение правильно ставить вопрос и отсекать ненужные ссылки — очень большой плюс при работе со справкой.

Перейдем к следующему объекту рассмотрения, регламентированному в начале раздела, — проекту. Как уже упоминалось, проект — это набор программных модулей, связанных с основным документом приложения (см. "Разработка приложения"). Сейчас мы рассмотрим работу с проектами. Расскажем о свойствах проекта, о том, как манипулировать структурой проекта и как управлять проектами в многодокументных приложениях.

В начале этого раздела мы говорили, что проект состоит из модулей разных типов, но не говорили о том, как добавить модуль, удалить его или переименовать.



Добавление модуля в проект осуществляется следующим образом:

Пример 20.6. Добавление модуля

>Insert > {Forms | Module | Class Module}

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

Пример 20.7. Удаление модуля

> File > Remove Module Нет

Помимо вышеприведенных способов добавления и удаления модулей существует еще один, и на наш взгляд, более естественный способ. Для добавления (удаления) модуля необходимо в окне проекта выполнить следующую последовательность действий:

Insert

> (Forms | Module | Class Module}

( Remove Module)

При создании нового модуля ему присваивается имя модульы, где N — порядковый номер этого модуля. Аналогичная ситуация происходит при автоматической записи макросов, где модулю, содержащему макрос, присваивается имя NewMacros. Подобное наименование не несет никакой информативной нагрузки о содержании модуля, поэтому мы советуем всегда переименовывать стандартные имена модулей.

Пример 20.8. Переименование модуля

{В окне проекта} Modulel

{В окне свойств} Name := <Новое имя модуля>

После того как мы освоили создание и удаление модулей, давайте рассмотрим, для чего же они предназначены.

Модуль объекта приложения. Модули этого типа всегда связаны с объектами, реагирующими на события. Главное назначение подобных модулей состоит в том, что они содержат заготовки процедур реакций на события. Так, например, в Excel модуль ЭтаКнига содержит объект workBook, с которым связаны события ОТ Activate ДО WindowResize.

Стандартный модуль. В модулях этого типа следует размещать обычные процедуры и функции. Как правило, это наиболее часто используемый тип модуля. При наличии большого количества процедур разумно иметь не один большой модуль, а несколько маленьких, содержащих процедуры и функции одной тематической направленности.

Модуль класса. Это специальный тип модуля, в котором следует размещать код пользовательских классов.



Модуль пользовательской формы. В этих модулях содержатся пользовательские формы вместе с процедурами реакции на события объектов этих форм.

И наконец, говоря о ведении проекта, нельзя не упомянуть о его сохранении. Безусловно, сохраняя весь документ приложения, вы сохраняете и проект, к нему присоединенный. Но, вообще говоря, можно сохранить проект и все изменения его кода прямо в редакторе.

Пример 20.9. Сохранение проекта

> File > Save имяПроекта

Ведение современных проектов целой командой разработчиков (или даже одним человеком) зачастую требует использования кода разных модулей, лежащих в разных проектах. В таких случаях можно воспользоваться вспомогательным инструментом VBA — экспортом и импортом модулей.

Если при работе над новым проектом А вам потребовались только одна функция или один класс, описанные в проекте в, то совсем необязательно на них ссылаться. Можно экспортировать модули из одного проекта в другой. Давайте на примере класса Person рассмотрим процедуру экспорта из проекта ciassPerson в новый проект.

Сначала мы выделяем экспортируемый модуль и сохраняем его на жестком диске в виде отдельного файла с именем, после чего импортируем этот файл в новый проект. В принципе произошло простое копирование кода из проекта в проект, но более цивилизованным методом. Кстати, следующему проекту, которому будет необходим класс Person, достаточно только импортирования уже созданного файла.

Пример 20.10. Экспорт и импорт классов

{В окне проекта CiassPerson} Person Export File...

Папка := <Диск>

Имя файла := Person

Тип файла Class Files (*.cls)

Сохранить

(В окне нового проекта}

Import File...

Папка := <Диск>

Имя файла := Person

Открыть

Аналогичным способом можно экспортировать и импортировать любые модули проекта (пользовательские модули, модули форм).

Замечание

Вспомните, что когда мы удаляем модуль из проекта, выводится диалоговое окно, предлагающее экспортировать модуль. Если модуль может оказаться вам полезен в будущем, но не нужен в данном проекте, сохраните его, нажав кнопку Да.В противном случае нажмите кнопку Нет.


Создание формы


Для создания формы необходимо перейти в режим конструктора форм.

Пример 19.1. Переход в режим конструктора форм

> Сервис > Формы > Конструктор форм...

Папки Библиотека стандартных форм (рис. 19.1)

Формы Контакт

Открыть

Рис. 19.1. Диалоговое окно Конструктор форм

Однако попутно необходимо сделать пару замечаний.

Пользователь может создавать собственные формы только на основе стандартных форм Outlook, добавляя или удаляя поля и команды.

Outlook имеет восемь стандартных форм, которые показаны на рис. 19.1. Я буду рассматривать создание пользовательской формы на основе формы Контакт. Создание форм на основе других стандартных прототипов будет аналогичным.

После открытия формы Контакт (Contact) в режиме конструктора пользователю представляется ее стандартный вид с добавленными специальными вкладками (рис. 19.2). Имена появившихся вкладок заключены в скобки, это означает, что они появляются только в режиме конструктора. Вкладки (2)—(6) являются пользовательскими, т. е. предназначены для размещения на них дополнительных элементов управления. Вкладки (Свойства) и (Команды) имеют специальное назначение, о котором пойдет речь в разделе 19.7 "Свойства формы".

Как было сказано выше, форму можно изменять, удаляя или добавляя новые поля и/или элементы управления. Для просмотра всех полей данной формы перейдите на вкладку Все поля (All Fields) и выберите значение Все поля контакта (All Contact Fields) в раскрывающемся списке Группы полей для выбора (Select From).

Рис. 19.2. Вкладка Все поля контакта в режиме конструктора форм



Создание и поручение задачи


После того как все списки инициализированы, переходим непосредственно к созданию задачи и ее поручению писателю. Оформим реализацию данной задачи в виде процедуры, которая будет вызываться нажатием клавиши Назначить задачу нашего диалогового окна.

Но прежде всего проверим, какой информацией мы будем обладать после окончания работы с диалоговым окном, а какую будет необходимо собрать дополнительно. Итак, для составления темы задачи нам достаточно серии, названия книги и автора. Для указания получателя задачи также достаточно имени писателя, поскольку Outlook автоматически соотнесет с ним адрес электронной почты. И наконец, последний параметр — длительность — хоть и получен, но не имеет смысла без установки даты начала задачи. Для разрешения этого вопроса за дату начала задачи мы примем дату ее назначения. Комментарием к задаче будет имя пользователя, создавшего поручение, — ответственного редактора.

Программа 22.6. Создание и поручение задачи

Sub AssignTask()

Dim tsk As Taskltem

tsk = Creatltem(olTaskltem)

With tsk

.Subject = series + ": " + authors + " " +title

.Body = "Ответственный редактор: " + .Owner

.StartDate = Now

.DueDate = .StartDate + duration

.Assign

.Recipients.Add authors

. Send End With End Sub

Прокомментируем эту программу. Сначала объявляется переменная — ссылка на объект Задача. После чего посредством функции createitem ей присваивается значение новой задачи. И далее планомерно заполняются поля задачи, при этом для заполнения текстовых полей используется операция сложения строк, а для задания начала задачи вызывается стандартная функция NOW. Для задания конца задачи мы прибавляем к дате старта количество месяцев, указанных в качестве продолжительности проекта.

Наша программа почти полностью готова, осталось лишь связать вызов процедуры AssignTask с реакцией на событие щелкнуть по кнопке Назначить задачу. Для этого перейдите в представление формы и дважды щелкните по кнопке, после чего автоматически откроется окно редактора кода с заглушкой процедуры — реакции на событие.


Программа 22.7. Обработчик процедуры — реакции на событие

Private Sub CommandButtonl_Click()

' Обработчик нажатия кнопки Назначить задачу

AssignTask

TaskForm.Hide

End Sub

Private Sub CommandButton2_Click() 'Обработчик нажатия кнопки Отмена

TaskForm.Hide End Sub

Комментарий здесь только один, переменная TaskForm — это имя нашего диалогового окна, чей метод Hide вызывается для закрытия. Итак, программа почти полностью готова, можно осуществить ее запуск и убедиться в ее работоспособности. После нажатия клавиши <F5>, тестового заполнения полей диалогового окна и нажатия кнопки Назначить встречу появится диалоговое окно системы безопасности Outlook. Разрешите доступ к ресурсам Outlook, после чего появится предупреждение об ошибке, изображенное на рис. 22.5.



Рис. 22.5. Диалоговое окно Microsoft Visual Basic, предупреждающее об ошибке

Его появление вызвано ошибкой в коде нашей программы, о поиске которой и пойдет дальше речь.


Создание панели пользователя


Панель пользователя практически ничем не отличается от панелей инструментов Стандартная и Дополнительно.

Рис. 22.11. Вкладка Панели инструментов диалогового окна Настройка

Пример 22.8. Создание панели инструментов

{В окне Outlook}

> Сервис > Настройка...

Панели инсрументов

Создать...

Панель инстрементов := BookTask

ОК

На рис. 22.11 изображено диалоговое окно Настройка и созданная панель Book-Task (маленький квадратик справа). Следующим шагом является добавление кнопок на панель и связывание с кнопкой вызова макроса пользователя.



Стандартные элементы управления


Элемент управления — это специальное средство графического интерфейса пользователя, предназначенное для ввода/вывода информации и управления работой программы. В Outlook, как и в других офисных приложениях, имеется четырнадцать стандартных элементов управления. Кроме того, в формах можно использовать дополнительные элементы управления OLE и ActiveX. В приведенной ниже таблице кратко описан каждый из стандартных элементов управления.

Таблица 19.1. Основные элементы управления

Название

Имя объекта

Описание

Поле со списком ComboBox

Используется либо для выбора требуемого значения из списка значений, либо для ввода его в поле

Текстовое

поле

TextBox

Используется для ввода и изменения данных,

а также для вывода результатов вычисления. Например, поле, в которое должно вводится название книги — TextBox

Надпись Label Используется для вывода в формате надписей. Данный объект обычно применяется для отображения пояснения к расположенному рядом элементу управления. Например, объект Название книги 1 — это Label

Список

ListBox

Используется только для выбора нужного значения из списка

Флажок

CheckBox

Специальная ячейка, принимающая значения Истина, если она помечена, и Ложь — в противном случае

Переключатель

OptionButton

Используется для выбора одного варианта из многих

Выключател ь

ToggelButton

Кнопка, имеющая два состояния: Включено и Выключено

Рамка

Frame

Позволяет сгруппировать элементы управления. Для создания группы следует вначале создать рамку, а потом занести в нее необходимые элементы управления

Кнопка

CommandButton

Создает кнопку, при нажатии которой выполняется команда

Рисунок

Image

Используется для вывода рисунка

Набор вкладок

TabStrip

Позволяет создать несколько вкладок в одной и той же области окна или окна диалога

Набор страниц

MultiPage

Служит для представления нескольких экранов инсрормации в виде единого набора

Полоса прокрутки

ScrollBar

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

Счетчик

SpinButton

Список, состоящий из упорядоченного набора чисел, изменяющихся с определенным шагом



Статическое заполнение списка


Начнем, пожалуй, с самого простого статического заполнения списка duration, который просто состоит из двенадцати цифр, одну из которых пользователь (редактор) должен выбрать в качестве ориентировочной длительности проекта.

Программа 22.1. Статическое заполнение списка

{На панели Project} 1R UserForml & View Code {В окне кода}

Private Sub Init_Duration() 'Инициализация списка duration With duration

For i = 1 To 12

.Addltem i Next i

.Listlndex = 0 End With End Sub

Поясним код программы. Во-первых, мы создаем процедуру, которую впоследствии будем вызывать из конструктора формы. Во-вторых, используя оператор with, обращаемся к объекту формы duration. И наконец, в цикле от 1 до 12 инициализируем список.

После того как мы создали процедуру, ее необходимо вызвать. Естественно, что все процедуры инициализации мы будем размещать в конструкторе формы — процедуре — реакции на событие initialize.

Программа 22.2. Вызов процедуры из конструктора

Private Sub UserForm_Initialize()

Init_Duration End Sub

Теперь, нажав клавишу <F5>, вы можете убедиться, что список duration инициализируется верно.



Структура программы


В предыдущих разделах мы рассмотрели те элементарные "кирпичики" (операторы и выражения), из которых строится программа. В ранних языках программирования, например в первых версиях Basic, на этом все и заканчивалось. Программа — это последовательность операторов, и все. Пока программы невелики, такой подход вполне работоспособен. Если в программе 10 операторов, то никакой дополнительной структуры не нужно. Но если в про грамме 10 000 операторов или 10 000 000 операторов (а такие программы есть, и они работают), то без введения дополнительной структуры не обойтись.

В VBA поддерживается следующая структура программы. На высшем уровне иерархии стоит приложение, далее идут проекты, связанные с фактическими документами этого приложения, на третьем уровне находятся модули (модули приложения, модули пользователя, модули класса, модули форм и модули ссылок). А на последнем уровне находятся процедуры и функции этих модулей.

Данная структуризация программ полностью, удовлетворяет принципам структурного и модульного программирования. В настоящем разделе мы подробно обсудим работу на уровне модуля, о работе с приложениями и проектами будет рассказано в разделе 20.6 "Редактор Visual Basic for Application".

Итак, модуль — это часть программы, оформленная в виде, допускающем ее независимую трансляцию. Модуль в свою очередь состоит из двух разделов: раздела объявлений (Declarations) и раздела процедур и функций. В разделе Declarations описываются глобальные переменные, типы, определенные пользователем, и перечисляемые типы. В следующем же разделе описываются процедуры и функции. Процедура — это минимальная семантически законченная программная конструкция, допускающая выполнение. В конце концов, просто так операторы не выполняются и не пишутся, они находятся в описании процедур и функций.

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

Существует три уровня видимости и пять способов объявления:


Процедура (область видимости — только та процедура, в которой переменная объявлена).

Оператор Dim объявляет переменную внутри тела процедуры и в любом месте процедуры, но до операторов, использующих ее. Время жизни данной переменной — это рамки процедуры, т. е. при входе в данную процедуру под переменную выделяется память и происходит ее инициализа ция, затем, в ходе выполнения процедуры, значение переменной может меняться, после выхода из процедуры выделенная память освобождается, и, соответственно, теряется значение переменной.

Оператор static антагонистичен оператору Dim, он объявляет статическую переменную. Разница в том, что при выходе из процедуры у статической переменной память не отбирается, а становится (в силу области видимости) временно недоступной, а соответственно, сохраняется ее значение, которым при повторном обращении к процедуре можно воспользоваться.

Модуль (область видимости — все процедуры модуля, в котором переменная объявлена):

Оператор Private объявляет переменную в разделе описаний Declarations (вне процедур модуля).

Оператор Dim абсолютно аналогичен (в данном случае) оператору Private.

Приложение (область видимости — все процедуры всех модулей активного приложения):

Оператор Public объявляет переменную в разделе описаний Declarations.

Процедуры, как и все определяемые пользователем элементы VBA, требуют объявления. Объявление процедуры имеет следующий синтаксис:

[Private | Public | Friend] [Static] Sub имяПроцедуры ([ списокАргументов ]}

[ блокОператоров1 ]

[Exit Sub]

[ блокОператоров2 ] End Sub

Ключевое слово Private задает следующую область видимости для процедуры — только модуль, в котором она описана. То есть ее могут вызывать только процедуры того же модуля. Ключевое слово Public, наоборот, объявляет процедуру доступной для всех модулей проекта. По умолчанию процедура общедоступна, т. е. имеет статус Public. Что касается использования ключевого слова Friend, то о нем мы расскажем чуть позже, когда речь пойдет о классах VBA.



После операторов объявления идет необязательное ключевое слово static, определяющее все локальные переменные статическими. Данный оператор равносилен тому, что каждая из описанных в теле процедуры- переменных объявлялась бы как static.

ИмяПроцедуры — это идентификатор процедуры, удовлетворяющий всем правилам создания имен.

После имени идут обязательные скобки, но необязательный список-Аргументов. Давайте подробнее рассмотрим объявление одного аргумента; если их больше, то они просто разделяются запятой.

[Optional] [ByVal | ByRef] [ParamArray] имя-Аргумента [()] [As типДанных] [= значениеПоУмолчанию]

Ключевое слово Optional означает, что аргумент необязателен и его можно опустить при вызове процедуры. По умолчанию аргумент обязателен. Все необязательные аргументы должны находиться после обязательных. Естественно, что необязательный параметр значениеПоУмолчанию — это значение необязательного аргумента, если он не будет задан при вызове процедуры. Если в конструкцию входит ключевое слово ParamArray, то использование ключевого слова Optional невозможно.

В качестве фактических параметров процедура может получать не только значения констант, но и значения переменных. При передаче процедуре переменных в качестве параметров может использоваться один из двух способов: ByVal (по значению) и ByRef (по ссылке).

Чтобы понять, в чем разница между этими двумя способами, нужно рассмотреть хранение и механизм передачи параметров "изнутри". Итак, при объявлении переменной какого-либо типа выделяется область в памяти компьютера, в которой будет храниться значение переменной. Размер этой области, понятно, зависит от типа этой переменной. Теперь, зная, как устроена переменная внутри компьютера, рассмотрим вопрос о передаче ее в качестве параметра в процедуру.

Если переменная передается в процедуру по ссылке (то есть с использованием перед ее именем ключевого слова ByRef), то процедуре будет передан адрес этой переменной в памяти. При этом происходит отождествление формального аргумента процедуры и переданного фактического параметра.



Тем самым вызываемая процедура, изменяя значение формального параметра, изменяет значение переменной.

Если же переменная передается по значению (то есть с использованием перед ее именем ключевого слова Byval), то компилятор создает временную копию этой переменной и именно адрес этой переменной-копии передается процедуре. Тем самым вызываемая процедура, изменяя значение формального параметра, изменяет значение переменной-копии (но не самой переменной), которая будет уничтожена после завершения работы процедуры. По умолчанию в VBA переменные передаются по ссылке.

После рассмотрения способов передачи переменных в процедуру вернемся к дальнейшему обзору ее конструкции. Следующий параметр paramArray может появиться только перед последним аргументом в списке аргументов, указывая, что он является необязательным массивом элементов типа variant.

имяАргумента — это идентификатор, составленный согласно правилам создания имен и представляющий аргумент в теле процедуры. Параметр типданных — это либо встроенный тип данных, либо тип, определенный пользователем. По умолчанию типДанкых является Variant.

После описания процедуры идет блокОператоров1 (обычно называемый телом процедуры), в котором могут быть использованы значения аргументов" процедуры. Если в ходе выполнения операторов процедуры встречается оператор Exit Sub (выход из процедуры), то выполнение процедуры прекращается и управление передается оператору, следующему за оператором вызова процедуры.

Функция отличается от процедуры тем, что помимо выполнения операторов ею возвращается некоторое значение. Синтаксис описания функции немногим отличается от процедуры:

[Public | Private | Friend] [Static]

Function имяФункции [(списокАргументов)] [As типЗначения]

[блокОператоров1]

[имяФункции = Выражение] [Exit Function]

[блокОператоров2]

[имяФункции = Выражение] End Function

Во-первых, ключевое слово sub заменено на Function. Во-вторых, после объявления аргументов следует указать тип возвращаемого функцией значения.


В-третьих, в теле функции есть присваивание имени функции какого-либо значения, имеющего объявленный тип. Конечно, подобное присваивание необязательно, но тогда ваша функция будет похожа на процедуру, а результатом функции окажется значение по умолчанию, определенное для соответствующего типа. И наконец, вместо ключевого слова Exit Sub для выхода из функции используется ключевое слово Exit Function.

Давайте на примере об издательстве и магазинах опишем процедуру инициализации массива заявок. Итак, у нас есть аргумент массива, который передается процедуре, а процедура инициализирует его с помощью стандартной функции inputBox. Для определения верхней и нижней границ массива используются стандартные функции LBound и uBound.

В случае с функцией в качестве аргументов вводится массив заявок и количество книг на складе, а возвращается логическое значение True, если удовлетворяются заявки всех магазинов, и False — в противном случае. Кстати, аргумент количество книг мы сделаем необязательным, по умолчанию равным 5000.

Программа 20.14. Объявление процедур и функций

Public Sub InitBookShops(arr() As Integer)

Dim i, str For i = LBound (arr) To UBound (arr)

str = "Ввести заказ для магазина №" & i arr(i) = InputBox(str) Next i End Sub

Public Function SaleAbility(arr() As Integer, _ '

Optional numOfBooks As Integer = 5000) As Boolean

Dim sumOfBooks

For Each elem In arr

sumOfBooks = sumOfBooks + elem Next If sumOfBooks < numOfBooks Then

SaleAbility = True Else

SaleAbility = False End If End Function

Замечание

В теле функции SaleAbility имеется сознательно допущенная нерациональность. Вместо последнего условного оператора if. . .Then. . .Else можно и нужно написать эквивалентный, более эффективный оператор присваивания SaleAbility = sumOfBooks < numOfBooks. Этим замечанием мы специально акцентируем внимание читателя на подобных мелких, но важных "хитростях" хорошего стиля программирования.

Помимо вышеописанного объявления процедур и функций, в VBA существует особый вид процедур.


Это процедуры реакции на событие, вызываемое системой или пользователем (см. главу 22 "Разработка приложения"). Например, для документов Word определены события open и close, для рабочих книг Еxcel — Beforesave и Beforedose, для объектов пользовательских классов — initialize и Terminate, нажатие кнопки диалогового окна тоже является событием и т. д. Пользователь способен сам создать процедуру реакции на подобные события, например попросить выводить сообщение "До свидания, спасибо за работу!" при закрытии документа.

Синтаксис подобной процедуры такой же, как и у обыкновенной, только в ее имени сначала указан объект, с которым будет связано событие, потом — символ подчеркивания (_), а затем — собственно имя события.

Программа 20.15. Процедура реакции на событие

Private Sub Document_Close()

MsgBox ("До свидания, спасибо за работу!")

End Sub

Замечание

Событийное управление — это способ структуризации программного кода, основанный на следующей идее. Имеется некоторое предопределенное множество поименованных событий. События могут быть явным образом связаны с объектами, а могут быть связаны неявным образом или быть связаны с неявными объектами, в последнем случае события обычно называют системными. События могут возникать. Возникновение события подразумевает, что состояние системы изменилось определенным образом. С событием может быть связана процедура, которая называется реакцией на событие. При возникновении события автоматически вызывается процедура реакции. В современных системах программирования, поддерживающих событийное управление, предусматривается большое число самых разнообразных событий, реакции на которые могут быть определены в программе, например: нажатие клавиши на клавиатуре, попадание указателя мыши в определенную область экрана, достижение внутренним таймером заданного значения, открытие заданного файла и т. д. В программе, полностью управляемой событиями, нет основного потока управления, он находится вне программы (в операционной системе или в административной системе времени выполнения, т.


е. там, где реализован механизм возникновения событий). Управление в программу попадает только в форме вызова процедуры реакции. Такая организация программы обеспечивает высокую модульность, прозрачность, сбалансированность структуры и другие полезные свойства. Понятно, что если связать события с командами приложения (как обычно и делается), то событийное управление как нельзя лучше подходит для реализации интерфейса пользователя.

Совет

В современных системах программирования имеются богатые и все время развивающиеся библиотеки готовых компонент, которые называются элементами управления (controls) и тесно интегрированы со встроенными механизмами событийного управления. Использование готовых элементов управления удобно, продуктивно и должно быть рекомендовано в большинстве случаев. Более подробная информация по этому вопросу дана в главе 22 "Разработка приложения".

Естественно, что помимо объявления процедур и функций их нужно использовать — вызывать. Существует несколько способов это сделать, причем "несколько" это очень слабо сказано. VBA предоставляет пользователю настолько гибкую систему вызова процедур и функций, что ему приходится задумываться над тем, каким из способов вызывать процедуру.

Первый, самый простой, вызов:

ИмяПроцедуры СписокФактическихПараметров

ИмяПроцедуры — это ваше Вызываемой Процедуры, а списокФактическихПара - метров — это список фактических параметров, передаваемых процедуре при ее вызове. Он должен соответствовать обязательному списку аргументов, заданному при объявлении процедуры. Фактические параметры, если их больше одного, перечисляются через запятую; их порядок обязан соответствовать объявленным аргументам. Заметьте, что при подобном вызове процедуры нет необходимости заключать список фактических параметров в скобки.

Также можно вызывать процедуру, используя ключевое слово Call: Call имяПроцедуры (СписокФактическихПараметров)

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



Вызов функции немного отличен от вызова процедур. Главное отличие в том, что можно передавать вычисляемое значение функции некоторой переменной, таким образом, вызов функции имеет следующий вид:

ИмяПеременной = ИмяФункции (СписокФактическихПараметров)

Давайте на примере вышеобъявленных процедур и функций покажем их вызов.

Программа 20.16. Вызов процедур и функций

Sub Test() .

Dim bookshops(1 To 25) As Integer Dim result As Boolean

Init bookshops

result = SaleAbility(bookshops, 3000)

MsgBox(result) End Sub

В рассмотренных способах вызова фактические параметры располагались в той же последовательности, что и формальные аргументы при объявлении процедуры или функции. В ряде случаев, особенно когда процедура содержит большое количество необязательных аргументов, можно воспользоваться уникальной возможностью VBA — именованными аргументами. При подобном вызове, кроме значения фактического параметра, указывается и имя

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

Программа 20.17. Использование именованных аргументов

Sub Test2()

Dim bookshops(1 To 25) As Integer

Dim result As Boolean

Init bookshops

result = SaleAbility(arr := bookshops, numOfBooks := 3000)

MsgBox(result) End Sub

При описании синтаксиса объявления процедуры мы вскользь упомянули ключевое слово ParamArray, настало время уделить ему достойное внимание. Возможность передавать процедуре заранее неизвестное число фактических параметров является опять-таки уникальной по отношению ко многим другим языкам программирования.

Например, мы создадим процедуру подсчета общего количества заявок с использованием параметра ParamArray. При вызове этой процедуры в процедуре Tests можно задавать сколько угодно фактических параметров массива заявок.

Программа 20.18. Использование параметра ParamArray



Sub FullSum(ParamArray arr() As Variant)

Dim sum As Integer

For i = LBound(arr) To UBound(arr) sum = sum + arr(i)

Next i

MsgBox (sum) End Sub

Sub Test3 ()

FullSum 100, 2000, 350, 450 End Sub

Рассмотрим еще один способ вызова процедур или функций — рекурсивный вызов, т. е. вызов, при котором процедура вызывается из своего же тела. Стандартный пример рекурсивной функции — вычисление факториала.

Программа 20.19. Рекурсивный вызов функции

Function fctrl(n As Integer) As Variant

If (n <= 1) Then fctrl = 1

Else

fctrl = n * fctrlfn - 1) End If End Function

Sub Test4 ()

MsgBox fctrl(20) End Sub

Как правило, рекурсивными вызовами не стоит злоупотреблять, поскольку при рекурсивных вызовах достаточно быстро заполняется стековая память компьютера и на их обработку тратится гораздо больше времени. В нашем случае можно избежать использования рекурсивного вызова его заменой на обыкновенный цикл. Хотя, безусловно, есть ситуации, когда использование рекурсивных методов заметно ускоряет работу, например при работе с древовидными структурами данных.

В заключение мы рассмотрим пример, показывающий различие между передачей параметров по ссылке и по значению, в котором приведены две процедуры: RefVal и MainCalc. Вспомогательная процедура RefVal использует три формальных аргумента, описанные по-разному. Далее в теле этой процедуры каждый из них увеличивается на единицу, а затем их значения выводятся на экран. Основная процедура MainCalc устанавливает значения переменных а, ь и с, а затем передает их в качестве параметров процедуре RefVal. При этом первый параметр передается по ссылке (по умолчанию), второй — по значению, а третий — снова по ссылке. После возврата из процедуры RefVal основная процедура также выводит на экран значения трех переменных, передававшихся в качестве параметров. Всего на экран выводится шесть значений. Сначала это числа 11, 21 и 31 (все полученные значения увеличились на 1 и выводятся процедурой RefVal). Затем это числа И, 20 и 31 (эти значения выводятся процедурой MainCalc, причем переменные, переданные по ссылке, увеличились, а переменная, переданная по значению, — нет).



Программа 20.20. Разница между ByRef и ByVal

Sub RefVal(x, ByVal у, ByRef z)

х = х + 1

у = у + 1

z = z + 1

MsgBox(х)

MsgBox(у)

MsgBox (z) End Sub

Sub MainCalc 0 a = 10 b = 20 с = 30 Call RefVal(a, b, c)

MsgBox(a) MsgBox(b) MsgBox(c) End Sub

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


Свойства формы


На неотображаемой вкладке Свойства пользователь может внести специальную информацию о данной форме. Эта информация является в своем роде справочным материалом, позволяющим понять назначение этой формы возможному пользователю.

Первые два поля Категория (Categories) и Подкатегория (Sub-Categories) разрешают присвоить форме категорию для последующего удобства в ее поиске. Например, для данной формы можно задать категорию писатель. Подкатегории позволяют организовать более мелкую сортировку форм, например, если вы создадите форму на основе сообщения для писателя, то можно создать две подкатегории контакт И сообщение.

Поля Версия (Version) и Номер формы (Form Number) служат для отслеживания изменений формы. Таким образом, разработчик формы, изменив ее и установив другой вариант версии, дает возможность пользователю формы узнать, что он работает с обновленной версией старой формы. Можно провести аналогию с версиями Windows 95 и 98, 2000.

Кнопки Изменить крупный/мелкий значок (Change Large/Small Icon) предназначены для изменения пиктограммы по умолчанию у формы пользователя.

В поле Контакт (Contact) выберите имя контакта, к которому пользователи смогут обратиться, чтобы получить сведения о данной форме. Имя контакта отображается в диалоговом окне Об этой форме меню Справка (Help), a также в диалоговом окне свойств данной формы.

Большое текстовое поле Описание (Description) служит для описания данной формы. Описание формы является небольшим справочным руководством по работе с ней.

Флажок Защитить структуру формы (Protect form design) позволяет пользователю установить пароль, необходимый для открытия и работы с формой в режиме конструктора.

Очень важен флажок Отправлять вместе с элементом (Send form definition with item). Он устанавливается, чтобы вместе с элементом включить все сведения, которые понадобятся другим пользователям при работе с соответствующей формой. При сбросе флажка макет формы удаляется из элемента и может использоваться в библиотеке форм, что позволяет уменьшить размер элемента.


И наконец, последний флажок Использовать только для ответов (Use form only for responses). При установленном флажке данная форма будет использоваться только для ответов на сообщения, например при выборе команд Ответить (Reply), Ответить всем или Переслать, при этом она не включается в библиотеку форм. Тип ответа, для которого используется форма, задается в диалоговом окне свойств команд формы.
На рис. 19.9 изображена заполненная вкладка Свойства формы Контакт.

Рис. 19.9. Вкладка Свойства формы Контакт

Свойства элементов управления


Как и все прочие объекты Visual Basic, элементы управления имеют свои свойства и методы. Например, флажок является объектом класса checkBox и имеет свойства, которые определяют, в частности, имя этого объекта (Name) — то имя, под которым этот флажок будет известен в модуле Visual Basic; его надпись (Caption) — текст, располагающийся справа от флажка; связанную с этим флажком клавишу быстрого вызова (Accelerator) — одну из букв

Щелчки нужно делать с некоторым интервалом, чтобы не получился так называемый двойной щелчок: такой щелчок используется для перехода к окну ассоциированных с этим управляющим элементом процедур обработки событий, надписи, которая будет подчеркнута (при нажатии на соответствующую клавишу на клавиатуре будет изменяться текущее состояние флажка); его начальное значение (value) — определяющее, установлен или снят этот флажок; а также другие свойства. Однородные объекты образуют семейство соответствующих элементов управления, имеющее специальное название в Visual Basic, например семейство CheckBoxes представляет собой совокупность всех флажков в диалоговом окне.

Иногда возникает необходимость изменять некоторые свойства элементов управления диалогового окна программным путем, непосредственно во время работы приложения: с помощью процедуры инициализации — перед тем, как открыть диалоговое окно; в результате действий пользователя — в то время, как окно открыто, или же сразу после его закрытия. Кроме того, свойства элементов управления могут быть установлены заранее, статически, во время проектирования диалога. Делается это с помощью панели свойств, обычно располагающейся в левом нижнем углу окна Visual Basic 2 .

Обратите внимание, что на этой панели имеются две вкладки — Alhabetic и Categories. Обе они показывают одни и те же свойства — только на первой вкладке эти свойства располагаются в алфавитном порядке, а на второй вкладке они сгруппированы в несколько категорий, состав которых зависит от конкретного элемента управления. 'Вот основные категории, которые присутствуют почти для всех элементов управления: Вид, Данные, Поведение, Размещение, Разное и Шрифт. Обычно разыскивать нужное свойство удобнее, используя представление по категориям.


Например, все надписи в диалоговом окне, а также и само диалоговое окно, имеют свойство caption. Можно изменять текст надписей с помощью панели свойств, и при этом изменить это свойство для самого диалогового окна можно только таким способом. Вот как это делается:
Пример 22.4. Определение названия диалогового окна
{все диалоговое окно целиком — щелчком по свободному месту} Caption := Задача: Написание книги
Большинство свойств различных элементов управления можно установить статически только с помощью панели свойств. А некоторые свойства, например расположение и размеры, которые устанавливаются обычно с помощью мыши, не мешает проверить с помощью этой панели (рис. 22.3).
Ниже мы продемонстрировали установку свойств для объекта image (указывается путь до картинки и способ ее отображения), объекта comboBox
Если панель свойств не отображается, открыть ее можно с помощью нажатия на клавишу <F4> или с помощью команды > Вид > Окно свойств.
(отмена возможности редактирования текстового поля раскрывающегося списка, т. е. пользователь может только выбирать существующие элементы) и объекта EditBox (устанавливается максимальное число вводимых символов).
Пример 22.5. Установка свойств для элементов управления
ComboBoxl
Name := series
Style 2-fmDropDownList
ComboBox2
Name := author
Style 2-fmDropDownList
EditBox
Name := title MaxLength := 50
ComboBoxS
Name := duration
Style 2-fmDropDownList



Рис. 22.3. Панель свойств для раскрывающегося списка

Типы данных


Как мы уже отмечали, язык — это знаковая система для передачи информации. Когда же мы говорим о языке программирования, то подразумеваем под информацией строго определенное понятие. В данном случае информация — это данные и процедуры их обработки. В этом разделе мы коснемся только первой части настоящего определения, а именно данных.

Данные в VBA характеризуются своими типами, которые определяют:

формат представления данных в памяти компьютера;

область возможных значений;

множество допустимых операций, применимых к данным.

В свою очередь типы данных делятся на простые (встроенные и определяемые) и на структурные, именно в таком порядке мы и будем их описывать.

Итак, начнем с встроенных типов данных. Как и любой язык программирования высокого уровня, VBA содержит все привычные встроенные типы данных: арифметические, строковые и логические, но есть и свои типы, специфические для VBA. Полный перечень встроенных типов данных VBA с соответствующими областями значений и требуемой памятью приведен в табл. 20.2.

Таблица 20.2. Встроенные типы данных VBA

Тип данных

Описание

Область значений

Требуемая память

Boolean

Логическое значение

True (Истина) и

2 байта



False (Ложь)


Byte

Число без знака

0-255

1 байт

Currency

Десятичные числа с фиксированным количеством знаков после запятой

-922 337 203 685 477,5808 - 922 337 203 685 477,5807

8 байтов

Date

Используется для хранения дат

1.01.0100г.-31.12.9999г.

8 байтов

Decimal

Любое число

28 знаков

12 байт

Double

Числовые значения с пла-

-1.7Е308--4.9Е324

8 байтов


вающей точкой двойной точности

для отрицательных чисел и 4.9Е324 —




1 ,7Е308 для положи-




тельных чисел


Тип данных

Описание

Область значений

Требуемая память

Integer

Короткие целые числовые

-32 768 - 32 767

2 байта


значения



Long

Длинные целые числовые

-2 147483648-

4 байта


значения

2147483647


Object

Ссылка на объект


4 байта

Single

Числовые значения

-3.4Е38--1.4Е45

4 байта


с плавающей точкой обыч-

для отрицательных



ной точности

чисел




и 1.4Е-45-3.4Е-45


String

Используется для хранения строковых значений

для положительных

Длина строки от 0 до 64 Кбайт

1 байт на символ

Variant

Может использоваться

Значения любого

16 байт плюс


для хранения всех вышеперечисленных типов

из вышеперечисленных типов плюс Null, Error, Empty, Nothing.

1 байт на каждый символ строковых зна-




чений

<
Если такие типы данных, как integer или string не требуют особых комментариев, поскольку они стандартны и просты, то типы данных object и variant следует прокомментировать. Про тип данных object мы отдельно поговорим в разделе 20.5 "Классы и объекты", сейчас же рассмотрим уникальный в своем роде тип Variant.

Тип variant — это универсальный тип данных, позволяющий программисту не думать о том, каким будет тип переменных. С одной стороны, безусловное удобство: не надо думать при объявлении переменной, с другой — это может привести к ошибкам, которые трудно обнаружить. Более того, на обработку переменных данного типа тратится больше времени, да и память расходуется нерационально (особенно, когда речь идет о статических массивах данного типа).

Мы советуем (особенно начинающим программистам) не злоупотреблять данным типом, хотя ряд приемов его использования заметно упрощает программирование. Например, вы хотите, чтобы пользователь программы ввел целое число (после чего программа нарисует круг соответствующего радиуса) и переменную ввода целого типа. Но что, если пользователь введет вместо целого числа вещественное или, вообще, строковое значение? Произойдет ошибка при попытке присвоения переменной значения не того типа.

Вот тут-то и необходим тип Variant. Если переменная для ввода будет объявлена как variant, ничего страшного не случится: введенное значение бу дет благополучно присвоено этой переменной, а вы получите возможность проанализировать введенное значение и попросить пользователя повторить ввод, если введенное им значение не отвечает требуемым условиям. Теперь перейдем к разговору о третьей составляющей нашего определения типа данных, об операциях. Операция — это действие, выполняемое над данными.

[Результат =] операнд! <операция> операнд2

Любая операция имеет результат и несколько операндов (как правило, два). Операнд — это элемент данных, участвующий в операции. Для каждой операции определены типы данных операндов, для которых она имеет смысл и по которым определяется тип результата.


Естественен вопрос: по какому именно правилу определяется тип результата, ведь в качестве операндов могут быть операнды разных типов? Для ответа на этот вопрос необходимо ввести определение приведения. Приведение — это (автоматическое) преобразование значения одного типа в эквивалентное значение другого типа. Конечно, не всякое приведение возможно, т. е. не всегда можно сделать именно эквивалентное преобразование. Например, целое число 3 можно преобразовать в вещественное число 3.0 и значение сохранится, но вещественное число 3.1415926 нельзя преобразовать в целое, не потеряв информацию. Таким образом, учитывая приведения типов, можно однозначно определять тип результата операции по следующему правилу: если операция применяется к операндам различных типов, то операнд, у которого порядок типа ниже, преобразуется к типу операнда, у которого порядок выше и значение операции будет иметь, соответственно, тип высшего порядка. Существует четыре вида операций:

Арифметические (+, - ,*, \, /, ^, mod).

Логические (not, and, or, xor, eqv, imp).

Строковые (+,&).

Операции отношения (=, <>, <, >, <=, >=, Is, Like).

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

Переменная — это элемент данных в программе, которому присвоено имя Значение переменной может задаваться и изменяться программой (переменная — не константа), но в соответствии с определенным типом данной переменной, который задается при ее объявлении. При объявлении задается имя (для идентификации переменной в программе), затем объявляется ее тип (для определения возможных значений переменной и способов ее обработки), а также определяется область видимости этой переменной.



Явное объявление простых переменных имеет следующий синтаксис:

{ Dim I Private | Public | Static } имя Переменной [As <типДанных>] [, имяПеременной [As <типДанных>]} ...

Рассмотрим первую часть объявления — объявление области видимости переменной при помощи соответствующих ключевых слов. К сожалению, что такое область видимости переменной и время ее жизни, нельзя объяснить без специальных понятий и определений, которые будут приведены в разделе 20.4 "Структура программы". Поэтому мы не будем подробно останавливаться на этом вопросе, кроме разве мелких замечаний. Более того, данные ключевые слова несут локальную нагрузку на семантику конструкций и их пропуск при описании ни на чем не скажется.

Следующая часть объявления — это имя переменной. Правила составления имен уже достаточно подробно обсуждались в разделе 20.1 "Общие сведения", и мы не будем еще раз останавливаться на этом.

И наконец, последнее, что необходимо сделать при явном объявлении переменной, — указать ее тип, используя ключевое слово Аs, после которого идет ключевое слово, определяющее тип данных, например integer.

Помимо явного способа объявления переменной, существуют и неявные. Во-первых, можно непосредственно в имени переменной указать ее тип, добавив в конец имени специальный символ (например, $ — строка). А во-вторых, можно вообще не использовать операторы объявления, а при необходимости прямо на месте неявно вводить переменную. Например, можно сразу написать оператор d = 5. В данном случае не было предварительного (явного) объявления переменной, но все-таки она будет проинициализиро-вана. Дело в том, что по умолчанию VBA расценивает данную переменную как нестатическую типа variant. Приведем теперь программу объявления переменных.

Программа 20.3. Объявление переменных j

Dim str As String, Var = 123.456

Dim str$, k&

Кстати, помимо явной инициализации переменных, например pi = 3.14, существует инициализация по умолчанию. То есть, когда вы объявляете переменную и не инициализируете ее, ей присваивается значение по умолчанию, так, например, для числовых типов это значение равно 0.



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

[Public I Private] Const имяКонстанты [As ТипДанных] = выражение

Ключевые слова Public и Private имеют такой же смысл, как и в случае с переменными. Отсутствие этих ключевых слов и описание константы внутри процедуры объявляет ее как локальную, использование же их, наоборот, объявляет ее как открытую или закрытую глобальную константу. Задание имени и типа данных аналогично случаю с переменными.

Выражение — это любое значение или формула, возвращающая значение, используемое в качестве константы. Например, мы хотим ввести константу, значением которой будет площадь — const squares = 20000. Или в виде формулы (зная длину и ширину):

Const lengths = 200

Const widths = 100

Const squares = length*width

Совет

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

В VBA, кроме констант, описываемых пользователем, существуют предопределенные встроенные константы. При именовании встроенных констант используется стандартное соглашение, позволяющее определить, к объектам какого приложения относится эта константа. Например, встроенные константы, относящиеся к Word, начинаются с букв wd, Excel — ex, PowerPoint — pp, Access — ac, VBA — vb. Например, в случае

Call Msgbox ("Использование констант", vblnformation)

используется константа vblnformation, с помощью которой в диалоговом окне выводится значок "Информация" (рис. 20.2).



После того как выше мы описали работу с простыми типами данных, перейдем к рассмотрению более сложных — структурных типов данных. Сейчас мы рассмотрим простейший из них — массивы.

Массив — это совокупность однотипных индексированных переменных Представьте, что имеется 20 магазинов, которым издательство поставляет книгу "Microsoft Outlook 2002 в подлиннике". Естественным образом хоте лось бы иметь список, в котором было бы указано количество экземпляров, проданных каждому магазину. Данные количества для разных магазинов являются, в принципе, элементами одного типа (а точнее, просто числами). Таким образом, данная совокупность представляет собой массив. Обращение же к элементам массива происходит путем указания имени данного массива и порядкового номера требуемого элемента. Конечно, вы вправе присвоить каждому магазину персональное имя и работать с ними, как с обособленными единицами. Но представьте, что вам надо провести одну и ту же процедуру для каждого магазина, например подсчитать общее количество проданных книг. Не проще ли задать цикл для всего массива магазинов, где изменяется лишь индекс, который однозначно определяет магазин?

Количество же индексов массива в VBA может достигать 60, но это своего рода излишество, как правило, используются массивы с одним, двумя и тремя индексами. О количестве индексов массива говорят как о размерности массива. Массивы с одним индексом называют одномерными, с двумя — двумерными и т. д. Продолжив наш пример, предположим, что издательство выпускает не одну книгу, а множество различных книг, скажем, еще 100. Таким образом, вы имеете дело с двумерным массивом (20x100) и обращение к необходимому элементу становится тривиальным: магазин № 7 книга № 56. Данное обращение покажет количество проданных книг № 56 магазину № 7. Конечно, в языке VBA подобные выражения неприемлемы, но суть остается той же. Как и любой элемент данных, массив необходимо объявлять. Ниже приведен синтаксис объявления массива:

{ Dim I Private | Public | Static} имяМассива (<размер1> [, <размер2>] ...) [Аs типДанных] [, имяМассива (<размер1> [, <размер2>] ... ) [As типДанных]]



Итак, опять мы встречаем знакомые конструкции — операторы объявления массива и имя массива. Размер массива может задаваться тремя способами.

Объявляется только верхняя граница, при этом нижняя граница по умолчанию принимает значение, равное 0. Синтаксис подобного объявления прост: { верхняяГраница}

Объявляется нижняя и верхняя граница изменения индекса: (нижняяГраница То верхняяГраница)

Размер массива вообще не объявляется, размерность массива неизвестна: ( )

Приведем ряд примеров, поясняющих использование синтаксических конструкций. В первом из них объявляется одномерный массив типа variant с использованием ключевого слова Dim, причем индексация производится от -14 до — 1. Данная индексация имеет смысл, например, в случае с метеорологическими данными, представляющими средние дневные температуры за последние две недели. В таком случае temperature (-2) будет соответствовать позавчерашней температуре. Во втором примере показано объявление двумерного массива магазинов с использованием константных аргументов, и инициализация элемента (7, 56).

Программа 20.4. Объявление массивов

{Первый пример}

Dim temperature( - 14 То -1)

temperature(-2) = -10

{Второй пример}

Const numbShop As Integer = 20, numbBook As Integer = 100

Dim numbBookSale (1 To numbShop, 1 To numbBook) As Integer

numbBookSale(7, 56) = 300

В приведенных примерах речь все время шла о массивах фиксированного размера, количество элементов в которых явно указано во время описания в операторе Dim. Такие массивы называются статическими. Но иногда количество элементов массива изначально не известно. Например, вы не знаете точного количества магазинов (возможно, появятся еще несколько магазинов, с которыми издательство будет сотрудничать). Как быть? Не стопорить же сбыт продукции до выявления конечного числа магазинов.

Для решения подобных проблем VBA предлагает использование динамических массивов, т. е. массивов, размеры и количество элементов которых при описании не фиксируются, но могут быть определены непосредственно при выполнении программы.


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

ReDim имяМассива (размер1[, размер2 ...])

При всем обилии встроенных типов данных часто возникает желание ввести новый тип данных, содержащий некоторые определенные значения. Такой тип называется в VBA перечисляемым. Мы поясним перечисляемые типы на следующем, довольно характерном, примере.

Мы хотим ввести тип "неделя". Элементами данного типа будут только обозначения дней недели, и, соответственно, область значений будет изменяться от понедельника до воскресенья.

[Private | Public] Enum имяTипа

имяЗначения [ = Константа] имяЗначения [ = Константа]

End Enum

Синтаксис довольно прост. Операторы Private и Public объявляют область видимости для типа (кстати, перечисляемые типы могут описываться только на уровне модуля, т. е. нельзя описать перечисляемый тип внутри процедуры). Затем следует ключевое слово Enum и имятипа, после чего — перечисление значений типа (по одному на строчке). По умолчанию все значения типа перенумеровываются целыми числами, начиная с 0, но вы можете самостоятельно указать константное целое значение для значений типа.

Программа 20.5. Объявление перечисляемого типа

Enum Week

Monday

Tuesday

Wednesday

Thursday

Friday

Saturday

Sunday End Enum

Sub Weekend()

Dim day As Week

Day = Saturday End Sub

После описания простейшего структурного типа данных (массива) перейдем к более сложному типу, а точнее, к типу, определяемому пользователем. В то время как массив представляет собой совокупность однотипных переменных, хотелось бы создать объединение элементов разных типов (запись).

Например, мы могли бы описать человека при помощи массива целых чисел: Dim Person () As Integer, где Person (1) задает рост, Person (2) — Вес, Person(3) — объем грудной клетки и т.


д. Но это все элементы одного типа integer, а как же быть когда мы захотим определить не менее важный па

раметр человека — его имя, имеющее тип string, или дату рождения типа Date? Решением является создание записи. В нашем случае это будет выглядеть следующим образом: мы создаем пользовательский тип данных Person, элементами которого являются значения разных типов. Обращение же к таким переменным строится следующим образом: Person->Weight или Person->Name

Конечно, перечисляемый тип тоже определяется пользователем, но это простой тип данных.

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

[Private |Public] Type имяТипа

имяПоля [([<размер>]}] As типДанных [имяПоля [ ( [<размер>] ) ] Аs типДанных]

End Type

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

Для тех, кого последнее предложение заставило задуматься, небольшое пояснение. Определение записи можно рассматривать как дерево. Корень — это имя типа, а вершины — имена полей, которые могут являться корнями подобного же дерева. Не допускается использование рекурсивных определений, т. е. нельзя объявить тип следующим образом:

Туре Заяц

Волк Аs Заяц

End Type

В приведенной ниже программе мы объявляем тип Person, имеющий поля name (имя) и birthday (дата рождения) простых типов. Далее мы объявляем тип Book, имеющий поле author определенного выше типа Person, поле title (название книги) типа string и поле content (названия глав книги), представляющее собой динамический массив типа string.


После объявления типов мы объявляем одномерный массив типа Book и полностью инициализируем второй элемент массива, используя для доступа к полям записей точечную нотацию. Небольшой нюанс при инициализации поля content: поскольку это динамический массив, его необходимо переопределить. В конце просто выводится название одной из глав книги.

Программа 20.6. Объявление типов

Public Type Person

name As String

birthday As Date End Type

Public Type Book

author As Person

title As String

content () as String End Type

Sub TypeExample()

Dim arrBook(l) As Book

arrBpok(1).author.name = "Федор Новиков"

arrBook(l).author.birthday = #10/10/1951#

arrBook(l).title = "Microsoft Office 2001 в целом"

ReDim arrBook(1).content(0 To 1)

arrBook(1).content(0) = "Введение"

MsgBox (arrBook(1).content(0)) End Sub


Вкладка Оформление


На этой вкладке задаются параметры оформления объекта (рис. 14.4).

В поле Имя (Name) задается внутреннее название объекта. По умолчанию объекту присваивается название с порядковым номером (Поле со списком 1). Если добавляется еще один объект того же типа, ему присваивается имя с номером 2 и т. д. Например, для раскрывающегося списка задано имя Переплет.

Поле Заголовок (Caption) служит для введения информации, визуально отождествляемой с элементом Так, например, для элемента управления Надпись (Label) задан заголовок переплет.

В разделе Положение (Position) определяется местоположение объекта на форме. Поля сверху (Тор), слева (Left) определяют положение верхнего левого угла объекта, а высота (Height), ширина (Width), соответственно, высоту и ширину объекта. Пользователь может задавать положение объекта как численно, так и перемещая его и изменяя границы на самой форме.

В разделе Шрифт и цвет (Font and Color) выбираются настройки шрифта, а также указываются параметры его отображения в форме (цвет текста и цвет фона).

Рис. 19.4. Вкладка Оформление диалогового окна Свойства

В разделе Настройки (Settings) указываются дополнительные параметры объекта:

видимое (Visible). Отображение элемента управления на странице. Чтобы его скрыть, сбросьте флажок.

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

только чтение (Read Only). Возможность выделять и копировать содержимое элемента управления без сохранения внесенных в него изменений.

изменяет размер вместе с формой (Resize with form). Определение размера элемента управления относительно размера формы. Например, при уменьшении размера формы элемент управления также уменьшается.

объемное (Sunken). Придание элементу управления объемного вида.

многострочное (Multi-line). Разрешение вводить в текстовое поле текст, состоящий из нескольких строк. При нажатии клавиши <Enter> создается новая строка.



Вкладка Значение


На этой вкладке происходит связывание элемента управления с полем формы. То есть, размещая на форме элемент управления, мы создаем лишь заглушку, не имеющую отношения к форме. Определяя для элемента управления поле, его формат и допустимые значения, мы наполняем его смыслом. Как и в случае с предыдущими полями, Outlook не имеет встроенного поля переплет, поэтому его необходимо создать.

Рис. 19.5. Вкладка Значение диалогового окна Свойства

Пример 19.5. Связывание элемента управления с полем Outlook

Создать

Имя := Переплет

Тип Текст

ОК

Тип списка Раскрывающийся список

Возможные значения := Мягкий; Твердый

Установить начальное значение поля := Мягкий (рис. 19.6)

Помимо типа Текст (Text) существует еще десять стандартных типов данных. В табл. 19.2 приведены названия типов данных и их описание.

Таблица 19.2. Стандартные типы полей

Тип данных

Описание

Текст (Text)

Текст (буквы, цифры, специальные знаки). Может содержать до 255 символов

Число (Number)

Числовые данные или математические вычисления, не включающие денежные суммы

Процент (Percent)

Числовые данные, выраженные в процентах

Денежный (Currency)

Числовые данные денежного типа или математические вычисления с участием денежных сумм

Да/Нет (Yes/No)

Данные, принимающие одно из двух значений: Истина или Ложь

Дата/время

(Date/Time)

Значения дат и времени

Длительность

(Duration)

Числовые данные. Длительность задается в минутах, часах или днях

Ключевые слова

(Keywords)

Данный тип используется для группировки и поиска родственных элементов, аналогично категориям Outlook

Выражение

(Combination)

Комбинация значений полей и текста

Формула (Formula)

Вычисления с участием стандартных полей и полей пользователя

Целое число (Integer)

Целочисленные данные

Посредством кнопки Выбрать поле (Choose Field) можно выбрать поле из уже имеющихся. Возможные значения списка вводятся через запятую или точку с запятой. Рассмотрение действий, связанных с кнопкой Изменить (Edit) и группой переключателей Вычислять выражение (Initial Value), отложим до следующего раздела.

Замечание

Параметры вкладки Проверка (Validation) также будут рассмотрены ниже, поскольку они тесно связаны с работой над формулами.



Вычисления в форме


В некоторых случаях требуется добавить в форму специальные поля. Например, поле, в котором вычислялось бы значение по определенным формулам на основе заданной пользователем информации.

Примером такого поля для нас будет служить последнее поле нашей формы — общее количество страниц, ведь его значением является сумма значений всех полей кол-во страниц 1 — Кол-во страниц з. Для создания данного поля воспользуемся панелью Выбор поля (Field Chooser).

Совет

Если вам необходимо создать текстовое поле с надписью, то гораздо удобнее использовать панель Выбор поля, нежели панель Toolbox (то есть создать два элемента управления и для каждого задать свойства). В качестве примера на закрепление пройденного материала попытайтесь создать то же поле, только посредством панели Toolbox.

Пример 19.7. Создание вычисляемого поля

{Панель Выбор поля}

Создать

Имя := Общее количество страниц

Тип Формула

Изменить... (рис. 19.7)

Поле > Поля пользователя в папке > Кол-во страниц1

(Ввести знак "+" и повторить для случая 2 и 3)

ОК

Рис. 19.7. Диалоговое окно Поле формулы

Помимо стандартных функций сложения (+), вычитания (-), умножения (*) и деления (/), можно задавать и более сложные из набора встроенных функций Outlook. Существует шесть типов функций.

Преобразования (Conversion). Данный набор функций служит для преобразования выражений одного типа в выражения другого. Например, Oct (число) переводит число из десятичного формата в восьмеричный.

Дата/время (Date/Time). Функции для работы с датой и временем. Например, Date () возвращает текущую дату и время компьютера.

Финансовые (Financial). Набор функций для финансовых расчетов. Функция SLN (стоимость, остаточная_стоимость, время_эксплуатации) , на-пример, вычисляет обесценивание актива в течение единичного периода по линейному закону.

Общие (General). Набор специальных функций, необходимых для построения формул с разветвленной структурой. Например, iif (выражение, еслиистина, еслиложь» возвращает одно значение, если указанное выражение истинно, и другое, если — ложно.



Математические (Math). Набор формул для математических вычислений. Например, cos (число) возвращает косинус числа.

Текстовые (Text). Функции для работы с текстом и строками. Например, Len (строка) возвращает количество символов в строке.

После создания поля с формулой и добавления его на форму выделите поле и откройте диалоговое окно Свойства, а затем перейдите на вкладку Значение (Value). В разделе Начальное значение (Initial Value) установите переключатель Вычислять выражение автоматически (Calculate this formula automatically), что позволит автоматически вычислять сумму при изменении значений полей кол-во страниц.

Помимо этого, для поля можно задать дополнительные параметры проверки. Для чего перейдите на вкладку Проверка (Validation) диалогового окна Свойства (рис. 19.8).



Рис. 19.8. Вкладка Проверка диалогового окна Свойства

Пример 19.8. Установка дополнительных параметров проверки

Проверить это поле перед закрытием формы

Формула проверки

Изменить...

Поле > Поля пользователя в папке >Общее кол-во страниц

Ввести "> 0"

ОК

Вывести сообщение := Значение поля "Количество страниц" не может быть отрицательным

ОК


Вызов макросов


Итак, наше приложение готово, но удобно ли им пользоваться? Где та легкость и удобство в работе, заявленные в начале данной главы? Естественно, что конечного пользователя не устроит запуск редактора VBA и выбор команды > Run > Run SubXUserForm.

Одним из удобных средств, помогающих в вызове процедур, являются кнопки на панели инструментов Outlook. В этом разделе мы рассмотрим создание панели пользователя и добавление на нее кнопки, вызывающей процедуру пользователя.

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

Пример 22.7. Функция запуска приложения

{В редактор VBE} > Insert > Modules

Name := AssignTask (В редактор VBE} Sub GenerateTask() UserForm.Show End Sub

Теперь все готово к созданию панели и кнопки пользователя.



Взятие данных из Outlook


В предыдущей программе мы заполняли список динамически, считывая данные из файла. Переходя к инициализации списка авторов, отметим, что эта информация также способна динамически изменяться, но в отличие от серии книг, информация о писателях (по условиям задачи) хранится в Outlook, более того, условимся, что она хранится в отдельной папке Writers, являющейся подпапкой папки Contacts. Тогда процедура инициализации будет выглядеть следующим образом.

Программа 22.5. Инициализация данных из Outlook

Sub Init_Authors()

Объявление переменных

Dim nms As NameSpace

Dim fldContacts As MAPIFolder

Dim itms As Collection

Dim itm As Integer

Создание объекта, указывающего на данные Outlook

Set nms = Application.GetNamespace("MAPI") 'Создание объекта, указывающего на папку Контакты

Set fldContacts = nms.GetDefaultFolder(olFolderContacts) 'Присваеваем объекту значение подпапки Writers

Set fldContacts = fldContacts.Folders("Writers") 'создание объекта (семейство), содержащего все элементы папки Контакты

Set itms = fldContacts.items 'Организация цикла по всем контактам в папке

For itm = 1 То itms.Count

With itms(itm) 'Инициализация списка именами контактов

authors.Addltem .LastNameAndFirstName .End With

Next

authors.Listlndex = 0 End Sub

Итак, прежде всего, мы объявляем ряд переменных, после чего получаем ссылку на папку с контактами и организуем цикл по всем ее элементам. Как видите, все достаточно просто.