Текст
                    ПРОГРАММИРОВАНИЕ НА
VBA 2002
В.Г. Кузьменко
ПРОГРАММИРОВАНИЕ НА
VBA 2002
Москва
ЗАО «Издательство БИНОМ»
2003
УДК 004.43
ББК 32.973.26-018.1
К89
Кузьменко В.Г.
Программирование на VBA 2002. — М.: ООО «Бином-Пресс», 2003 г. — 880 с.: ил.
В книге содержится курс по программированию на Visual Basic for Applications (VBA), являющимся базовым языком в приложениях Microsoft Office (Word, Excel, Access, PowerPoint, FrontPage, Visio и др.). Книга предназначена для начинающих программировать в среде Windows с применением Word-, Excel-, PowerPoint-объектов.
Часть книги посвящена вопросам разработки Office-приложений, использующих базы данных, хранимых как в отдельных файлах, так и на удаленных серверах.
Материала книги достаточно для изучения основ языка Visual Basic и создания простых макросов, помогающих автоматизировать рутинную повторяющуюся работу с документами, электронными таблицами, диаграммами, презентациями и т.д., а также для разработки довольно сложных приложений обработки баз данных с использованием диалоговых окон, обеспечивающих пользователя самыми современными интерфейсными средствами.
Большинство примеров в книге посвящены актуальным в настоящее время вопросам коммерческой деятельности, поэтому книга будет очень полезной менеджерам различных уровней, которым, по-видимому, и предназначен как Microsoft Office, так и встроенный язык программирования VBA.
Приложения в конце книги могут послужить удобным справочником при работе как с VBA, так и с обычным VB.
ISBN 5-9518-0039-0
© Кузьменко В.Г., 2003
© Издательство БИНОМ, 2003
Содержание
Введение.................*...............................................21
Часть I. Язык программирования Visual Basic..............................23
Глава 1. Макросы и языки программирования................................24
Макрос и макрорекордер.................................................24
Из истории VBA........................................................25
Зачем изучать язык программирования VBA...............................27
Создание макросов.....................................................28
Создание макроса в Word..............................................28
Создание макроса в PowerPoint........................................30
Запись новых макросов.................................................32
Задание стартовых условий для макроса................................33
Запуск макрорекордера и присваивание имени макросу...................33
Запись макроса в Word 2002.......................................... 35
Задание стартовых условий..........................................35
Присваивание имени макросу и выбор	места для его сохранения........36
Использование панели инструментов и клавиатуры для запуска макроса .... 36
Запись ваших действий..............................................37
Остановка макрорекордера...........................................38
Запись макроса в Excel 2002......................................... 38
Задание стартовых условий..........................................39
Назначение имени и выбор места для сохранения макроса..............39
Запись действий....................................................40
Остановка макрорекордера...........................................42
Код макроса...........................................................42
Выполнение макросов...................................................45
Примеры записи более полезных	макросов................................46
Оформление замечаний.................................................47
Подписи к рисункам...................................................47
Подчеркивание листинга...............................................49
Макрос-шутка..........................................................49
Глава 2. Среда Редактора Visual Basic....................................52
Модули................................................................52
Модули в Word 2002 ................................................. 52
Модули в Excel 2002 ................................................ 52
Модули в PowerPoint 2002............................................ 53
Редактор Visual Basic.................................................53
Запуск Редактора VB................................................  53
Окна Редактора VB....................................................54
Меню Редактора VB....................................................56
Меню Файл (File)...................................................56
Меню Edit (правка).................................................57
- Меню View (Вид)...................................................58
Меню Insert (Вставка)..............................................59
Меню Format (Формат)...............................................60
Меню Debug (Отладка)...............................................61
Меню Run (Запуск)..................................................62
Меню Tools (Сервис)................................................63
Меню Add-Ins.......................................................63
Другие меню........................................................63
6
Программирование на VBA 2002
Знакомство с панелями инструментов Редактора VB........................64
Панель инструментов Standard.........................................65
Панель инструментов Edit (правка)....................................66
Глава 3. Редактирование простых макросов.................................68
Редактирование макросов.................................................68
Отображение модуля.....................................................68
Как найти записанный макрос............................................69
Использование инструмента Object Browser...............................69
Просмотр модулей проекта с помощью Object Browser....................70
Составные части записанного макроса..................................72
z Редактирование текста макроса...........................................74
Символ продолжения строки VBA.......................................76
Перемещение или копирование макроса из одного модуля в другой.......77
Сохранение и перенос модулей как текстовых	файлов......................78
Экспортирование модулей..............................................78
Импортирование модулей...............................................79
Удаление модулей из проекта............................................80
Написание новых макросов и процедур....................................81
Вставка и переименование модуля.......................................81
Выделение существующего модуля........................................82
Написание текста процедуры.............................................82
Свойство Auto-Indent (автоотступ)...................................84
Запуск процедуры во время редактирования...............................85
Отображение сообщений для пользователя процедуры......................85
Сообщения об ошибках во время написания, редактирования или выполнения процедуры................................86
Ошибки синтаксиса......................................................87
Ошибки времени исполнения.............................................88
Печать исходного кода.................................................90
Глава 4. Типы данных, переменные и константы.............................91
Обзор типов данных Visual Basic.........................................91
Экспоненциальное представление........................................93
Тип Date...............................................................93
Числа.................................................................94
Типы данных Byte, Integer и Long.....................................94
Числа с плавающей точкой............................................95
Тип данных Currency..................................................96
Текстовые строки......................................................96
Логические значения..................................................96
Тип данных Variant....................................................97
Переменные..............................................................97
Что такое переменная?.................................................97
Выбор имен для переменных.............................................98
Идентификаторы......................................................98
Создание переменных....................................................99
Задание типа данных переменной.......................................101
Использование Dim для объявления типизированных переменных.........102
Использование символов определения типа для объявления типизированных переменных..........................................103
Использование Dim для объявления строковых переменных фиксированной длины................................................104
Область действия: доступность переменных.............................104
Область действия процедурного уровня...............................104
Область действия модульного уровня.................................105
Использование переменных с одним и тем же именем в различных уровнях области действия...............................106
Содержание
7
Персистенция: Определение того, как долго переменные удерживают свое значение...........................................107
Требование явного объявления переменных............................108
Константы ........................1.................................110
Создание именованных констант......................................110
Область действия констант..........................................111
Написание литеральных констант.....................................112
Константы String.	 112
Численные константы..............................................112
Константы Date...................................................113
Константы Boolean................................................113
Задание типа константы.............................................113
Внутренние константы...............................................114
Поиск имеющихся внутренних констант с помощью Object Browser.....115
Получение данных от пользователя....................................116
Глава 5. Выражения в Visual	Basic.................................118
Совместимость типов данных..........................................119
Автоматическое преобразование данных Visual Basic..................120
Преобразования численных типов.....................................121
Преобразования строк и чисел.......................................121
Преобразования значений типа	Boolean...............................122
Преобразования значений типа	Date..................................122
Оператор присваивания (=)...........................................122
Арифметические операции.............................................124
Сложение (+).......................................................124
Вычитание (-)......................................................126
Умножение (*)......................................................128
Деление (/)........................................................128
Целочисленное деление (\)..........................................129
Деление по модулю (Mod)............................................129
Возведение в степень (~)...........................................129
Операции сравнения.................................................130
Сравнение строк....................................................131
Двоичное и текстовое сравнение строк.............................132
Выбор метода сравнения строк.....................................132
Сравнение строки с шаблоном........................................132
Сравнение объектов.................................................135
Логические операторы................................................135
Таблицы истинности...............................................136
And..............................................................136
Or...............................................................137
Not..............................................................137
Xor..............................................................138
Eqv..............................................................138
Imp..............................................................139
Конкатенация строк.................................................139
Использование конкатенации строк.................................140
Операторы конкатенации строк.....................................141
Приоритеты выполнения операций при вычислении сложных выражений . . 142
Глава 6. Использование функций Visual Basic...........................144
Функции.............................................................144
Использование функций в выражениях.................................144
Аргументы и возвращаемое значение функции..........................145
Игнорирование результата функции...................................146
Использование именованных аргументов функции........................147
Использование других функций VBA....................................152
8
Программирование на VBA 2002
Математические функции.............................................152
Функции преобразования данных......................................153
Функции даты и времени.............................................154
Строковые функции..................................................156
Использование функций для манипулирования строками.................158
Удаление ненужных символов.........................................158
Определение длины строки...........................................160
Сравнение и поиск строк............................................160
Использование функции StrComp....................................160
Использование функции InStr......................................161
Разбиение строки на меньшие части..................................162
Функция Left.....................................................162
Функция Right....................................................163
Функция Mid......................................................163
Использование символов, которые нельзя ввести с клавиатуры.........164
Форматирование значений данных.....................................166
Использование функций host-приложений..............................174
Глава 7. Создание и использование функций и функций-процедур . . 177
Функции-процедуры и определенные пользователем функции..............177
Создание функций-процедур...........................................178
Написание функции-процедуры........................................178
Создание определенных пользователем функций для Excel..............180
Объявление типов данных для аргументов функции.....................181
Использование функций-процедур в VBA................................182
Использование инструмента Object Browser для нахождения функций-процедур....................................183
Ввод описания функции-процедуры с помощью инструмента Object Browser . . 184
Использование функций пользователя в рабочих листах Excel...........185
Создание функций для Excel.........................................186
Глава 8. Изменение порядка выполнения операторов в VBA . . . 190
Простой выбор......................................................191
Использование необязательных аргументов............................194
Выбор ветви с помощью If...Then...Else.............................195
Сложный выбор......................................................197
Вложенные операторы If...Then....................................197
Использование If...Then...ElseIf...................................199
Оператор Select...Case...........................................201
Безусловный переход................................................204
Использование MsgBox для обеспечения возможности выбора.............205
Глава 9. Дополнительные свойства процедур и функций...................209
Раннее окончание процедур, функций и целых программ.................209
Использование оператора Exit.......................................209
Использование оператора End........................................212
Дополнительные свойства необязательных аргументов...................214
Управление передачей аргументов.....................................215
Передача аргументов по ссылке и по значению........................215
Определение способа передачи аргумента.............................216
Рекурсия............................................................217
Примеры рекурсивных функций........................................218
Как избежать случайной рекурсии и других проблем...................220
Глава 10. Объекты и коллекции, введение...............................221
Объекты.............................................................221
Свойства объекта...................................................222
Методы объекта....................................................  222
Содержание
9
Классы объекта....................................................223
Использование объектов............................................223
Использование свойств объектов..................................225
Использование методов объекта...................................231
Объявление объектных переменных...................................236
Объект в выражениях...............................................237
Ссылка на объекты с помощью With...End With.......................240
Работа с коллекциями объектов и контейнерами объектов.............241
Добавление к коллекциям...........................................246
Ссылка на конкретные объекты в коллекции или контейнере...........247
Фигуры в слое векторной графики....................................248
Добавление к коллекции Shapes ♦ автофигур»........................248
Добавление к коллекции Shapes специальных фигур...................251
Использование Object Browser с объектами, методами и свойствами. . . . 258
Глава 11. Повторение действий в Visual Basic: циклы..................260
Команды организации циклов.........................................260
Повторение цикла фиксированное число раз: циклы For...............261
Использование цикла For...Next..................................261
Использование For...Next с возрастающим счетчиком...............262
Использование For...Next с убывающим счетчиком..................264
Цикл For Each...Next............................................267
Циклы Do..........................................................270
Как прервать выполнение макроса или процедуры.....................272
Использование циклов, тестирующих условия до выполнения тела цикла. . . 273
Циклы Do While..................................................273
Циклы Do Until................................................  275
Использование циклов, тестирующих условия после выполнения тела цикла. . 277
Циклы Do...Loop While...........................................277
Циклы Do...Loop Until...........................................278
Вложенные циклы....................................................279
Вложение циклов For...............................................280
Вложенные циклы Do..............................................281
Глава 12. Массивы....................................................284
Размерность массива................................................284
Одномерные массивы................................................284
Многомерные массивы...............................................285
Статические и динамические массивы................................285
Оператор Option Base................................................286
Объявление массивов.................................................287
Использование массивов..............................................288
Использование ReDim с динамическими массивами......................291
Функции LBound и UBound............................................295
Использование Erase для очистки или удаления массивов..............296
Использование массивов в качестве аргументов процедур и функций . . . 298
Часть II. Разработка приложений......................................301
Глава 13 Управление файлами с помощью VBA............................302
Управление файлами.................................................302
Что такое управление файлами......................................302
Возможности VBA по управлению файлами.............................302
Атрибуты файла......................................................303
Получение атрибутов файла.........................................305
Изменение атрибутов файла.........................................307
Как находить файлы..................................................309
Использование функции Dir для нахождения файлов....................309
10
Программирование на VBA 2002
Использование встроенных диалоговых окон Excel	>
для получения имен файлов............................................313
Использование метода GetOpenFilename................................313
Использование метода GetSaveAsFilename..............................317
Использование встроенных диалоговых окон Word для получения имен файлов............................................319
Использование Word-диалогового окна Открытие документа..............320
Использование Word-диалогового окна Сохранение документа............321
Работа с дисками и папками...........................................323
Получение пути текущей папки и буквенной метки диска................323
Изменение текущей папки.............................................324
Изменение текущего диска..........................................325
Создание дисковых папок.............................................326
Удаление дисковых папок...........................................327
Копирование и удаление файлов........................................327
Копирование файлов..................................................327
Удаление файла......................................................329
Переименование или перемещение файлов................................330
Получение информации о файлах........................................331
Получение времени и даты создания/модификации файла.................331
Получение длины файла...............................................332
Глава 14. Элементы диалоговых окон.....................................334
Формы пользователя...................................................334
Свойства объекта UserForm...........................................335
Методы объекта UserForm.............................................336
События и событийные процедуры......................................338
Синтаксис Load/Unload.............................................339
Примеры программ модуля класса формы................................339
Элементы управления..................................................343
Использование Toolbox (панели элементов).............................350
Добавление к форме элементов управления.............................350
Редактирование элементов управления на форме........................358
Выбор элементов управления..........................................359
Перемещение элементов управления....................................359
Изменение размеров элементов управления.............................359
Копирование, вставка и удаление элементов управления................359
Редактирование или форматирование заголовков элементов управления . . . 360
Управление последовательностью перехода............................  360
Задание свойств формы и элементов управления в режиме разработки. ... 361
Пример разработки приложения с диалоговой формой.....................363
Интерфейс...........................................................363
Что должен уметь пользователь?....................................363
Что поместить в диалоговое окно?..................................364
Данные для макроса................................................364
Разработка приложения...............................................364
t Разработка диалогового окна..........................................364
Глава 15. Отладка VB-кода. Поиск и устранение ошибок...................372
Типы ошибок.........................................................372
Средства отладки....................................................374
Режимы отладки......................................................376
Режим останова......................................................376
Переход в режим останова из окна сообщения об ошибке..............376
Точки останова......................................................377
Использование оператора Stop......................................378
Переход в режим останова с помощью команды Step Into..............379
Переход в режим останова прерыванием исполнения кода..............379
Содержание
11
Выход из режима останова...........................................379
Использование команды Step Into.......................................380
Наблюдение за значениями выражений....................................380
Редактирование наблюдаемого выражения...............................383
Удаление наблюдаемого выражения....................................383
Использование команды Step Over.......................................384
Использование окна Locals............................................. 384	'
Трассировка вызовов процедур..........................................384
Использование окна Immediate..........................................386
Оператор Debug.Print..................................................387
Оператор Debug. Assert................................................387
Обработчик ошибок.....................................................387
Выход из блока обработки прерывания по ошибке......................389
Программная обработка ошибок при помощи оператора On Error............392
Часть Ш. Управление другими приложениями................................395
Глава 16. Управление host-приложениями VBA..............................396
Работа с Excel.........................................................396
Возвращение объекта книга.............................................396
Как открыть книгу.....................................................397
Как создать новую книгу...........................................  .	398
Как сделать книгу активной............................................399
Как сохранить книгу...................................................400
Как закрыть книгу.....................................................404
Работа с объектами Worksheet..........................................406
Возвращение значения объекта Worksheet.............................406
Как сделать лист активным..........................................408
Как создать новый лист.............................................408
Как переименовать лист.............................................409
Копирование и перемещение листа....................................409
Как удалить лист...................................................410
Методы, возвращающие объекты Range....................................411
Использование Range метода.........................................411
Использование метода Cells............................................412
Использование метода Offset........................................415
Другие методы и свойства, возвращающие диапазоны ячеек.............416
Работа с Cells и Ranges...............................................417
Выделение ячейки или диапазона ячеек...............................417
Свойства Value и Formula...........................................418
Определение имени диапазона ячеек..................................419
Как вырезать, скопировать и очистить данные........................420
Работа с объектами Word...............................................422
Работа с объектами Document...........................................422
Доступ к объекту Document..........................................422
Как открыть документ...............................................423
Как создать новый документ.........................................424
Как сделать документ активным......................................425
Как сохранить документ.............................................426
Как закрыть документ...............................................428
Работа с объектами Template...........................................429
Как создать шаблон.................................................429
Как загружать и выгружать общие шаблоны............................429
Как присоединить шаблон............................................431
Компоненты объекта Document...........................................431
Как задать диапазон..................................................432
Как получить ссылку на объект......................................433
Как выполнить ссылку на диапазон...................................434
Работа с объектом Selection...........................................436
Как переместить или «свернуть» объекты Selection и Range..............437
12
Программирование на VBA 2002
Добавление текста..................................................439
Как вырезать, скопировать, вставить и удалить текст................441
Глава 17. Работа с другими приложениями: Automation...................444
Что такое OLE?......................................................444
Краткая история OLE................................................444
Работа Visual Basic for Applications с технологией OLE ............446
Поиск типа класса объекта..........................................447
Использование реестра Windows......................................447
Поиск объектного класса в реестре................................448
Использование программы System Information.......................450
Добавление связанных и внедренных объектов.........................451
Объекты Shape и OLEFormat..........................................452
Использование метода AddOLEObject коллекции Shapes.................462
Примеры использования метода AddOLEObject коллекции Shapes.........455
Вставка нового внедряемого объекта...............................455
Вставка существующего файла как внедренного объекта................456
Вставка существующего файла как связанного объекта.................457
Коллекция Excel OLEObjects.........................................458
Коллекция InLineShapes в Word......................................460
Работа со связанными и внедренными объектами........................461
Доступ к OLE-объектам..............................................461
Использование свойств OLE-объектов.................................462
Методы OLE-объектов................................................465
Метод Update.......................................................465
Методы Verb и DoVerb...............................................468
Технология Automation...............................................472
Доступ к объектам Automation.......................................472
Создание нового Automation-объекта..................................475
Функция CreateObject...............................................475
Использование ссылок на библиотеки объектов........................478
Доступ к существующим объектам Automation..........................479
Глава 18. Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»..................................482
Запуск приложения-сервера...........................................483
Инициализация и завершение связи с DDE-сервером.....................484
Инициализация и завершение связи с DDE-сервером..................  485
Управление приложением-сервером....................................487
Обмен данными с приложением-сервером DDE............................489
Получение данных от DDE-сервера....................................489
Передача данных DDE-серверу........................................493
Передача «нажатий клавиш» другому приложению........................494
Доступ к DLL из Visual Basic for Applications.......................496
Объявление DLL-процедур............................................497
Примеры DLL........................................................498
Глава 19. Использование обработчиков событий..........................503
События и обработчики событий.......................................503
Где хранится обработчик события....................................504
Имена и объявление обработчиков событий.........................  .	505
Аргументы обработчика события......................................506
Работа с событиями объекта Application..............................506
Работа с событиями объектов Excel...................................508
Событие Open.......................................................510
Событие BeforeClose................................................512
Событие Activate...................................................513
Содержание	13
Событие Deactivate..................................................513
Событие BeforeDoubleClick...........................................514
События Change и SelectionChange....................................515
Событие Calculate...................................................518
Другие события......................................................519
Печать............................................................519
Сохранение рабочих книг...........................................519
Создание новых объектов...........................................520
Изменение выделенного фрагмента...................................520
Работа со свойствами и методами Excel, связанными с событиями .... 520
Свойство OnWindow Excel.............................................521
Метод OnKey Excel...................................................522
Метод OnTime Excel...................................................525
Работа с событиями объектов Word.....................................526
Событие Open........................................................527
Событие Close.......................................................528
Событие New.........................................................529
Событие Documentchange..............................................529
Событие Quit........................................................530
Работа с коллекциями и методами, связанными с событиями Word .... 532
Коллекция KeyBindings................................................532
Метод OnTime Word....................................................534
Часть IV. Доступ к базам данных из приложений Microsoft Office. . 537
Глава 20. Введение в базы данных.....................................  538
Что такое «базы данных»?..............................................538
Типы баз данных......................................................539
Функции систем управления базами данных..............................540
Модель данных........................................................541
Реляционная модель данных............................................541
Операции над отношениями..........................................542
Объединение.......................................................542
Пересечение..........................................................543
Вычитание.........................................................543
Декартово произведение............................................544
Деление...........................................................544
Проекция..........................................................545
Соединение........................................................546
Выбор.............................................................546
Связи между отношениями...........................................548
Ограничения реляционной модели....................................550
Нормализация отношений............................................550
Базы данных в Excel..................................................552
Импорт данных в Excel из баз данных..................................554
Создание базы данных в Access........................................561
Бизнес-задача: разработка базы данных для учета движения товаров на складе . . 562
Создание таблицы в Access..........................................565
Другие способы создания базы данных..................................569
Занесение данных в таблицы баз данных...............................570
Глава 21. Основы языка SQL.............................................572
Типы команд SQL......................................................573
SQL в Visual Basic...................................................574
Инструкция SELECT....................................................574
Выбор в SQL-запросе определенных полей.............................578
Выбор в SQL-запросе определенных записей...........................579
Использование в SQL-запросе функций для вывода определенных записей . . . 580
Форматирование выводимых в запросе данных..........................582
14
Программирование на VBA 2002
Выбор данных из более чем одной таблицы...........................583
Вывод выбранных данных в определенном порядке.....................584
Агрегирующие функции в инструкции SELECT..........................585
Группировка данных в инструкции SELECT............................587
Подзапросы в инструкции SELECT....................................588
Глава 22. Доступ к базам данных из VBA-кода............................593
Microsoft DAO.........................................*..............593
Рабочие пространства DAO............................................594
Использование DAO-модели для Microsoft Jet..........................597
Объект Database...................................................597
Объект Recordset..................................................599
Пример работы подключения VBA-кода к базе данных..................602
Пример создания базы данных из	кода	VBA...........................608
Доступ к источникам данных ODBC......................................610
Использование DAO-модели для ODBCDirect.............................612
Microsoft ADO........................................................615
Объект Connection.................................................617
Объект Recordset..................................................621
Коллекция Field как свойство объекта Recordset....................623
Глава 23. Работа с SQL Server..........................................634
Установить SQL Server на компьютер очень просто......................636
Базы данных в SQL Server.............................................637
Основные этапы работы с SQL Server...................................639
Создание базы данных при помощи Server Enterprise Manager...........639
Создание базы данных посредством кода...............................647
Представления и хранимые процедуры..................................651
Приложения.............................................................657
Приложение А. Справочные таблицы книги.................................658
Приложение Б. Приоритеты операций в Visual Basic.......................701
Приложение В. Операторы в VBA..........................................702
AppActivate..........................................................702
Веер.................................................................702
Call.................................................................703
ChDir................................................................704
ChDrive..............................................................704
Close................................................................704
Const................................................................705
Date.................................................................705
Declare..............................................................706
Deftype..............................................................708
DeleteSetting........................................................709
Dim..................................................................709
Do...Loop............................................................710
End..................................................................711
Enum.................................................................712
Erase................................................................713
Error................................................................714
Event................................................................714
Exit.................................................................715
FileCopy.............................................................716
For Each...Next......................................................717
Содержание	15
For...Next............................................................717
Function..............................................................718
Get...................................................................721
GoSub...Return........................................................723
GoTo..................................................................724
If...Then...Else......................................................724
Implements..............*.............................................725
Input #...............................................................725
Kill..................................................................726
Let...................................................................726
Line Input #..........................................................727
Load..................................................................728
Lock, Unlock..........................................................728
LSet..................................................................729
Mid...................................................................730
MkDir.................................................................730
Name..................................................................730
On Error..............................................................731
On...GoSub, On...GoTo.................................................733
Open..................................................................734
Option Base...........................................................735
Option Compare........................................................735
Option Explicit.......................................................736
Option Private........................................................736
Print #...............................................................736
Private...............................................................737
Property Get..........................................................738
Property Let..........................................................741
Property Set..........................................................743
Public................................................................745
Put...................................................................746
RaiseEvent............................................................748
Randomize.............................................................749
ReDim.................................................................749
Rem...................................................................750
Reset.................................................................750
Resume................................................................750
RmDir.................................................................753
RSet..................................................................753
SaveSetting...........................................................753
Seek..................................................................754
Select Case...........................................................755
SendKeys..............................................................756
Set...................................................................758
SetAttr...............................................................759
Static................................................................759
Stop..................................................................760
Sub...................................................................760
Time..................................................................762
Type..................................................................762
Unload................................................................763
While... Wend.........................................................763
Width #...............................................................764
16
Программирование на VBA 2002
With.................................................................764
Write#..............................................................  765
Приложение Г. Функции в VBA...........................................767
АЪз..................................................................767
Array................................................................767
Asc.................................................*...............767
Atn..................................................................768
CallByName...........................................................768
Функции преобразования типов.........................................769
Возвращаемые типы..................................................769
Choose...............................................................769
Chr..................................................................770
Cos..................................................................770
CreateObject.........................................................770
CurDir..............................................................  771
CVErr................................................................771
Date.................................................................772
DateAdd..............................................................772
DateDiff.............................................................773
DatePart.............................................................774
DateSerial...........................................................774
DateValue............................................................775
Day..................................................................775
DDB..................................................................775
Dir..................................................................776
Environ..............................................................777
EOF..................................................................777
Error................................................................778
Exp..................................................................778
FileAttr.............................................................778
FileDateTime........................................................779
FileLen..............................................................779
Filter...............................................................779
Fix..................................................................780
Format...............................................................781
Formatcurrency.......................................................782
FormatDateTime.......................................................783
FormatNumber........................................................783
FormatPercent........................................................784
FreeFile.............................................................785
FV...................................................................785
GetAllSettings.......................................................786
GetAttr..............................................................786
GetObject............................................................787
GetSetting...........................................................788
Hex..................................................................788
Hour.................................................................789
Ш....................................................................789
Input................................................................790
InputBox.............................................................790
InStr................................................................791
InStrRev.............................................................792
Int..................................................................793
Содержание
17
IPmt...............................................................793
IRR................................................................794
IsArray............................................................795
IsDate.............................................................795
IsEmpty............................................................795
IsError..........................................................  796
IsMissing..........................................................796
IsNull.............................................................796
IsNumeric..........................................................797
IsObject...........................................................797
Join...............................................................798
LBound.............................................................798
LCase..............................................................799
Left...............................................................799
Len................................................................799
Loc................................................................800
LOF................................................................800
Log................................................................801
LTrim..............................................................801
Mid................................................................801
Minute.............................................................802
MIRR...............................................................802
Month..............................................................802
MonthName..........................................................803
MsgBox.............................................................803
Now................................................................805
NPer...............................................................805
Функция NPV......................................................  806
Oct................................................................806
Partition..........................................................807
Pmt................................................................807
PPmt...............................................................808
PV.................................................................809
QBColor............................................................810
Rate...............................................................811
Replace............................................................812
RGB................................................................813
Right..............................................................814
Rnd................................................................815
Round..............................................................816
Rtrim..............................................................816
Second.............................................................816
Seek...............................................................816
Sgn................................................................817
Shell..............................................................817
Sin................................................................818
SLN................................................................819
Space..............................................................819
Spc................................................................819
Split..............................................................820
Sqr................................................................821
Str................................................................821
StrComp............................................................821
18
Программирование на VBA 2002
StrConv............................................................822
Str Reverse........................................................823
String.............................................................823
Switch.............................................................824
SYD................................................................824
Tab..............................................................  824
Tan................................................................825
Time...............................................................825
Timer..............................................................825
TimeSerial.........................................................825
TimeValue..........................................................826
Trim...............................................................826
TypeName...........................................................826
UBound.............................................................827
UCase..............................................................828
Vai................................................................828
VarType............................................................828
Weekday..........................................................  829
WeekdayName........................................................830
Year...............................................................831
Приложение Д. Константы в VBA........................................832
Календарные (Calendar) константы...................................832
Константы типов вызова (CallType)..................................832
Константы цветовые (Color).........................................832
Константы типов сравнений (Comparison).............................833
Константы компиляции (Compiler)....................................833
Константы дат (Date)...............................................833
Константы формата дат (Date Format)................................834
Константы функций Dir, GetAttr и SetAttr...........................835
Константы типов драйверов (DriveType)..............................835
Константы атрибутов файлов (File Attribute)........................835
Константы файлового ввода/вывода (File Input/Output)...............836
Константы форм (Form)...............................................836
Константы Dir, GetAttr и SetAttr....................................836
Константы ключевых кодов (Keycode)..................................837
Смешанные константы (Miscellaneous Constants)......................839
Константы функции MsgBox...........................................840
Аргументы-константы функции MsgBox.................................840
Возвращаемые значения функции MsgBox..............................841
QueryClose-константы...............................................841
Константы Shell....................................................841
Константы специальных папок (SpecialFolder)........................841
Константы преобразования строк (StrConv)...........................842
Константы системных цветов (System Color)..........................842
Tristate-константы.................................................843
VarType-константы...........................................  .	. . 844
Приложение Е. События объектов User Form.............................845
Activate...........................................................845
Initialize.........................................................845
QueryClose.........................................................846
Возвращаемые значения...........................................846
Resize.............................................................847
Содержание	19
Terminate............................................................847
События объектов управления.............................................848
AddControl...........................................................848
AfterUpdate...........................................................849
BeforeDragOver.......................................................849
BeforeDropOrPaste.....................................................851
BeforeUpdate........................................................ 852
Change...............................................................852
Click................................................................853
DblClick.............................................................853
Enter................................................................854
Error.................................................................855
Exit.................................................................856
KeyDow, KeyUp........................................................856
KeyPress.............................................................857
Layout...............................................................858
MouseDown, MouseUp...................................................858
MouseMove............................................................859
RemoveControl........................................................861
Scroll...............................................................861
SpinDown, SpinUp.....................................................863
Zoom.................................................................865
Предметный указатель....................................................  867
Введение
Без преувеличения можно сказать, Microsoft Office любых версий является самым полезным и самым используемым продуктом Microsoft. И современный руководитель, и менеджер, и преподаватель, и студент, и школьник — все, кто имеет в своем распоряжении компьютер, в той или иной степени используют эту систему. Часто встречаются такие пользователи, которые не умеют включить и выключить компьютер, но большую часть своей профессиональной деятельности работают с приложениями типа Word, Excel, Outlook и т.д. Это связано с большой универсальностью Microsoft Office, набор приложений предназначен для решения очень широкого круга задач: от создания простых документов и отчетов до полной автоматизации документооборота с использованием систем управления базами данных. При этом каждый пользователь имеет возможность, с одной стороны, расширить этот диапазон, с другой — настроить любое приложение Microsoft Office для оптимального выполнения своих специфических задач.
Одним из наиболее важных и полезных аспектов подготовки Microsoft Office к выполнению определенных задач является автоматизация процессов взаимодействия пользователя с приложениями Microsoft Office. Эти приложения не являются законченными продуктами, настроенными на выполнение всех возможных задач, а представляют собой системы, которые нуждаются в определенной настройке, что обеспечивается разнообразными средствами, как интерактивными, так и программными. Все приложения Microsoft Office поддерживают язык программирования Visual Basic for Applications (VBA). VBA позволяет работать c Microsoft Office, как с некоторым конструктором: в распоряжении разработчика VBA-приложения не только большое количество объектов и коллекций, но и возможности настроек, позволяющие до такой степени программно настроить любое приложение, что пользователь такого приложения может и не понять, с каким приложением происходит «общение».
Важнейшим достоинством VBA является возможность объединять любые приложения Microsoft Office для решения, практически, любых задач по обработке информации. В этом смысле Microsoft Office можно считать системой программирования, подобной C++, Delphi и т.д., но с более мощными и разнообразными функциями, поскольку здесь имеется неизмеримо большее количество управляемых системой объектов и готовых решений для конечных пользователей.
Привлекательная особенность VBA в том, что он очень удобен для первого знакомства с программированием в среде Windows. Этому способствует широкое распространение приложений Microsoft Office, беконечное разнообразие возможных практических задач, интуитивно понятная интегрированная среда редактора Visual Basic, возможность обучения программированию посредством анализа кода, записанного при помощи макрорекордера, наличие огромного количества объектов, которыми можно управлять из VB-кода. Многие программные структуры VB-кода, работу с объектами, принципы программирования в Windows намного легче изучать в среде редактора Visual Basic какого-либо приложения Microsoft Office, чем в интегрированной среде любой другой системы программирования, например, C++ или Delphi. При этом очень быстро гарантируется результат: даже небольшие навыки по созданию макросов (основных единиц кода на языке VBA), помогающих автоматизировать рутинную повторяющуюся работу над документами, электронными таблицами, почтовыми сообщениями и т.д., коренным образом изменят процесс создания необходимых документов и отчетов, а более глубокие знания VBA-программирования позволят решать, практически, любые задачи: от автоматизации создания простых документов до обработки баз данных с использованием как настольных, так и сетевых СУБД.
Возможности VBA совсем не уступают другим системам программирования в Windows и постоянно растут. К тому же многие системы программирования в Windows и VBA используют общие библиотеки объектов, среди которых — объекты Word, Excel и т.д.
ЧАСТЬ I
Язык программирования Visual Basic
I
Глава 1
Макросы и языки программирования
Удивительно, но многие пользователи Word и Excel не знают самых простых дополнительных возможностей этих продуктов, которые реализуются посредством макросов. Конечно, и Word, и Excel предоставляют достаточно широкий набор функций для выполнения самых разнообразных офисных задач, но все же знание и использование макросов VBA дает такие преимущества, которые невозможно переоценить.
Перед тем как вы начнете писать собственные макросы, вам следует хорошо понять, что такое макросы и чем отличается VBA-программируемый макрос от записанного макрорекордером.
Макрос и макрорекордер
Независимо от используемых вами операционной системы и программных приложений вы часто выполняете одни и те же последовательности команд для многих рутинных задач. Вместо повторения последовательности команд каждый раз, когда вам необходимо выполнить какую-либо задачу, вы можете создать мак рос (macro), который вместо вас будет выполнять эту последовательность. Макросы позволяют вводить одиночную команду, выполняющую ту же задачу, для реализации которой вам было бы необходимо вводить несколько команд вручную.
Записанные макрорекордером последовательности команд первоначально назывались макрокомандами (macro commands).Сейчас этот термин сократился до более простого слова макрос. (Термин macro используется как префикс в нескольких словах в английском языке; он произошел от греческого слова, означающего расширенный или растянутый). Применительно к информатике и программным приложениям под словом макрос всегда подразумевается макрокоманда.
Макросы, кроме удобства, имеют и другие преимущества. Поскольку компьютеры больше приспособлены для выполнения повторяющихся задач, чем люди, запись макрорекордером неоднократно выполняемых команд повышает точность и скорость работы. Другим преимуществом использования макросов является то, что при их выполнении обычно нет необходимости в присутствии человека-оператора. В случае, если макрос очень длинный или выполняет операции, требующие значительного времени (например, поиск в базе данных и сортировка), вы можете оставить работающий компьютер и делать что-нибудь другое, а также переключиться на другое приложение.
Макрорекордер (или просто «рекордер») записывает все действия пользователя, включая ошибки и неправильные запуски. Когда программа воспроизводит макрос, она выполняет каждую записанную рекордером команду точно в такой последовательности, в которой вы их выполняли во время записи. Первые макрорекордеры имели серьезный недостаток. Если вы записывали длинную серию действий, содержащую маленькую ошибку, единственной возможностью удалить эту ошибку являлась повторная запись макроса. Кроме того, если вам было необходимо внести небольшое изменение в длинный макрос, то также приходилось перезаписывать весь макрос. Перезапись длинного макроса часто приводила к дополнительным ошибкам в новой записи. По этим причинам разработчики программного
Макросы и языки программирования
25
обеспечения добавили макрорекордерам возможность редактирования макросов, чтобы вы могли легко исправлять небольшие ошибки или вносить другие изменения в макрос без его полной перезаписи.
Из истории VBA
Несмотря на то что Visual Basic for Applications (VBA) — это относительно новый продукт, предпосылки его появления имеют историю, почти столь же долгую, что и вся компьютерная индустрия. Язык VBA является современным диалектом языка программирования BASIC, который был создан в начале 60-х годов. (BASIC — это сокращение от Beginner’s All-Purpose Symbolic Instruction Code.)
Хотя по сегодняшним стандартам первоначальный язык BASIC имел значительные ограничения, изучать и понимать его было легко, что способствовало его быстрому распространению. Версии языка BASIC создавались (и все еще создаются) для использования на всех типах компьютеров. Версия Microsoft GWBASIC (GW означает Graphics Workshop) была одним из первых языков программирования, доступных для компьютеров, которые эволюционировали в современные персональные компьютеры. GWBASIC поставлялся с версиями MS-DOS до Version 5.0. Ранние ПК, выпускаемые IBM, имели даже версию BASIC, встроенную в микросхемы ROM (Read Only Memory) компьютера.
С годами первоначальная структура и спецификации BASIC были улучшены. По мере усовершенствования и изменения технологии для языков программирования различные создатели программного обеспечения добавляли некоторые возможности к первоначальному BASIC. Современные диалекты BASIC обычно имеют многие или все свойства, существующие в других более поздних языках программирования, таких как Pascal или С.
В конце 80-х годов Microsoft опубликовала значительно улучшенную версию языка BASIC, названную QuickBASIC. QuickBASIC включал почти все возможности современных систем разработки программного обеспечения. Microsoft поставляет теперь версию QuickBASIC с DOS Version 6.0 и более поздними версиями (но не в Windows 95).
После нескольких версий QuickBASIC в 1992 году Microsoft представила Visual Basic for Windows. Как и в случае с QuickBASIC, Visual Basic for Windows был дополнен современными возможностями и тесно интегрирован в среду Windows. Visual Basic предоставляет команды для создания и управления необходимыми элементами программы в Windows: диалоговыми окнами, линейками меню, раскрывающимися списками, командными кнопками, флажками, панелями инструментов и так далее. В частности, Visual Basic включает необходимые команды для использования Object Linking and Embedding (OLE) и Dynamic Data Exchange (DDE) для связи или совместного использования данных с другими приложениями Windows. Visual Basic является существенно новым языком программирования для Windows со своими корнями в BASIC.
В то время как BASIC развивался и улучшался, изменялись макрорекордеры, используемые в программных приложениях. С годами макросы приложений постепенно становились все сложнее в ответ на пожелания пользователей сделать макросы более гибкими в действии и более легкими для сопровождения. Многие макроязыки начали включать возможности, подобные тем, которые обычно имеются только в законченных языках программирования.
Макроязыки многих приложений значительно изменяются от продукта к продукту. Это означает, что вам может понадобиться изучить несколько различных макроязыков; в результате эффективность вашей работы может снизиться во время изучения нового макроязыка. Чтобы избежать необходимости изучения нового макроязыка для каждого продукта, Microsoft начала включать элементы языка
26
Глава 1
BASIC в макроязыки своих продуктов. Примером может служить макроязык для Word for Windows фирмы Microsoft (до Word 97), известный как WordBASIC, тогда как язык программирования для Access фирмы Microsoft был известен как Access Basic.
Для унификации макроязыков в своих приложениях Windows и для интеграции приложений на этих макроязыках с DDE и OLE Microsoft создала специальную версию языка Visual Basic, названную Visual Basic for Applications (сокращенно VBA). Excel 5 был первым продуктом, включающим Visual Basic for Applications (VBA). С появлением Microsoft Office 97 и 2000/2002 VBA реализуется теперь в Microsoft Word 97 и 2000/2002, Access 97 и 2000/2002, Excel 97 и 2000/2002, Microsoft PowerPoint 2000/2002, Microsoft FrontPage 2000/2002 и Microsoft Vi-sio 2000. В основные приложения Office (Word, Excel, PowerPoint), начиная с версии 2000, включен редактор сценариев — Microsoft Visual Basic Script Editor, который позволяет редактировать Web-страницы (например, в Word) и придать им динамику. Язык VBScript (Visual Basic Scripting Edition) входит в семейство языков Visual Basic и, являясь упрощенной версией языка Visual Basic, позволяет программировать документы, отображаемые браузерами World Wide Web.
Visual Basic for Applications в основном является тем же, что и Visual Basic for Windows, с некоторыми небольшими различиями. Макропрограммы VBA сохраняются в файловом формате, используемом приложением, в котором вы написали макрос Visual Basic for Applications, а не в отдельных текстовых файлах1. Например, макропрограммы VBA, созданные в Excel 2002, сохраняются в файле рабочей книги Excel, программы VBA в Word 2002 сохраняются в файле документа, а программы VBA в Access 2002 — в файле данных Access. Для выполнения макропрограммы VBA вы должны сначала запустить ее, используя приложение, в котором написали этот макрос. Например, вы не можете запустить макрос Excel VBA из любой другой программы, кроме Excel. Несмотря на то, что основные возможности VBA остаются теми же в приложениях, каждое приложение добавляет специальные команды и объекты (в зависимости от конкретного приложения) в Visual Basic for Applications. Например, VBA в Excel 2002 содержит много команд, которые относятся только к рабочим листам и задачам, которые вы можете выполнить с рабочим листом. Аналогично, VBA в Word 2002 содержит команды, относящиеся только к операциям над текстом в документе, тогда как VBA в Access 2002 содержит команды, относящиеся только к операциям с базой данных, и так далее.
Если до появления MS Office 97 средства программирования в офисных пакетах предназначались в основном для создания макрокоманд, расширяющих возможности конкретных приложений, то с выходом MS Office 97 специалисты получили универсальную систему программирования для прикладных программ на базе Visual Basic. Впервые MS Office был представлен как единая платформа для создания бизнес-приложений, предназначенных решать специализированные задачи пользователей. Это новое качество MS Office обуславливалось специальным выпуском для разработчиков — Developer Edition. По сведениям Microsoft, в настоящее время MS Office в качестве платформы создания бизнес-приложений используют более двух миллионов профессиональных разработчиков. Кроме выпуска Developer Edition, MS Office выпускается как Standard, Small Business, Professional и Premium. Эти выпуски отличаются только составом приложений, хотя от дельные приложения одинаковы во всех выпусках.
Поскольку книга предназначена в основном тем, кто только начинает про граммировать в среде Windows, здесь подробно рассмотрено VBA-программирова ние только для двух наиболее используемых приложений — Word и Excel. Основ
1 Пакет MS Office Developer (MOD), предназначенный для разработчиков профессиональны: приложений, позволяет создавать автономные VBA-проекты, которые хранят исходный ко, файлов в виде двоичных файлов отдельно от таких приложений как Word, Excel и т.д.
Макросы и языки программирования
27
ной целью, которую преследует автор книги, является изучение основ языка VBA, который, как утверждает Microsoft, начиная с версии MS Office 2000, не отличается от обычного VB. VBA-программирование (разработка макросов) рассматривается для самого распространенного (по крайней мере, в России) пакета MS Office ХР Professional, в состав которого входят такие приложения, как Microsoft Access for Windows, Microsoft Excel for Windows, Microsoft FrontPage for Windows, Microsoft Outlook for Windows, Microsoft PowerPoint for Windows, Word for Windows.
Зачем изучать язык программирования VBA
Поскольку вы можете использовать макрорекордер в Word или Excel для записи ваших действий в макрос (а в Access для этой цели использовать своего рода конструктор) и затем воспроизводить их, сначала может показаться, что изучать VBA необязательно. Однако одни записанные макросы не могут удовлетворить все ваши потребности. Записанный макрорекордером макрос может только воспроизводить без отклонений каждое действие в той же последовательности, в которой вы первоначально выполняли эти действия. VBA можно использовать для улучшения макросов, записанных макрорекордером, значительно повышая их мощь и возможности.
Записанные макрорекордером макросы лишены гибкости, поэтому они не могут реагировать на изменившиеся или меняющиеся условия. На языке VBA вы можете написать макрос, который проверяет соответствие различным предопределенным условиям и выбирает соответствующую последовательность действий на основе этих условий. Если вы, например, выполняете какой-либо Excel-макрос, который пытается выбрать рабочий лист с именем "Продажи", в то время, когда в книге нет такого рабочего листа, записанный вами макрос будет выполняться неправильно и Excel выведет на экран сообщение об ошибке. Добавив VBA-команды к этому записанному макросу, вы могли бы с его помощью выполнить проверку наличия этого определенного рабочего листа перед его выбором или даже вставить новый рабочий лист и дать ему соответствующее имя, если нужный рабочий лист не существует.
Что касается повторяющихся действий в самом макросе, записанные рекордером макросы имеют значительные ограничения. Если вам необходимо, чтобы записанный макрос повторял какое-либо действие несколько раз, вы должны вручную повторять это действие нужное количество раз, когда записываете макрос. Такой макрос всегда повторяет это действие одинаковое количество раз, всякий раз, когда вы его запускаете, до тех пор, пока вы не отредактируете или не перезапишете его. Напротив, макрос, написанный на языке VBA, может использовать предопределенные условия или вводимые пользователем данные для повторения действия различное количество раз или для принятия решения о необходимости выполнения этого действия.
В качестве примера вы можете записать рекордером макрос для изменения ширины нескольких смежных столбцов в рабочем листе Excel. Если вам необходимо, чтобы макрос изменял ширину первых трех столбцов в рабочем листе, вы должны вручную повторить операцию изменения размера для каждого из трех столбцов при записи макроса. Записанный макрос будет только (и всегда) изменять ширину первых трех столбцов в рабочем листе. Вы не можете использовать тот же макрос для изменения ширины двух или четырех столбцов. Кроме того, если вы изменили ширину первых трех столбцов, записанный макрос будет выполнять действие только над тремя первыми столбцами. Вы не сможете использовать тот же макрос для изменения ширины столбцов со второго по четвертый. Добавив команды VBA к этому записанному рекордером макросу, вы можете создать макрос, который запрашивает, размер скольких и каких столбцов необходимо изменить, и даже позволяет задавать новую ширину столбцов.
28
Глава 1
Эти два примера представляют пару простейших задач, которые вы можете выполнить с командами VBA в макросах. Существует много обстоятельств, при которых вам может понадобиться добавлять команды принятия решений и эффективное повторение команд к макросам, записанным макрорекордером. Единственный способ получить такие возможности — это вручную добавить операторы VBA к записанному макросу.
Конструктор макросов в Access также не «всесилен» и не позволяет создавать приложения со сложной обработкой данных. Рано или поздно наступает время, когда самый искушенный в Access пользователь приходит к тому, что ему не хватает только конструктора для решения новых задач по обработке баз данных.
Кроме улучшения определенных макросов, записанных макрорекордером, вы можете использовать VBA для соединения, организации и управления несколькими записанными макросами, с помощью которых вы выполняете сложную общую задачу, состоящую из нескольких меньших задач. Например, вы можете регулярно импортировать данные из базы данных в рабочий лист Excel, форматировать эти данные для вывода на экран, генерировать диаграмму из этих данных и затем распечатывать эту диаграмму и отформатированный отчет.
Для того чтобы объединить эти отдельные задачи для создания единственной задачи, выполняемой одним макросом, вы можете сначала написать отдельный макрос для каждой из отдельных задач: для импортирования данных, форматирования этих данных для последующего отображения, создания диаграммы и печати данных. Далее вы могли бы организовать записанные макросы так, чтобы они выполнялись в нужной последовательности одним макросом, который вы напишете посредством команд VBA.
С помощью макросов можно создавать пользовательские меню, диалоговые окна и панели инструментов, которые могут до неузнаваемости изменить интерфейс всем известных продуктов Word и Excel. Уместно здесь отметить также и возможность создания разнообразной системы проверки данных, вводимых пользователем в диалоговых окнах. Когда вы научитесь писать программы на языке VBA, вы, скорее всего, уже никогда не станете начинать создание макроса с использования рекордера.
Создание макросов
Существует мнение, что изучение языка VBA легче всего начать с записи нового макроса при помощи рекордера. Поэтому большая часть литературы по VBA следует схеме, по которой читателю предлагается сначала посмотреть, как макросы создаются самими продуктами, такими как Word и Excel, а затем, осторожно внедряя свои инструкции в работающие макросы, изучить новый для них язык. Мне же представляется более продуктивным другой подход, при котором вы начнете писать макросы (с использованием Visual Basic Editor — Редактора), как обычные программы на новом для вас языке программирования и каждый свой шаг будете проверять контрольными запусками кода.
В следующей главе будут очень подробно приведены все детали построения макросов, а сейчас создадим первый простой макрос, точнее — процедуру, в Word и в Access. Да, в Access, это — не опечатка. Access 2002 позволяет писать процедуры так, как это позволяет Word 97/2002 и Excel 97/2002. Далее мы не будем рассматривать макросы Access: в виду особого места этого приложения в Office 2002 вам следует обратиться к другим источникам, если вы хотите освоить VBA для Access.
Создание макроса в Word
Запустите Word, выберите Tools | Macro | Visual Basic Editor (Сервис | Макрос | Редактор Visual Basic) или нажмите комбинацию клавиш Alt+Fll. Ваш экран будет выглядеть подобно приведенному на рис. 1.1. Не вникая в маловажные для перво
Макросы и языки программирования
29
го раза детали, поместите курсор в самое большое окно (Code) и введите следующий текст (без нумерации строк!):
Листинг 1.1. Первый макрос в Word
1	Sub MyFirstMacro()
2	MsgBox ("Макрос в Word1")
3	End Sub
Рис. 1.1
Ваш экран будет выглядеть подобно, хотя возможны некоторые несовпадения
Первая и третья строки этого макроса-процедуры являются заголовком и окончанием процедуры, соответственно. Причем MyFirstMacro — это имя макроса, под которым он будет узнаваем системой. Вторая строка макроса содержит функцию вывода диалогового окна с текстом "Макрос в Word!". Если учесть, что в Windows по-другому вывести информацию из любой (!) программы довольно трудно и чаще всего не нужно, то можно считать, что вторая строка содержит обычный оператор вывода на экран.
Не всегда при запуске Редактора Visual Basic вам сразу будет предоставлено окно Code, в котором можно сразу начать писать операторы на языке Visual Basic Чтобы вывести это окно для вашего первого макроса, щелкните на значке Project(ChapterOI) в окне Project, а затем на кнопке с вертикальной стрелкой рядом с кнопкой Insert Module (вторая кнопка вверху слева) и в появившемся меню выберите Module
После ввода инструкций (иногда так называют операторы языка программирования, чтобы не путать их с математическими и другими операторами) в окно Code ваш экран должен иметь вид, как на рис. 1.2. Подобным образом можно вы
Рис. 1.2
Макрос в окне Code редактора Visual Basic
30
Глава 1
вести предварительно вычисленные или введенные (в диалоговом окне) данные. Таким образом, вы уже на полпути к написанию простейших макросов.
Теперь можно выполнить контрольный запуск макроса, не выходя из Редактора. Выберите Run | Run Sub/UserForm. Результатом работы макроса будет выдача на экран диалогового окна. Сравните его с рис. 1.3.
Рис. 1.3
Результат работы вашего первого макроса (программы на языке Visual Basic)
Если у вас имеется опыт работы с какой-нибудь другой системой программирования, то вас, видимо, никак не впечатлит подобное достижение, но задержитесь немного в Word, прежде чем повторить этот результат в Access, и запустите созданный макрос непосредственно из Word (все-таки Редактор VB в Word — это не совсем Word). Для этого покиньте Visual Basic Editor либо при помощи комбинации клавиш Alt+Q, либо — меню File | Close and Return to Microsoft Word. После того как вы окажитесь в привычном для всех окне Word, выберите Tools | Macro | Macros (Сервис | Макрос | Макросы). В появившемся диалоговом окне Macros выберите (видимо, единственный) уже знакомый вам макрос MyFirstMacro и щелкните на кнопке Run.
Создание макроса в PowerPoint
Совсем несложно создать макрос в приложении PowerPoint. Запустите PowerPoint. На рис. 1.4 представлено диалоговое окно, которое может появиться в вашей системе (состояние этого окна зависит от «истории» работы с PowerPoint этой или предыдущей версии).

Рис. 1.4
По крайней мере, система PowerPoint не позволит вам «потеряться» в начале работы с ней

!*] Файл фавка Вид &стдэ^ Форцат сейме Показ слайдов Окно Сграека
• 18 » ж К у A z Конструктор -Создать слайд
Создание презентацив ▼ *
Заголовок слайда
Подзаголовок слайда
Открытие презентации и#" f -резан ли»
Создание
'' новая pSs<-fl г »
К2 Ит oat офс$*< и- кя
**1 Из НеКЛвра
Создание из ююгащейся презентации
V бьйир 'ра«в~ <*|ии
Создание с помощью шаблона j Ххцие иибта-ы jfj цйПлонь- кзмсяч веб ifj шлблпнь. н* Мм слаб сот
51%	’ * • ДМ
Заметки к <_л «щу
33 ?
Дейсрия • U | Автофисуры •	*1	/	• «X ’ 88 ~~	&
С'	ysns
3) Стрзйьаьчг'язДНтиигГо t __	* Пекаммть при эапуов
Оформление по умолчанию русский (Россия)
Поскольку нашей целью является создание самого простого макроса, щелкните на надписи Новая презентация (Blank Presentation) в правом окне в разделе Создание (New) для выбора пустой презентации. Далее вам снова будет предложено сделать некоторый выбор (рис. 1.5). Впрочем, выбор уже сделан (первый тип слай
Макросы и языки программирования
31
да выделен синим прямоугольником), вы можете не согласиться с ним и выбрать другой, но пока нас устроит и выбор по умолчанию.
Рис. 1.5
«Пообщайтесь» с PowerPoint или продолжайте свой путь к созданию макроса
В данный момент нас интересует вопрос написания макроса. Поэтому выберите Сервис | Макрос | Редактор Visual Basic (Tools | Macro | Visual Basic Editor), в появи-шемся на экране окне редактора щелкните на кнопке со стрелкой с именем Insert UserForm (в верхней правой части окна) и выберите из раскрывающегося меню опцию Module. Редактор Visual Basic создаст новый модуль и откроет соответствующее ему окно, как показано на рис. 1.6.
Рис. 1.6
Совсем не трудно в PowerPoint подготовить место для написания макросов
В этом окне следует набрать код из листинга 1.1, только вместо слова "Word” наберите "PowerPoint", как показано на рис. 1.7.
Если вы запустите этот макрос (Run | Run Sub/UserForm), то увидите на экране результат, подобный приведенному на рис. 1.8.
Теперь после того, как вы изучите следующий раздел, у вас будет свое мнение о том, с чего легче начать изучение языка VBA.
32
Глава 1
Рис. 1.7
Так может выглядеть ваш первый макрос в PowerPoint
tie Microsoft Visual Basic • Презентация! - (Module! (Code)l
Eife Edit View Insert Format Debug bun Tools &dd-lns JMndow tjelp
@ Д * Ы 53> Д *••">	Col 33
I	jrJ jMyFiisfMiKio
MyFirstMacro ()
MsgBox ("Макрос в PowerPoint!")
Sub
}r(Generaii
- VBAProject (Презентация!)
- Modules
42 Module!
Sub
End
‘ МосКШ

Module 1 Module
Alphabetic <Categorized^
Рис. 1.8
Так может выглядеть диалоговое окно, созданное посредством написания кода в Редакторе Visual Basic в системе PowerPoint
Макрос в PowerPort!
Запись новых макросов
В этом разделе рассказывается о том, что вам необходимо знать для записи кг кого-либо макроса. Затем вы выполните необходимые шаги для записи определе! ного макроса как в Word 2002 и Excel 2002, так и в PowerPoint 2002.
Обычно запись макроса включает четыре основных шага:
1.	Задание стартовых условий для макроса. Это означает задание тех услови вашей рабочей среды, которые должны быть соблюдены во время воспроизв дения записанного макроса.
2.	Запуск макрорекордера и присвоение имени макросу. Одновременно с запу ком макрорекордера вы должны дать имя макросу и выбрать место, где < должен быть сохранен. При запуске макрорекордера вы можете выбирать м жду назначением команды запуска макроса с помощью так называемой «гор чей клавиши» или связыванием макроса с каким-либо меню или панелью и струментов (в зависимости от того, записываете ли вы макрос в Excel ш в Word).
3.	Выполнение действий, которые вам необходимо записать для использован позже. Вы можете записать в макрос любое действие, которое можно выпс нить, используя клавиатуру или кнопки мыши, включая выполнение рав записанных макросов. Конкретные выполняемые вами действия зависят от ; дачи, которую вам необходимо записать.
4.	Остановка макрорекордера. Когда вы останавливаете макрорекордер, ваг действия больше не записываются и не сохраняются в макросе. Как только останавливаете рекордер, новый записанный макрос сразу же готов к испо. зованию.
В последующих двух разделах описываются более подробно два первых обш шага при записи макроса. Затем вам будут представлены конкретные пошагов инструкции для записи макроса в Word, Excel и PowerPoint.
Макросы и языки программирования
33
Задание стартовых условий для макроса
Перед записью какого-либо макроса вы должны задать условия, при которых вы будете запускать его позже. Выполнение (running или executing) макроса означает воспроизведение записанных в этом макросе инструкций. Предположим, например, что вам необходимо создать макрос, который будет применять определенный шрифт, размер и цвет шрифта в любом выбранном тексте документа в Word. Стартовыми условиями для этого макроса будут открытый документ с выделенным блоком текста. Если вы хотите создать подобный макрос форматирования текста в Excel, стартовыми условиями будут открытая рабочая книга, выбранный рабочий лист и выделенная ячейка или диапазон ячеек.
Вам необходимо задать стартовые условия для макроса перед тем, как запускать макрорекордер, потому что макрорекордер будет записывать все действия, которые вы выполняете. Если вы запустите макрорекордер, а затем откроете некоторый документ и выделите текст, эти действия станут частью полученного в результате записи макроса. Ваш законченный макрос будет слишком специфическим: он будет всегда открывать один и тот же документ и форматировать один и тот же блок текста. Для создания общего макроса, который вы можете использовать для форматирования любого выбранного текста, вам следует запускать макрорекордер после открытия документа и выбора текста.
Запуск макрорекордера и присваивание имени макросу
Независимо от того, работаете ли вы в Word, Excel или PowerPoint, запись нового макроса осуществляется одним и тем же способом. Выберите команду Сервис | Макрос | Начать запись (Tools | Macro | Record New Macro). И в Word, и в Excel, и в PowerPoint отображается диалоговое окно Запись макроса (Record Macro), которое используется для того, чтобы вы могли дать имя новому макросу, выбрать место его сохранения и другое.
Диалоговое окно Запись макроса может немного отличаться в зависимости от того, записываете ли вы макрос в Word, Excel или PowerPoint. Диалоговое окно Запись макроса в Word 2002 позволяет по выбору назначать «горячую клавишу» для запуска нового макроса или добавлять новый макрос как кнопку на панели инструментов. В Excel 2002 диалоговое окно Запись макроса дает возможность назначать только «горячую клавишу» для запуска нового макроса. В PowerPoint 2002 подобное диалоговое окно позволяет указать имя макроса, презентацию, в которую следует записать макрос. Во всех этих приложениях окно Запись макроса позволяет внести описание макроса.
Больше о специфических опциях Excel, Word и PowerPoint, имеющихся в диалоговом окне Запись макроса, вы узнаете из конкретных пошаговых инструкций немного позже в этой главе.
Имена макросов должны начинаться с буквы, хотя они могут содержать числа. Имена макросов не могут включать пробелы или знаки препинания. В Excel вы можете вводить имя макроса длиной до 64 символов; Word позволяет вводить имя макроса длиной до 80 символов.
Диалоговые окна Запись макроса в Word и в Excel имеют следующие три общих элемента (на рис. 1.10 приведено окно для Word, а на рис. 1.15 — для Excel): 1. Текстовое окно Имя макроса (Macro Name). Первой опцией диалогового окна
Запись макроса является Имя макроса. По умолчанию VBA выбирает имя макроса, состоящее из слова «Макрос» («Macros»), за которым следует номер, соответствующий числу макросов, уже созданных в этом сеансе работы. Вам следует вводить макросам имена, которые несут определенную информацию о том, что выполняют макросы.
2 Программирование на VBA 2002
34
Глава 1
2. Текстовое окно Описание (Description). Информация в текстовом окне Описание макросом непосредственно не используется. Текстовое окно Описание предназначено для ввода некоторых замечаний и комментариев о том, что выполняет данный макрос. Когда вы записываете макрос, VBA заполняет по умолчанию окно Описание информацией, начиная с даты записи этого макроса и имени пользователя. [VBA получает имя пользователя из текстового окна Имя и фамилия (Name) на вкладке в диалоговом окне Параметры (Options) на вкладке Пользователь (User Information) в Word (рис. 1.9) и текстового окна Имя пользователя (User name) вкладки Общие (General) диалогового окна Параметры (Options) в Excel (рис. 1.10).]
3. Раскрывающийся список Макрос доступен для: (Store macro in:). Этот раскрывающийся список позволяет выбрать, где следует сохранить записанный макрос. Макросы, записываемые в Word, всегда сохраняются в файле документа (.doc) или в файле шаблона документа (.dot). Макросы, записываемые в Excel, всегда сохраняются в файле рабочей книги (.xls).
Рис. 1.9
Вкладка Пользователь диалогового
окна Параметры в Word
Рис. 1.10
Вкладка Общие диалогового окна Параметры в Excel
Макросы и языки программирования
35
Запись макроса в Word 2002
Предположим, что вы часто форматируете слова или фразы, к которым хотите привлечь внимание в вашей документации, с помощью полужирного шрифта Arial 12-го размера. Поскольку вы форматируете только одиночные слова или короткие фразы, использовать какой-либо именованный стиль невозможно, так как стили Word применимы только к целым параграфам. Поэтому вам приходится применять форматирование шрифта вручную. Выбор шрифта Arial, изменение его размера и применение атрибута полужирного шрифта к тексту включают несколько операций с мышью или клавиатурой. Если вы часто выполняете эту задачу, можете сберечь время и усилия, записав макрорекордером макрос для выполнения нужного форматирования любого выделенного блока текста.
Задание стартовых условий
Поскольку вам необходимо, чтобы макрос выполнял действие над любым выделенным блоком текста в любом открытом документе, стартовыми условиями для этого макроса являются открытый документ и выделенный блок текста. Для задания стартовых условий в этом упражнении выполните следующие шаги:
1.	Запустите Word 2002.
2.	Откройте какой-либо документ.
3.	Выделите любое слово или фразу в документе. На рис. 1.11 показан пример открытого документа с единственным выделенным словом.
3l Chapter©! -Microsoft Word
файл Правка Вид Вставка Формат Сервис Таблица Qn-ю Справка
Н RX «о т 5] 115%	▼ ” Listing	- Times New Roman
Исправления в измененном документе - Показать *	। J - ЭД ,
0.
- 10
2
1 t' 2 t 3 ' l_4 1 5l 1 6 и 7 1 U 8 'I? ' 10u ' 11 il 12 ' L13 ' Щ 1 15 L ' 16 L £ Предположим что вы часто форматируете слова или фразы к которым хотите привлечь внимание в вашей документации с помощью полужирного шрифта Anal 12-го размера Поскольку вы формалисте только одиночные слова или короткие фра гы использовать какой-либо именованный стиль невошпжно гак как стили Woid применимы только к целым параграфам Поэтому вам приходится применять форматирование шрифта вручную Выбор шрифта Anal изменение его размера и применение атрибута полужирного шрифта к тексту включают несколько операций с мышью пли клавиатурой Если вы часто выполняете чу тадач\ можете сберечь время и усилия, записав макрорекордером макрос для выполнения нужного форматирования любого выделенного блока текста
3

Я
Задание стартовых* условий
Поскольку вам необходимо чтобы макрос выполнял действие над любым выделенным блоком текста в любом открытом документе стартовыми условиями для этого макроса являются открытым докчмент и выделенный блок текста Для задания стартовых у словил в пом упражнении выполните следующие шаги
1	Запустите Woicl 2(»О2
2	Откройте какой-либо документ
3	Выделите любое слово или фразу в документе На рис 1 11 показан пример открытого документа с единственным	ловом
<ыд елейным
Выделив текст в открытом документе вы спздапп необходимые стартовые х словил дат записи общего макроса i цепью применения форматирования символов к любомч выбранноьа теылх
Стр 13 Разд 1	13/25 На 23 5см Ст 20 Кол 14
русачий (Ро В
Рис. 1.11. Задавайте стартовые условия для макроса форматирования текста в Word перед запуском макрорекордера
Выделив текст в открытом документе, вы создали необходимые стартовые условия для записи общего макроса с целью применения форматирования символов к любому выбранному тексту.
2»
36
Глава 1
Присваивание имени макросу и выбор места для его сохранения
Теперь вы готовы запустить макрорекордер в Word, дать имя макросу, выбрать место для сохранения нового макроса и выбрать дополнительные опции. Выполните следующие шаги:
1.	Выберите команду Сервис | Макрос | Начать запись (Tools | Macro | Record New Macro). В Word отображается диалоговое окно Запись макроса (Record Macro), показанное на рис. 1.12.
Заполненное диалоговое окно
Запись макроса для макроса-примера ВыделитьТекст
Запись макроса	Р>Ж|
ДОя ма»<роса
|ВыделитьТекст
Назначить макрос
Макрос доступен для
jbcex документов (Normal dot)	▼
Описание
IМакрос записан И 01 2003 Владимир Кузьменко
Устанавливает Arial, Bold 12 для выделенного фрагмента текста
OK J Отмена
2.	В текстовом поле Имя макроса (Macro name) введите ВыделитьТекст (или Вы-делить_Текст) в качестве имени макроса. Это имя помогает запомнить, что выполняет макрос.
3.	Оставьте описание по умолчанию, в текстовом поле Описание (Description), но в добавление к существующему описанию введите следующий текст: Устанавливает Arial, Bold, 12 для выделенного текста. Этот дополнительный комментарий поможет вам (и другим) определить назначение этого макроса.
4.	Используйте раскрывающийся список Макрос доступен для: (Store Macro in:) для выбора места, в котором будет сохранен записанный макрос. Вы можете сохранить макрос в любом загруженном в данный момент глобальном шаблоне или в текущем документе. Так как вам необходимо, чтобы макрос мог использоваться в любом документе, над которым вы будете работать, выберите Всех документов (All Documents) (Normal.dot).
5.	Щелкните на кнопке ОК для начала записи макроса, если только вы не хотите добавить ваш макрос в панель инструментов или назначить для него «горячую клавишу». Для выбора любой из этих опций выполняйте инструкции, описанные в следующем разделе этой главы. Итак, вы теперь готовы выполнять действия, которые хотите записать.
Конкретные места хранения, доступные в Word в диалоговом окне Запись макроса, зависят от того, какие глобальные шаблоны у вас загружены в данный момент. Доступные варианты всегда включают шаблон Normal.dot и текущий активный документ.
На рис. 1.12 показано диалоговое окно Запись макроса, заполненное для макроса-примера ВыделитьТекст.
Использование панели инструментов и клавиатуры
для запуска макроса
Существуют две дополнительные опции, которые вы можете выбрать в диалоговом окне Запись макроса в Word: либо назначить «горячую клавишу» для нового макроса, либо связать его с командной кнопкой на панели инструментов. Если вы
Макросы и языки программирования
37
назначаете «горячую клавишу» для макроса, вы можете позже запускать этот макрос нажатием сочетания клавиш. Если вы связываете макрос с командной кнопкой на панели инструментов, то можете запускать его, щелкая эту кнопку на панели инструментов.
Используйте опции «горячей клавиши» и клавиатуры только в случае, если уверены, что будете очень чдсто использовать макрос, который собираетесь записывать макрорекордером. Если вы будете назначать «горячие клавиши» всем вашим макросам, у вас скоро не останется неназначенных сочетаний «горячих клавиш». Если вы будете связывать все ваши макросы с панелью инструментов, вам ее не хватит, хотя она достаточно большая.
Щелчок мышью на кнопке панели (Toolbars) или клавишам (Keyboard) для помещения вашего нового макроса на панель инструментов или назначения ему «горячей клавиши» приводит к запуску макрорекордера. Поэтому, если вы собираетесь использовать обе опции, выберите сначала кнопку панели, а затем нажмите кнопку клавишам для вывода на экран диалогового окна Настройка клавиатуры (Customize Keyboard).
Для того чтобы назначить макросу «горячую клавишу», щелкните на кнопке клавишам в диалоговом окне Запись макроса в Word. Открывается окно Настройка клавиатуры, показанное на рис. 1.13. Так как вы назначаете «горячую клавишу» новому макросу (который еще не был записан), список Категории (Categories) отключен. Имя записываемого вами нового макроса выбирается по умолчанию в списке Команды (Commands). Нажмите сочетание клавиш, которое Хотите использовать для запуска этого макроса; клавиши, которые вы нажимаете, появляются в текстовом окне Новое сочетание клавиш (Press new shortcut key). Щелкните на кнопке Назначить (Assign), чтобы назначить сочетание клавиш новому макросу. Щелкните на кнопке Закрыть (Close) для выхода из диалогового окна Настройка клавиатуры и переходите к записи макроса.
Как только вы закрываете диалоговое окно Настройка клавиатуры, Word активизирует макрорекордер и начинает запись ваших действий.
Рис. 1.13
Диалоговое окно Настройка клавиатуры позволяет назначить сочетание «горячих клавиш» для макроса
Запись ваших действий
Независимо от того, запускаете ли вы макрорекордер щелчком на кнопке ОК или, выбирая опцию панели (Toolbars) или клавишам (Keyboard), Word отображает панель Остановка записи (Stop Recorder). Когда макрорекордер начинает записывать ваши действия, на экране появляется значок магнитофонной кассеты как
38
Глава 1
часть указателя мыши. Макрорекордер сохраняет каждое действие, которое вы • выполняете, в новом макросе до тех пор, пока вы не остановите рекордер или не сделаете паузу.
Обратите внимание, что в строке состояния в нижней правой части окна Word появляется аббревиатура REC (ЗАП), чтобы напоминать вам о том, что Word записывает все ваши действия. В качестве примера выполните следующие действия: 1. Используйте список Шрифт (Font) на панели Шрифт для выбора шрифта Arial. 2. Используйте список Размер (Size) для выбора 12 в качестве нового размера шрифта.
3. Выберите Полужирный (Bold) из списка Начертание (Font Style) для включения атрибута полужирного шрифта для текста (рис. 1.14).
Это были действия, необходимые вам для этого отдельного макроса, и теперь вы готовы к остановке макрорекордера.
Рис. 1.14
Диалоговое окно Шрифт позволяет задать характеристики текста
Шрифт
Шрифт Интервал Анимация
Шрифт	Начертание	Размер
|^.al ........................... IBSS& ~ [Д~~
Цвет текста
Авто
Подчеркивание
V] [(нет)	Г [
Видоизменение
Г“ зачеркнутый двойное зачеркивание
Г надстрочный
~~ подстрочный
Г~ с тенью
Г Контур
Г приподнятый
Г~ утопленный
Г малые прописные j gee прописные Г~ скрытьм
Образец
выделенным
Шрифт TrueType Он используется для вывода как на экран, так и на
Остановка макрорекордера
Как было упомянуто в предыдущем разделе, Word начинает запись макроса и отображает панель Stop Recorder сразу после того, как вы щелкните на кнопке ОК в диалоговом окне Запись макроса. Завершив последовательности действий, которые вам необходимо записать, немедленно остановите макрорекордер.
Для остановки макрорекордера щелкните на кнопке Остановить запись (Stop Macro) на панели Остановка записи или выберите Сервис | Макрос | Остановить запись (Tools | Macro | Stop Recording). Для макроса-примера ВыделитьТекст вам следует остановить макрорекордер немедленно после выполнения шагов, указанных в предыдущем разделе.
Ваш новый Word-макрос является теперь законченным и готовым к запуску. Далее в этой главе вы узнаете, как запускать этот новый макрос.
Запись макроса в Excel 2002
Для этого примера предположим, что вам также часто приходится применять полужирный шрифт Arial 12-го размера в качестве стиля форматирования симво
Макросы и языки программирования
39
лов ячеек рабочих листов, к которым вы хотите привлечь особое внимание. В этом случае вы не можете использовать именованный стиль Excel [доступный с помощью команды меню Формат | Стиль (Format | Style)] для применения необходимого форматирования символов, поскольку это повлияло бы на все атрибуты ячеек, а не только на формат символов. Вместо этого вы должны каждый раз задавать атрибуты шрифта вручную. С целью сокращения времени, необходимого для форматирования текста, вам необходимо записать макрос, который выбирает полужирный шрифт Arial 12-го размера и применяет это форматирование к любой ячейке или диапазону ячеек текущего выделенного фрагмента.
Задание стартовых условий
Так как вам необходимо, чтобы макрос работал с любой выделенной ячейкой или диапазоном ячеек, стартовыми условиями для этого макроса являются открытая рабочая книга с выделенным диапазоном ячеек в активном рабочем листе. Чтобы'задать стартовые условия для данного конкретного примера в Excel, выполните следующие шаги:
1.	Запустите Excel 2002, если он еще не запущен.
2.	Откройте какую-либо рабочую книгу.
3.	Выберите какой-либо рабочий лист.
4.	Выделите любую ячейку в рабочем листе.
Вы только что создали необходимые стартовые условия, чтобы записать общий макрос для форматирования символов любой выделенной ячейки или диапазона ячеек в рабочем листе Excel.
Назначение имени и выбор места для сохранения макроса
Для запуска макрорекордера в Excel, назначения имени макросу, выбора места для сохранения нового макроса и выбора дополнительных опций выполните следующие шаги:
1.	Выберите команду Сервис | Макрос | Начать запись (Tools | Macro | Record New Macro). В Excel отображается диалоговое окно Запись макроса (Record Macro), показанное на рис. 1.15.
3 длись макро

Рис. 1.15
Заполненное диалоговое окно Запись макроса для макроса-примера FormatArialBold12
ймя макроса |FcrmatAriaBoldl2	——
Сочетание клавиш Сохранить g
CtrM-| [личная книга макросов т । ^писание [Макрос записан 1/11/2003 (Владимир Кузьменко) [форматирует ячейку Arial Вой, 12|
ОК < Отмена [
2.	В текстовом окне Имя макроса (Macro Name) введите FormatArialBoldl2 в качестве имени макроса. Это имя помогает запомнить, что выполняет макрос.
3.	Оставьте описание по умолчанию, введенное в текстовом окне Описание (Description), но введите следующий текст дополнительно к существующему описанию: Форматирует текст диапазона: Arial, Bold, 12. Этот дополнительный комментарий поможет вам (и другим) определить назначение данного макроса.
4.	Используйте список Сохранить в (Store macro in) для выбора места, в котором будет сохранен записанный макрос. Доступными вариантами являются Личная книга макросов (Personal Macro Workbook), Новая книга (New Workbook)
40
Глава 1
и Эта книга (This Workbook). Поскольку вам необходимо, чтобы этот макрос был доступен во всех ваших рабочих книгах, выберите Личная книга макросов. Выбор Эта книга приведет к тому, что Excel сохранит новый макрос в текущей активной рабочей книге. Выбор Новая книга приведет к созданию в Excel новой рабочей книги, в которой будет сохранен этот макрос, — рабочая книга, которая была активной при запуске вами макрорекордера, остается активной рабочей книгой; любые действия, которые вы записываете, выполняются в этой книге, а не в новой рабочей книге, созданной для сохранения макроса.
5.	Если вы уверены в том, что будете часто использовать макрос, который собираетесь записывать, можете назначить для его запуска горячую клавишу. Если — да, введите горячую клавишу в текстовое окно Сочетание клавиш (Shortcut Key) окна Запись макроса.
6.	Щелкните на кнопке ОК для начала записи макроса.
На рис. 1.15 показано диалоговое окно Запись макроса, заполненное для макроса-примера FormatArialBoldl2.
Запись действий
Как только вы щелкните на кнопке ОК в диалоговом окне Запись макроса, Excel запустит макрорекордер, отобразит панель Остановить запись (Stop Recorder) и начнет запись ваших действий. Макрорекордер сохранит каждое ваше действие в новом макросе.
На рис. 1.16 показана панель Остановить запись в Excel, выведенная на экран во время сеанса записи макроса. (На рис. 1.16 записываемым макросом является макрос-пример FormatArialBoldl2). Заметьте, что в строке состояния в нижней левой части окна Excel появляется слово Запись (Recording) как напоминание о том, что Excel записывает все ваши действия.
Не всегда при запуске макрорекордера вы можете увидеть на экране панель Оста-новить запись Поскольку это — обычная панель, ее можно отображать или не ото-бражать Этим, как и другими панелями, управляет команда Панели инструментов (Toolbars) меню Вид (View) В любом случае (при наличии на экране панели Остановить запись или ее отсутствиии) вы можете остановить макрорекордер, выбрав Сервис | Макрос | Остановить запись
В Microsoft Excel-PRESK2
Рис. 1.16
Excel отображает панель Остановить запись и слово Запись (в строке состояния) во время записи макроса
файл Правка Вид Вставка фодат Сервис Да-ные окно Справка	~ - в х
И & & &	120% ” СУ ? Arid	* 12 - [ж К ч g, S » gi «в t» • •й” • Д, - ”
А7 ▼ д Группа товара Аксессуары	7 июл 2001
j Общество с	—
7 ограниченной ч ответственностью ,	125047, Россия. Москва. ул.Красноармеиская. д.4
4 Л’ «	,
ГТр| ВЭ С Тел.(095) 212-38-01. 212-64-23 Факс (095) 212-39-14 E-mail:symbas@orc.ru
6 ~~
" [Группа товара: Аксессуары	7 июл 20»
8
9		Наименование	Цена		Наименование
10	1	(A) 64-bit "DOCTOR V 64"	0	44	(A) Gun PSX Jolt
11	2	(A) Automatic RF SWITCH SPS	0	45	(Al Gun PSX Judge Dredd EL-'
12	3	(A) AV Multi Box	9,5	46	(Al Joystick PSX Arcade Rex
Н	4	(A) CD LensCleaner	n	47	(A) Joystick PSX Sakkara 602
и И 4	Я н	(Д) rioaninn Krt МП \ Прейскурант / Sheetl / Dialog 1 /			/Д) Invctirk
Готово Эагмсь
Макросы и языки программирования
41
По умолчанию панель Остановить запись в Excel содержит две командные кнопки (см. рис. 1.16). Левая кнопка — это кнопка Остановить запись (Stop); щелкните на этой кнопке для остановки макрорекордера. Правая кнопка — это кнопка Относительная ссылка (Relative Reference). По умолчанию Excel записывает абсолютные ссылки на ячейки в ваши макросы. Если вы, например, начнете запись с выделенной ячейки А7, а затем выделите ячейку справа От А7, то есть В7, то ваш записанный макрос также будет выделять ячейку В7, и так каждый раз, когда он будет запускаться.
Если вы щелкаете на кнопке Относительная ссылка, Excel записывает относительную ссылку на ячейку каждый раз, когда вы выделяете какую-либо ячейку. Если выделенной в данный момент является ячейка А7 и вы выбираете ячейку справа от нее во время записи с относительными ссылками, то Excel записывает, что вы выделили ячейку, находящуюся на 1 столбец и 0 строк правее от текущей выбранной ячейки. Когда вы запустите записанный макрос, он выделит ячейку, находящуюся непосредственно справа от активной ячейки.
Кнопка Относительная ссылка является кнопкой-переключатпелел» (toggle). Когда запись с относительными ссылками отключена, кнопка Относительная ссылка выглядит плоской; при помещении курсора мыши на кнопку вид кнопки изменяется и она выглядит отжатой. Когда запись с относительной ссылкой включена, кнопка Относительная ссылка на панели Остановить запись нажата (находится в «утопленном» положении). Щелкая на кнопке Относительная ссылка, можно включать и выключать запись с относительными ссылками во время записи по вашему желанию.
Для выполнения записи макроса FormatArialBoldl2 действуйте следующим образом:
1.	Выберите команду Формат | Ячейки (Format | Cells) для отображения диалогового окна Формат ячеек (Format Cells).
2.	Щелкните на ярлычке Шрифт (Font) для отображения опций шрифта. (На рис. 1.17 показано диалоговое окно Формат ячеек с отображенными опциями шрифта).
3.	Выберите Arial в списке Шрифт (Font). (Выполните этот шаг, даже если шрифт Arial уже выбран).
Рис. 1.17
Диалоговое окно Формат ячеек в Excel с опциями шрифта, заполненное для макроса FormatArialBold12
Формат ячеек
Число | Вьравнивание j Шрифт p граница < Вид | Защита J
Размер:
Шрифт;
| Arial
& Abertis Extra Bold fi Abertis Medium
Начертание: | полужирный
обычный курсив
Подчеркивание:
|нет
полужирный курсив Цвет: I Авто
I Обычный


- видоизменение Г~ зачеркнутый Г верхний индекс Г нижний индекс
Образец
АаВЬБбЯя
Шрифт типа TrueType. Шрифт будет использован как для вывода на экран, так и для печати.
ОК	Отмена
42
Глава 1
4.	Выберите Полужирный (Bold) в списке Начертание (Font Style).
5.	Выберите 12 в списке Размер (Size).
6.	Щелкните на кнопке ОК, чтобы закрыть диалоговое окно Формат ячеек и изменить выделенную ячейку в рабочем листе.
Остановка макрорекордера
После того как вы закончите выполнение последовательности действий для записи, вам следует немедленно остановить макрорекордер Excel. Для этого щелкните на кнопке Остановить запись (Stop Macro) на панели Остановить запись (Stop Recorder) или выберите команду Сервис | Макрос | Остановить запись (Tools | Macro | Stop Recording).
Для макроса-примера FormatArialBoldl2 вам необходимо остановить макрорекордер сразу же после того, как вы щелкните на кнопке ОК, чтобы закрыть диалоговое окно Формат ячеек. Ваш новый макрос в Excel теперь закончен и готов к выполнению. Вы узнаете о том, как выполнить новый макрос, позже в этой главе.
Код макроса
При записи макроса в Word, Excel или PowerPoint рекордер сохраняет последовательность текстовых инструкций, которые описывают на языке программирования Visual Basic for Applications различные действия, выполняемые вами в то время, когда рекордер включен. Это текстовое описание ваших команд называется исходным кодом (source code) для этого макроса. Позже, когда вы запускаете макрос, VBA считывает записанные в исходном коде инструкции и выполняет каждую последовательно, дублируя таким образом действия, которые вы выполняли, когда записывали макрос.
В следующих строках приведен исходный код, полученный при записи вами макроса ВыделитьТекст в Word 2002. Обратите внимание, имя и описание макроса, которые вы ввели в диалоговое окно Запись макроса, включены в начало исходного кода записанного макроса.
Листинг 1.2. Макрос, записанный в Word
1 Sub ВыделитьТекст()
2 ’
3 ' ВыделитьТекст Макрос
4 1 11 Макрос записан 11.01.2003 Владимир Кузьменко
5 ' "&chr (10)&"Устанавливает Arial, Bold, 12 для выделенного
б ' фрагмента текста
7 With Selection.Font	I
8	.Name	=	"Arial"
9	.Size	=	12
10	.Bold	=	True
11	.Italic	= False
12	.Underline = wdUnderlineNone
13	.Underlinecolor = wdColorAutomatic
14	.StrikeThrough = False
15	.DoubleStrikeThrough = False
16	.Outline = False
17	.Emboss = False
18	.Shadow = False
19	.Hidden = False
20	.SmallCaps = False
21	.AllCaps = False
22	.Color = wdColorAutomatic
Макросы и языки программирования
43
23	.Engrave = False
24	.Superscript = False
25	.Subscript = False
26	.Spacing = -0.1
27	.Scaling = 100
28	.Position = 0
29	.Kerning = 10
30	.Animation = wdAnimationNone
31	End With
32 End	Sub
Подобный код производится макрорекордером Excel. Следующие строки представляют собой исходный код, полученный при записи макроса FormatArial-Boldl2 в Excel. Заметьте, что имя и описание макроса, которые вы ввели в диалоговое окно Запись макроса, также включены в начало исходного кода записанного макроса.
Листинг 1.3. Макрос, записанный в Excel
1	Sub FormatArialBoldl2()
2	'
3 ' FormatArialBoldl2 Макрос
4 ' Макрос записан 1/11/2003 (Владимир Кузьменко) Форматирует
5 ' ячейку: Arial, Bold, 12
6
7
8	With Selection.Font
9	.Name = "Arial"
10	.Fontstyle = "полужирный"
11	.Size = 12
12	.Strikethrough = False
13	.Superscript	= False
14	.Subscript =	False
15	.OutlineFont	= False
16	.Shadow = False
17	.Underline =	xlUnderlineStyleNone
18	.Colorindex = xlAutomatic
19	End With
20	End Sub
Так же просто записать макрос и в PowerPoint. Если вы перед редактированием слайда выполните команды (как и в Word, и в Excel) Сервис | Макрос | Начать запись, то после редактирования и форматирования строк Заголовок слайда и Подзаголовок слайда и отключения макрорекордера вы можете получить следующий код макроса.
Листинг 1.4. Макрос, записанный в PowerPoint
1 Sub Макрос1()
2 '
3 ' Макрос записан 1/11/2003. Автор: Владимир Кузьменко
4 '
5
6	ActiveWindow.Selection.SlideRange.Shapes("Rectangle 2").Select
7	ActiveWindow.Selection.ShapeRange.TextFrame.TextRange.Select
8	ActiveWindow.Selection.ShapeRange.TextFrame.TextRange._
Characters(Start:=1, Length:=0).Select
9	With ActiveWindow.Selection.TextRange
10	.Text = "Новый слайд"
44
Глава 1
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
With .Font
.Name = "Arial"	<	i
.Size = 44 .Bold = msoFalse .Italic = msoFalse	।
.Underline = msoFalse .Shadow = msoFalse .Emboss = msoFalse	»
.BaselineOffset = 0 •AutoRotateNumbers = msoFalse .Color.SchemeColor = ppTitle End With End With ActiveWindow.Selection.ShapeRange.TextFrame.TextRange._
Characters(Start:=l, Length:=ll).Select With ActiveWindow.Selection.TextRange.Font
•Name = "Times New Roman"
•Size = 36
•Bold = msoTrue
.Italic = msoFalse
.Underline = msoFalse
.Shadow = msoFalse
.Emboss = msoFalse
.BaselineOffset = 0
.AutoRotateNumbers = msoFalse
.Color.SchemeColor = ppTitle End With
ActiveWindow.Selection.SlideRange.Shapes("Rectangle 3").Select ActiveWindow.Selection.ShapeRange.TextFrame.TextRange.Select ActiveWindow.Selection.ShapeRange.TextFrame.TextRange._
Characters(Start:=1, Length:=0).Select With ActiveWindow.Selection.TextRange
.Text = "Первый подзаголовок" With .Font .Name = "Arial" .Size = 32 .Bold = msoFalse •Italic = msoFalse .Underline = msoFalse .Shadow = msoFalse .Emboss = msoFalse •BaselineOffset = 0 .AutoRotateNumbers = msoFalse .Color.SchemeColor - ppForeground End With End With
ActiveWindow.Selection.ShapeRange.TextFrame.TextRange._ Characters(Start:=1, Length:=19).Select
With ActiveWindow.Selection.TextRange.Font
.Name = "Arial"
.Size = 32
.Bold = msoFalse
.Italic = msoTrue
.Underline = msoFalse
.Shadow = msoFalse
.Emboss = msoFalse	»
•BaselineOffset = 0
.AutoRotateNumbers = msoFalse
.Color.SchemeColor = ppForeground End With
End Sub
Макросы и языки программирования
45
На данном этапе работы с книгой еще рано изучать приведенные листинги. Вы можете записывать и выполнять макросы, даже не заглядывая в исходный код или не зная, что данный макрос выполняет. В следующей главе описываются разные составляющие макроса и объясняется, как находить исходный код для определенного макроса и выводить его на экран для редактирования и проверки.
Выполнение макросов
После того как вы записали рекордером макрос, этот макрос можно выполнить. При выполнении макроса Word, Excel или PowerPoint следуют всем инструкциям, записанным в макросе.
И в Word, и в Excel макрос запускается выбором команд Сервис | Макрос | Макросы (Tools | Macro | Macros). Word отображает диалоговое окно Макрос (Macros), приведенное на рис. 1.18, a Excel — на рис. 1.19. Эти диалоговые окна идентичны1 — выберите необходимый вам макрос в списке Имя (Macro name) и щелкните кнопку Выполнить (Run) для запуска макроса (другие кнопки в диалоговом окне Макрос обсуждаются далее).
Рис. 1.18
Используйте в Word диалоговое окно Макрос для выбора макроса, который необходимо выполнить (приводятся только макросы, доступные в текущем документе или в общих шаблонах)
Рис. 1.19
Используйте в Excel диалоговое окно Макрос для выбора макроса, который необходимо выполнить
Макрос
Имд макроса
Описание
Макрос записан 1/11/2003 (Владимир Кузьменко)
Форматирует ячейку Aral, Вой, 12
1
В Word Список с именами макросов называется Имя, а в Excel — Имя макроса.
46
Глава 1
Например, для выполнения макроса ВыделитьТекст, который вы записали ранее в этой главе, сначала выделите некоторый текст в документе. Затем выберите Сервис | Макрос | Макросы для отображения диалогового окна Макрос. Выберите макрос ВыделитьТекст в списке Имя и затем щелкните на кнопке Выполнить, чтобы выполнить макрос ВыделитьТекст. Выделенный перед выполнением макроса текст в вашем документе будет отформатирован с использованием полужирного шрифта Arial 12-го размера.
Для выполнения записанного вами в Excel макроса FormatArialBoldl2 выберите сначала ячейку в рабочем листе (предпочтительнее ячейку, содержащую некоторый текст, чтобы вы могли видеть изменения). Выберите команду Сервис | Макрос | Макросы для отображения диалогового окна Макрос и затем выберите макрос PERSONAL. XLS!FormatArialBoldl2 в списке Имя макроса. Наконец, щелкните на кнопке Выполнить для запуска макроса FormatArialBoldl2. Текст в любой ячейке, которая была выделена до запуска вами этого макроса, будет теперь иметь формат полужирного шрифта Arial 12-го размера.
В Word диалоговое окно Макрос перечисляет макросы, сохраненные в текущем документе или в любых общих шаблонах (см. рис. 1.18). Используйте список Находится в: для выбора определенного документа или шаблона, если затрудняетесь найти нужный вам макрос в полном списке доступных макросов.
Диалоговое окно Макрос в Excel перечисляет макросы, сохраненные в любых рабочих книгах, открытых в данный момент. Имя рабочей книги, содержащей макрос, помещено перед именем макроса в списке Имя макроса, если макрос не находится в текущей рабочей книге (как в случае с макросом PERSONAL.XLS! For-matArialBoldl2). Если необходимый вам макрос не находится в списке, откройте рабочую книгу, в которой был сохранен этот макрос, чтобы сделать макрос доступным перед тем, как вы откроете диалоговое окно Макрос.
Если вы использовали опции диалогового окна Запись макроса (Record Macro) в Word для назначения вашему макросу горячей клавиши или кнопки на панели инструментов, вы можете также запускать этот конкретный макрос, щелкая на соответствующей кнопке панели инструментов или нажимая соответствующее сочетание клавиш. Как и в случае с макросами, перечисленными в диалоговом окне Макрос в Word, только макросы, сохраненные в текущем документе или в общем шаблоне, добавляются к панели инструментов или могут иметь активизированные горячие клавиши.
Аналогично, если вы назначили горячую клавишу в диалоговом окне Запись макроса в Excel, вы можете запускать этот конкретный макрос, нажимая сочетание назначенных клавиш. Как и в случае с макросами, перечисленными в диалоговом окне Макрос в Excel, только макросы, сохраненные в текущей отрытой рабочей книге (это не должна быть обязательно активная рабочая книга), могут иметь активизированные горячие клавиши.
Как вы уже знаете, вы можете также запускать макросы в Word и Excel, назначая им кнопки на панели инструментов или создавая для их вызова пункты меню. Вы можете также назначить макросу кнопку или графический объект, помещенный непосредственно в рабочий лист Excel или в документ Word. Для получения более полной информации об использовании интерактивных возможностей для назначения макросов кнопкам панели и графическим объектам в документах и рабочих листах обращайтесь к разделам справочной системы Excel и Word.
Примеры записи более полезных макросов
Закрепим первые успехи в изучении записи макросов, чтобы после прочтения этой главы вы уже могли уверенно записывать и использовать макросы, например, в Word 2002.
Макросы и языки программирования
47
Оформление замечаний
Начнем с постановки задачи. Пусть вам при написании некоторого отчета или статьи необходимо выделять каким-либо особенным способом части текста, в которых вы хотите высказать свое мнение, дать совет или предупредить читателя о чем-либо. В таких случаях неплохо было бы поместить в текст заголовок и выделить абзац или более, например, рамкой и отличным от остального текста стилем. Итак, решено, что нужен макрос, который будет выполнять следующие действия: 1) выводить заголовок Замечание стилем Замечание_заголовок, 2) устанавливать стиль последующего абзаца Замечание_текст. Понятно, что эти стили необходимо создать заранее и при этом нужно при создании стиля Замечание_заголовок следующим за ним стилем указать стиль Замечание_текст.
Перед тем как начать запись макроса рекордером, всегда планируйте свои дей-/дгх. ствия до мельчайших деталей, пока не научились редактировать записанные макросы.
Выполните следующие шаги:
1.	Перейдите на новую строку текста.
2.	Выберите Сервис | Макрос | Начать запись (Tools | Macro | Record New Macro).
3.	В окне Запись макроса (Record Macro) в поле Имя макроса (Macro name) введите имя нового макроса «Замечание».
4.	В поле Описание (Description) добавьте «Подготавливает текст-замечание».
5.	Нажмите на кнопку клавишам (Keyboard). При появлении окна Настройка клавиатуры (Customize Keyboard) нажмите комбинацию клавиш, например, Alt+Ctrl+З, а затем — кнопки Назначить (Assign) и Закрыть (Close).
6.	После появления на экране панели Остановить запись выберите на панели инструментов Word стиль Замечание_заголовок, введите слово Замечание (этим стилем) и нажмите клавишу Enter.
7.	Остановите запись, щелкнув на кнопке Остановить запись (Stop Macro) на одноименной панели или выбрав команду Сервис | Макрос | Остановить запись (Tools | Macro | Stop Recording).
Теперь у вас имеется макрос, который всегда при нажатии вами комбинации клавиш Atl+Ctrl+З будет производить подготовительные действия для ввода текста замечания. Чтобы проверить это, перейдите на новую строку текста и нажмите вышеуказанную комбинацию клавиш. Если вы сделаете все правильно, то на экране появится заголовок «Замечание», а следующий за ним абзац будет иметь стиль Замечание_текст.
Подписи к рисункам
Подпись к рисункам — это тоже одна из частых операций при написании различного рода документов. Поэтому запишем еще один макрос, который будет выполнять следующее: 1) автоматически задавать номер рисунка; 2) устанавливать стиль Рис_номер для номера рисунка; 3) устанавливать стиль Рис_текст. После выполнения такого макроса остается только ввести текст подписи.
Выполните следующие шаги:
1.	Перейдите на новую строку текста.
2.	Выберите Сервис | Макрос | Начать запись.
3.	В окне Запись макроса в поле Имя макроса введите имя нового макроса Номерурисунка.
48
Глава 1
4.	В поле Описание добавьте Автоматически нумерует рисунок, устанавливает стиль подписи рисунка.
5.	Нажмите на кнопку клавишам. При появлении окна Настройка клавиатуры нажмите комбинацию клавиш, например, Alt+Ctrl+N, а затем — кнопки Назначить и Закрыть.
6.	После появления на экране панели Остановить запись выберите Вставка | Ссылка | Название (Insert | Reference | Caption) для вывода окна Название (рис. 1.20). В этом окне щелкните кнопку Создать (New Label), а в окне Новое название (New Label) (рис. 1.21) введите, например, Рис. и щелкните кнопку ОК.
Рис. 1.20
Используйте диалоговое окно Назаание для создания нового заголовка к подрисуночной подписи и задания свойств заголовка
Название
Название.
|Рмсуток 1 Параметры
подпись: (Рисунок
1	J Создать... |	| Нумерация... j
Ав1оназвание... [	| ОК | Отмена j
Рис. 1.21
Введите, например, "Рис." и щелкните кнопку ОК
7.	В окне Название (рис. 1.22) щелкните кнопку Нумерация. В появившемся окне Нумерация названий (рис. 1.23) установите флажок Включить номер главы и выберите в окне комбинированного списка начинается со стиля стиль заголовка главы (который должен быть нумерованным). Щелкните на кнопке ОК в этом окне, а затем и в окне Название.
»ис. 1.22
J окне Название щелкните кнопку Нумерация
Установите стиль текущей строки Рис_номер, нажмите клавишу Enter. Остановите запись, щелкнув на кнопке Остановить запись (Stop Macro) на одноименной панели или выбрав команду Сервис | Макрос | Остановить запись (Tools | Macro | Stop Recording).
Макросы и языки программирования
49
Рис. 1.23
Установите флажок Включить номер главы и выберите в окне комбинированного списка начинается со стиля стиль заголовка главы (который должен быть нумерованным)
Формат:
включить номер главы
начинается со стиля I Заголовок 1
разделитель:	р(точка)
Образец: Рисунок П-1, Таблица 1-А
ОК I Отмена
После этого вы можете использовать макрос Номер_рисунка для автоматической нумерации рисунков, а после выполнения макроса — вводить текст подписи. Именно так были подготовлены подписи к рисункам этой главы.
В окне Caption можно указать редактору использовать в нумерации рисунка номер текущей главы документа, но эта возможность не применена в данном макросе
Подчеркивание листинга
Если вы уже успели заметить, листинги отделяются в этой книге от обычного текста строкой из символов . Вы тоже можете использовать подобное оформление для своих текстовых документов. Чтобы записать макрос с подчеркивающей строкой, необходимо сначала создать стиль, которым вы хотите выводить подчеркивающие символы, а затем выполнить обычные действия, связанные с включением рекордера, выбором созданного стиля, вводом строки символов и остановкой рекордера.
1.	Создайте новый стиль для строки с подчеркивающими символами. В данном случае в окне Шрифт (Font) были отмечены флажки верхний индекс (Superscript) и малые прописные (Small caps).
2.	Выберите Сервис | Макрос | Начать запись (Tools | Macro | Record New Macro).
3.	В окне Запись макроса в поле Имя макроса введите имя нового макроса «Line-
Under».
4.	После появления на экране панели Остановить запись выберите на Word-панели инструментов Форматирование (Formatting) стиль Подчеркнутый (Underline), введите строку символов (этим стилем) и нажмите клавишу Enter.
5.	Остановите запись, щелкнув на кнопке Остановить запись на одноименной панели или выбрав команду Сервис | Макрос | Остановить запись.
В отличие от предыдущих случаев при записи последнего макроса не была выбрана «горячая клавиша». Вы можете указать ее, хотя делать это необязательно.
Макрос-шутка
В качестве шутки вы можете написать очень простой макрос, который будет запускаться при каждой загрузке, например, Excel-рабочей книги. Вы можете подшутить над своим сослуживцем-менеджером, который 1-го апреля (в день смеха и шуток) оставил свой компьютер без присмотра, уходя’ покурить (встречаются у нас люди, желающие на своем примере убедиться во вреде курения). Представьте себе такую ситуацию: загружает объект вашей шутки рабочую книгу, над которой он трудился не один день, а ему на экран вместо знакомых колонок цифр и прочего выдается сообщение о том, что в результате разрушительного действия неизвестного вируса
50
Глава 1
(на компьютере же была установлена совершенно новая антивирусная программа!) рабочая книга полностью уничтожена. Эта первая шутка будет очень непродолжительной: после щелчка на кнопке ОК все будет работать по-прежнему. Далее в книге мы вернемся к этому макросу-шутке для добавления более «умного» кода.
Итак, «пробираемся» тайком на компьютер, загружаем файл, например, с именем Важные_данные. Рабочий лист этого файла может иметь, например, вид, как представлено на рис. 1.24.
Рис. 1.24
Главное
при создании макроса-шутки, чтобы файл, котором будет размещен макрос, был хоть как-то «дорог» тому, кто его создал
Выберите Сервис | Макрос | Редактор Visual Basic (Tools | Macro | Visual Basic Editor). В окне редактора щелкните на стрелке кнопки Insert UserForm и выберите Module в появившееся окно кода введите следующий код:
Sub Auto_open()
MsgBox "Ой1 Мамочки родные1 Самый страшный вирус " & "разрушил этот файл1"
End Sub
Рис. 1.25				L.tlX
Шутка закончится,	bfe'l <£айл Правка Вид Встарка Формат	и	-.j	-.правка	«• . 9 X
как только кто-либо	В й	120% -	7 Arial	’12 -г ж К Н SS. &	4Й	Ж .F
щелкнет кнопку ОК	▼	ft ($) ОТЧ (м+р)книжка 16 бит бол A	] В	С		D	Е Т
	7 ($) ОТЧ (м+р) комп Simba МР2	0	0
	8 ($) ОТЧ (м+р) кор 16бит	0	0
	9 ($) ОТЧ (м+р) кор 8бит	0	0
	10 ($) ОТЧ (м+р) короб ВЗЛОМ КОД	0	0
	11 |($) ОТЧ (м«р)книжка 16 бит бол		1	0	0
	12 ($) ОТЧ печать SM4	0	0
	13 ($) ОТЧ шнур DC			ft.
	14 ($) отчие книжкЖИЕИЯИИ		
	15 ($) ОТЧИС КНИЖК		
	16 ($) ОТЧИС КНОПКА Ои1 Мамочки родные' Самый страшный вирус разрушил этот файл		
	17 ($) ОТЧИС КОР KAJ		
	18 ($) ОТЧИС КОР KAI	1 О* 1	
	19 ($) отчие корпус		
	20 ($) ОТЧИС КОРПУС ДЖ КА S А-168	0	0
	21 ($) ОТЧиЬ Корпус Дж ка Sega	0	0
	22 ($) ОТЧИС Корпус комп Simba s	0	0
	23 ($) ОТЧИС КРЕСТ ДЖ A SEGA	0	0
	24 ($) ОТЧИС ПРИСТАВ 8 бит SIMBAS	0	о
	26 ($) ОТЧИГ ОРОРКА ДЖОЙСТИКА	П,	Л	’
	И 1 ► Н \Sbeetl / Sheet2 / Sheets /	!>'	! >1Г, 3
Макросы и языки программирования
51
Обратите внимание на имя Sub-программы. Эта программа запускается при открытии рабочей книги. Далее мы будем этим пользоваться не только для шуток.
Пока никто не видит, щелкните кнопку Save Важные_данные.х1а, затем выберите File | Close and Return to Microsoft Excel. Теперь остается срочно закрыть рабочую книгу и принять «смиренную позу».
Как только ваш коллега вернется и загрузит этот файл, на экране он увидит что-то похожее на рис. 1.25.
и .	-s.>
Гл«в« 2
Среда Редактора Visual Basic
»
В первой главе вы узнали, как записывать и выполнять макросы в Word и Excel. Перед редактированием и написанием макросов вам следует узнать больше о том, где сохраняются макросы. Необходимо также иметь общее представление о компоненте VBA Editor, его командах меню и кнопках панелей инструментов и о том, как они включаются в Word и Excel.
Модули
Вы уже знаете из первой главы, что макросы Visual Basic for Applications сохраняются как часть файлов, в которых Word, Excel и Access обычно содержат свои данные, — макросы сохраняются в файлах документов в Word и в файлах рабочих книг в Excel. Макросы сохраняются в специальной части файла данных, называемой Modules (модули). Модуль VBA содержит исходный код (source code) макроса — текстовое представление инструкций. Каждый документ Word (или шаблон документа) может содержать один или несколько модулей или не содержать никакого модуля; аналогично, каждый файл рабочей книги Excel может не содержать модулей или содержать один или несколько модулей. Модули, сохраняемые в одном документе Word или рабочей книге Excel, имеют общее название Project (проект).
Знание того, как Word и Excel именуют создаваемые в них модули, поможет вам находить ваши записанные рекордером макросы, когда вам потребуется просмотреть или редактировать их. В следующих нескольких параграфах описывается, как Word и Excel выбирают имена модулей при записи макроса рекордером.
Модули в Word 2002
При записи макроса в Word вы можете определять только документ или шаблон, в котором Word сохраняет записанный макрос. В Word все записанные макросы сохраняются в модуле с именем NewMacros. Например, если вы хотите сохранить новый записанный макрос в шаблоне Normal.dot, Word сохраняет исходный код этого макроса в модуле NewMacros шаблона Normal.dot. Другой пример — если вы открываете документ с именем Ch02.doc, а затем записываете макрос в этот документ, Word сохранит записанный макрос в модуле NewMacros документа Ch02.doc. Если модуль NewMacros не существует, Word создаст его.
Word продолжает сохранять записанные макросы в модуле NewMacros документа или шаблоне документа, который вы выбираете, независимо от того, записываете ли вы дополнительные макросы в текущем или каком-либо другом сеансе работы.
Модули в Excel 2002
Как и в Word, при записи макроса в Excel вы можете определять только рабочую книгу, в которой Excel сохраняет записанный макрос, — текущую рабочую книгу, новую рабочую книгу или рабочую книгу Personal.xls. Excel выбирает модуль, в котором сохраняется записанный макрос, и при необходимости создает этот модуль. Правила выбора модуля, в котором сохраняется ваш записанный макрос, в Excel являются более сложными, чем в Word.
Среда Редактора Visual Basic
53
Когда Excel создает модуль, в котором сохраняется записанный макрос, модулю присваивается имя ModuleN, где N — это количество модулей, созданных для определенной рабочей книги во время текущего сеанса работы. Например, в первый раз, когда вы сохраняете записанный макрос в Personal.xls (личной книге макросов), Excel создает модуль с именем Modulel. Если вы продолжаете записывать макросы в том же сеансе работы и сохранять их в Personal.xls, Excel продолжает сохранять записанные макросы в том же модуле Modulel до тех пор, пока вы не выберете другую рабочую книгу. Если позже в том же сеансе работы вы опять захотите сохранить записанные макросы в Personal.xls, Excel добавляет другой модуль с именем Module2 в эту книгу.
Если какая-либо рабочая книга уже содержит модуль с тем же именем, что выбран в Excel для нового модуля, Excel увеличивает число в имени модуля до тех пор, пока имя нового модуля не будет отличаться от имен существующих модулей. Например, если вы начнете новый сеанс работы в Excel и затем захотите сохранить записанный рекордером макрос в книге Personal.xls, Excel сначала выбирает имя Modulel для нового модуля. Если же книга Personal.xls уже содержит модули с именами Modulel и Module2, Excel увеличивает число в имени модуля, чтобы оно не совпадало с существующими именами; новый модуль получает имя Module3.
Модули в PowerPoint 2002
При записи нового макроса макрорекордером в PowerPoint имя макроса, предлагаемое приложением по умолчанию, состоит из слова "Macro" и номера очередного макроса. Если в момент записи нового макроса вы имеете открытыми несколько файлов с презентациями, то вам в окне Record Macro будет предложен список открытых презентаций, для указания того, в какой презентации сохранить записываемый макрос.
Приложения Microsoft Visio и Microsoft FrontPage не имеют макрорекордера. Все «офисные» приложения позволяют содавать новые модули, в которых вы можете хранить свои собственные макросы.
Редактор Visual Basic
Для просмотра модулей, сохраненных в определенном документе, шаблоне или рабочей книге (и исходного кода макроса, который они содержат), вам необходимо использовать компонент Visual Basic Editor (Редактор Visual Basic). Этот компонент предоставляет инструментальные средства, которые используются для создания новых модулей, просмотра содержимого существующих модулей, создания и редактирования исходного кода макроса, создания пользовательских диалоговых окон и выполнения других задач, относящихся к написанию и обслуживанию программ на VBA. Как вы уже могли заметить, в этой книге компонент Редактор Visual Basic называется просто «Редактор VB».
Редактор VB содержит одни и те же возможности в Word, Excel и Access. Когда вы используете Редактор VB в Word, вы, фактически, используете тот же Редактор VB, который имеется в вашем распоряжении в Excel. В последующих нескольких параграфах рассказывается о том, как запускать Редактор VB, объясняется назначение различных окон, отображаемых компонентом Редактор VB, и описывается меню Редактора VB и команды панели инструментов.
Запуск Редактора VB
Как указывалось в предыдущих разделах, чтобы просмотреть модули или исходный код VBA, который они содержат, вам необходимо сначала запустить Ре
54
Глава 2
дактор VB. Независимо от того, работаете ли вы в Word или в Excel (а также и Access), Редактор VB запускается одним и тем же способом. Используйте для этого один из следующих приемов:
 Выберите Tools | Macro | Visual Basic Editor (Сервис | Макрос | Редактор Visual Basic).
 Нажмите сочетание клавиш AH+F11.
Каким бы приемом вы не воспользовались, Word (Excel или PowerPoint), запустит Редактор Visual Basic. На рис. 2.1 показано типичное окно Редактора Visual Basic, отображенное в Word. Окно Редактора VB, отображаемое в Excel (рис. 2.2), в основном подобно окну Редактора VB, показанному на рис. 2.1.
Рис. 2.1
Типичное окно Редактора VB в Microsoft Word
'Ji Microsoft Visual Basic - Normal - [NewMacros (Code))
0e Edt yiew Insert Format Qetxjg Bin Tools idd-Ins ^ndow tHp ia-в > « ем ‘ • ► и	x ra ini,con
- A Modules
«££ Modulel
•41 Module?
«4£ NewMacros
-	Protect (Chapter02)
- "*< Microsoft Word Objects
pGenerah	yj [ВыделитьТекст
Sub ВыделитьТекст()
’ ВыделитьТекст Ма«р ~ ’ Уекр z •залига-i 11.01.zjCL Lr uvwc T	— J"	f	> j.
With Selection.Font
.Name = "Arial"
NewMacros Module
Alphabetic j Categorized j
.Size = 12
.Bold - True
.Italic = False
.Underline = wdUnderlineNone .UnderlineColor = wdColorAutomatic .StrikeThrough = False .DoubleStrikeThrough = False
□ ~ ез

Рис. 2.2
Типичное окно Редактора VB в Microsoft Excel
Microsoft Visual Sasic - Книга! - {Modulel (Code)}
Bte Edit yiew Insert Format Qebug Bin Tools idd-Ins Window ИФ
Я-H J‘fUI  > H titfW’'' S Ini.an
Sf
▼j [(Declaiations)

♦ л Microsoft Excel Object a
- Modules
•% Modulel
~ VBAProject (Книга!)
- Microsoft Excel Object
С ЛИСТ1 (JVCTl)
Sub FormatArialBoldl2 ()
1*1
[Лист! Worksheet
Alphabetic j categorized j
jlVCTl DisplayPageBre. False DIsplayRightToL False Enable AutoFiteiFalse
With Selection.Font .Name = "Arial" .Fontstyle = "полужирный .Size = 12 .Strikethrough « False .Superscript = False .Subscript - False
gfopartie? - ЛИС.Н

Окна Редактора VB
В окне Редактора VB имеются три дочерних окна, каждое из которых отображает важную информацию о VBA-проекте. [Project (Проект) — это группа модулей и других объектов, сохраняемых в определенном документе, шаблоне документа, рабочей книге или шаблоне рабочей книги.] Каждое из окон Редактора VB отображается по умолчанию в прикрепленных (docked) положениях, показанных на рис. 2.1.
Среда Редактора Visual Basic
55
Если необходимо, вы можете переместить любое из дочерних окон Редактора VB в любое место на экране, перетаскивая строку заголовка {title bar) этого окна таким же образом, каким бы вы перемещали любое окно на рабочем столе Windows. Перетаскивание одного из дочерних окон из его прикрепленного положения приводит к тому, что оно становится плавающим окном. Плавающие {floating) окна всегда остаются видимыми поверх других окон.) Вы можете также изменять размер любого из дочерних окон Редактора VB, расширяя или уменьшая рамку окна для увеличения или уменьшения его размера, что подобно изменению размера любого окна на рабочем столе Windows.
Далее описываются три окна Редактора VB и их назначение.
Project Explorer (Окно проекта) содержит дерево-диаграмму открытых в данный момент файлов (документы, шаблоны или рабочие книги) и объектов, содержащихся в этих файлах (объекты host-приложения, модули, ссылки, формы и так далее). Project Explorer можно использовать для перехода к различным модулям и другим объектам в проекте VB при помощи кнопок (панели инструментов этого окна) View Code (Программа), View Object (Объект) и Toggle Folders (Папки).
Properties Window (Окно свойств) содержит все свойства объекта текущего выбора. В некоторых случаях, как в окне, показанном на рис. 2.1, свойства объекта состоят только из его имени. (Подробнее об объектах и свойствах объектов вы узнаете из следующих глав.) Вкладка Alphabetic (по алфавиту) этого окна предоставляет список свойств выделенного объекта, составленный из имен свойств в алфавитном порядке. Вкладка Categorized (по категориям) отображает свойства объекта, отсортированные по категориям.
Code Window — это окно, в котором вы можете просматривать, редактировать нли создавать исходный код VBA. В режиме Full Module View весь исходный код макроса в модуле отображается сразу в прокручивающемся текстовом окне, а макрос отделяется от другого макроса серой линией. Редактор VB позволяет также просматривать содержимое модуля в режиме Procedure View (представление процедуры). Чтобы выбрать режим просмотра, щелкайте кнопки в нижнем левом углу Code Window (см. рис. 2.3).
.Name = "Arial"
.Size = 12
.Bold = True
.Italic = False
.Underline = wdUnderlineNone
.Underlinecolor = wdColorAutomatic
.StrikeThrough = False
.DoubleStrikeThrough = False
Procedure View
Full Module View
Рис. 2.3. Чтобы выбрать режим просмотра, щелкайте кнопки в нижнем левом углу Code
Когда Code Window находится в режиме Procedure View, видимым является исходный код только одного макроса. Используйте раскрывающийся список Procedure (процедура) для просмотра другого макроса. В режиме Full Module View вы можете также использовать раскрывающийся список Procedure для быстрого перехода к отдельному макросу.
Используйте список Object List (объект) для выбора объекта, процедуры которого хотите просмотреть или редактировать. В случае стандартных модулей, таких как модули, в которых сохраняются записанные вами макросы, единственным выбором в списке Object List является General (общая область).
56
Глава 2
Теперь, ознакомившись с окнами Редактора VB, вы можете перейти к изучению панелей инструментов и меню Редактора VB, которые содержат команды, помогающие управлять окнами Project Explorer, Properties Window, Code Window и их содержимым.
Меню Редактора VB
В этом и последующих разделах рассказывается о меню и панелях инструментов Редактора VB. Сейчас вам необходимо лишь познакомиться с имеющимися командами. Можете попробовать использовать некоторые из этих команд, только убедитесь сначала, что вы экспериментируете с документом (или рабочей книгой), не содержащим незаменимых данных.
Далее в тексте значки "О” с находящимся внутри них текстом означают, что в зависимости от ситуации на это место подставляется имя файла, модуля, макроса, проекта и т д	       
Меню Файл (File)
Меню File, как и во всех приложениях Windows, содержит команды, относящиеся к сохранению и открытию файлов. В Редакторе VB меню File предоставляет команды, необходимые для сохранения изменений в проекте VBA и вывода на экран исходного кода вашего макроса VBA. В табл. 2.1 приведены команды меню File, их горячие клавиши и назначение каждой команды.
Таблица 2.1. Команды меню File
Команда	Горячая клавиша	Действие
Save <project> (сохранить <про-ект>)	Ctrl+S	Сохраняет текущий проект (презентацию, рисунок и т.д. в зависимости от приложения, в котором открыт Редактор VB) VBA на диске, включая все модули и формы.
Import File (импорт файла)	Ctrl+M	Добавляет существующий модуль, форму или класс в текущий проект (презентацию). Вы можете импортировать только модули, формы или классы, сохраненные ранее командой Export File из другого проекта (презентации).
Export File (экспорт файла)	Ctrl+E	Сохраняет текущий модуль, форму или класс в формате текстового файла для импортирования в другой проект или в целях архивирования.
Remove <item> (удалить <...>)		Перманентно удаляет модуль или форму текущего выбора из проекта (презентации) VBA. Эта команда не доступна, если в Project Explorer не выбран никакой элемент.
Print (печать)	Ctrl+P	Печатает модуль или форму для документирования или с целью архивирования.
Close and Return to ... (закрыть и вернуться в ... )	Alt+Q	Закрывает Редактор VB и возвращает вас в host-приложение и документ/рабочую кни-гу/презентацию, из которых был открыт Редактор VB.
Среда Редактора Visual Basic
57
Меню Edit (правка)
Меню Edit содержит команды, относящиеся к управлению исходным кодом макроса в Code Window и объектами в формах. В табл. 2.2 приведены имеющиеся команды меню Edit, их горячие клавиши и описывается действие, выполняемое каждой командой.
Таблица. 2.2. Команды меню Edit
Команда	Горячая клавиша	Действие
Undo (отменить)	Ctrl+Z	Отменяет самую последнюю команду. Не все команды могут быть отменены. Меню доступно только в случае, если есть, что отменять.
Redo (вернуть)		Возвращает самую последнюю команду, которую вы отменили.
Cut (вырезать)	Ctrl+X	Вырезает выделенный текст или объект и помещает его в Windows Clipboard. Выделенный текст или объект удаляется из модуля или формы.
Сору (копировать)	Ctrl+C	Копирует выделенный текст или объект и помещает его в Windows Clipboard. Выделенный текст или объект остается неизменным.
Paste (вставить)	Ctrl+V	Вставляет текст или объект из Windows Clipboard в текущий модуль или форму.
Clear (очистить)	Del	Удаляет выделенный текст или объект из модуля или формы.
Select АП (выделить все)	Ctrl+A	Выделяет весь текст в модуле или все объекты в форме.
Find (найти)	Ctrl+F	Подобно команде Find в Word или Excel, позволяет находить указанный текст в модуле.
Find Next (найти далее)	F3	Повторяет последнюю операцию Find.
Replace (заменить)	Ctrl+H	Подобно команде Replace в Word или Excel, позволяет находить указанный текст в модуле и заменять его другим текстом.
Indent (увеличить отступ)	Tab	Смещает весь выделенный текст вправо на интервал табуляции.
Outdent (уменьшить отступ)	Shift+Tab	Смещает весь выделенный текст влево на интервал табуляции.
List Properties/ Methods (список свойств/методов)	Ctrl+J	Открывает список в List Properties/ Methods, отображая свойства и методы объекта, имя которого вы только что ввели. Когда курсор вставки находится на пустом месте в List Properties/ Methods эта команда открывает список глобально доступных свойств и методов.
List Constants (список констант)	Ctrl+ Shift+J	Открывает список в Code Window, отображающий допустимые константы для свойства, которое вы только что ввели с предшествующим знаком ".
58
Глава 2
Команда	Горячая клавиша	Действие
Quick Info (сведения)	Ctrl+I	Открывает всплывающее окно подсказки, отображающее правильный синтаксис для процедуры, функции или метода, который вы только что ввели в Code Window.
Parameter Info (параметры)	Ctrl+ Shift+I	Открывает всплывающее окно подсказки, отображающее параметры (называемые также аргументами) процедуры, функции или оператора, который вы только что ввели в Code Window.
Complete Word (завершить слово)	Ctrl+ Space	Редактор VB заканчивает слово, которое вы вводите, как только вы введете достаточно символов для того, чтобы VBA распознал ключевое слово.
Bookmarks (закладки)		Открывает подменю с пунктами для помещения, удаления или перехода к закладкам, которые вы ранее поместили в ваш модуль. В отличие от закладок в Word, закладки Редактора VB не имеют имен.
Меню View (Вид)
Меню View содержит команды, позволяющие выбирать элементы Редактора VB для просмотра и способ просмотра. В табл. 2.3 приведены команды меню View, их горячие клавиши и действие, производимое каждой командой.
Таблица 2.3. Команды меню View
Команда	Горячая клавиша	Действие
Code (программа)	F7	Активизирует Code Window для отображения исходного кода VBA, ассоциированного с выбранным модулем или формой.
Object (объект)	Shift+F7	Отображает объект текущего выбора в Project Explorer.
Definition (описание)	Shift+F2	Отображает исходный код VBA для процедуры или функции, на которую указывает курсор; отображает Object Browser для объектов в справке VBA.
Last Position (вернуться к последней позиции)	Ctrl+ Shift+F2	Переходит в последнюю позицию в модуле после использования команды меню Definition или после редактирования кода.
Object Browser (просмотр объектов)	F2	Открывает Object Browser, позволяющий определять, какие макросы доступны в данный момент.
Immediate Window (окно отладки)	Ctrl+G	Отображает окно отладчика Immediate Window VBA.
Среда Редактора Visual Basic
59
Команда	Горячая клавиша	Действие
Locals Window (окно локальных переменных)		Отображает окно отладчика Locals Window.
Watch Window (окно контрольного значения)		Отображает окно отладчика Watch Window (контрольные значения).
Call Stack (стек вызова)	Ctrl+L	Отображает список последовательности вызовов для текущей функции или процедуры VBA.
Project Explorer (окно проекта)	Ctrl+R	Отображает Project Explorer.
Properties Window (окно свойств)	F4	Отображает Properties Window.
Toolbox (панель элементов)		Отображает Toolbox. Toolbox используется для добавления элементов управления в пользовательские диалоговые окна.
Tab Order (последовательность перехода)		Отображает диалоговое окно Tab Order, которое используется при создании пользовательских диалоговых окон.
Toolbars (панели инструментов)		Отображает подменю, позволяющее показывать или скрывать различные панели инструментов Редактора VB или открывать диалоговое окно для настройки одной из панелей инструментов Редактора VB.
<Host applications (host-приложение)	Alt+Fll	Возвращает вас в host-приложение, из которого был запущен Редактор VB, но оставляет Редактор VB открытым. Конкретное имя этого пункта меню зависит от того, из какого host-приложения VBA вы запустили Редактор VB.
Меню Insert (Вставка)
Команды меню Insert позволяют добавлять различные объекты, такие как модули и формы, в ваш проект. В меню Insert никакие команды не имеют «горячих клавиш». В табл. 2.4 приведены действия, выполняемые каждой командой этого меню.
Таблица 2.4. Команды меню Insert
Команда	Действие
Procedure (процедура)	Вставляет новую процедуру (Sub, Function или Property) в текущий модуль. (Процедура — это еще одно название макроса).
UseForm	Добавляет новую форму (используется для создания пользовательских диалоговых окон) в проект.
Module (модуль)	Добавляет новый модуль в проект. Редактор VB дает этому модулю имя в соответствии с правилами, описанными ранее в этой главе.
60
Глава 2
Команда	Действие
Class Module (модуль класса)	Добавляет в проект class module (модуль класса). Модули класса используются для создания пользовательских объектов в вашем проекте.
File (файл)	Позволяет вставлять текстовый файл, содержащий исходный код VBA, в модуль.
Меню Format (Формат)
Команды меню Format используются при создании пользовательских диалоговых окон и других форм. Команды меню Format позволяют выравнивать объекты в форме по отношению друг к другу, настраивать размер элемента управления в соответствии с его содержимым и выполнять многие другие полезные задачи. Команды меню Format представлены здесь для полноты изложения материала, хотя вы не будете их применять до тех пор, пока не начнете создавать собственные пользовательские диалоговые окна. В табл. 2.5 приведены команды меню Format и их действия. Заметьте, что эти команды не имеют «горячих клавиш».
Таблица 2.5. Команды меню Format
Команда	Действие
Align (выровнять)	Открывает подменю команд, которые позволяют выравнивать выбранные объекты в форме по отношению друг к другу. Здесь можно выравнивать объекты по верхней/нижней, правой/левой границам, по центру или середине создаваемого объекта.
Make Same Size (выровнять размер)	Открывает подменю команд, позволяющих изменять размер выделенных объектов до размера указанного объекта.
Size to Fit (подогнать размер)	Одновременно изменяет ширину и высоту объекта до соответствия размеру его содержимого.
Size to Grid (выровнять размер по сетке)	Одновременно изменяет ширину и высоту объекта до ближайших меток сетки. При разработке форм Редактор VB отображает в форме сетку, чтобы было легче располагать и изменять размеры объектов в форме.
Horizontal Spacing (интервал по горизонтали)	Открывает подменю команд, позволяющих устанавливать горизонтальный интервал для выбранных объектов. Здесь можно устанавливать равномерный горизонтальный интервал, уменьшать или увеличивать его или удалять всякий горизонтальный интервал между объектами.
Vertical Spacing (интервал по вертикали)	Открывает подменю команд, позволяющих устанавливать вертикальный интервал для выбранных объектов. Здесь можно устанавливать равномерный вертикальный интервал, уменьшать или увеличивать его или удалять всякий вертикальный интервал между объектами.
Center in Form (разместить по центру в форме)	Открывает подменю команд, позволяющих изменять положение выбранных объектов, чтобы они были центрированы в форме горизонтально или вертикально.
Среда Редактора Visual Basic
61
Команда	Действие
Arrange Buttons (разместить кнопки)	Открывает подменю команд, позволяющих автоматически располагать командные кнопки в форме в ряд с равным интервалом по нижнему или правому краю формы.
Group (группировать)	Связывает несколько выбранных объектов вместе в одну группу, чтобы вы могли перемещать, изменять размер, вырезать или копировать объекты, обращаясь с ними, как с одним целым.
Ungroup (разделить)	Отменяет группировку объектов, которые перед этим были связаны вместе с помощью команды Group.
Order (порядок)	Открывает подменю команд, позволяющих изменять упорядочение сверху вниз (называемое z-order) перекрывающихся объектов в форме. Цспользуйте команду Order, чтобы обеспечить, например, появление текстового окна всегда поверх графического объекта в форме.
Меню Debug (Отладка)
Команды меню Debug используются при выполнении тестирования или отладки макросов. (Debugging — так называется процесс нахождения и исправления ошибок в программе.) В табл. 2.6 приведены команды меню Debug, их «горячие клавиши» и выполняемые действия.
Таблица 2.6. Команды меню Debug
Команда	Горячая клавиша	Действие
Compile <project> (компилировать <проект>)		Компилирует проект, выбранный в данный момент в Project Explorer.
Step Into (шаг с заходом)	F8	Выполняет исходный код вашего макроса по одному оператору каждый раз.
Step Over (шаг с обходом)	Shift+F8	Подобно команде Step Into команда Step Over позволяет выполнять все инструкции в макросе без паузы на каждой отдельной инструкции.
Step Out (шаг с выходом)	Ctrl+ Shift+F8	Выполняет все остающиеся операторы в макросе без паузы на каждом отдельном операторе.
Run to Cursor (выполнить до текущей позиции)	Ctrl+F8	Выполняет операторы исходного кода макроса от оператора, выполняющегося в данный момент, до текущей позиции курсора.
Add Watch (добавить контрольное значение)		Позволяет указывать переменные или выражения, значения которых можно наблюдать во время выполнения исходного кода VBA.
Edit Watch (изменить контрольное значение)	Ctrl+W	Позволяет редактировать спецификации для наблюдаемых переменных и выражений, которые были созданы ранее с помощью команды Add Watch.
62
Глава 2
Команда	Горячая клавиша	Действие
Quick Watch (контрольное значение)	Shift+F9	Отображает текущее значение выбранного выражения.
Toggle Breakpoint (точка останова)	F9	Отмечает место (или отменяет отметку) в исходном коде VBA, где вы хотите остановить выполнение макроса.
Clear АП Breakpoints (снять все точки останова)	Ctrl+ Shift+F9	Удаляет все точки останова в модуле.
Set Next Statement (задать следующую инструкцию)	Ctrl+F9	Позволяет менять обычное выполнение кода путем указания вручную следующей строки исходного кода, которая должна выполняться.
Show Next Statement (показать следующую инструкцию)		Приводит к подсветке Редактором VB следующей строки кода, которая будет выполняться.
Команды меню Debug позволяют непосредственно контролировать выполнение макроса, останавливать и запускать макрос в заданных точках и отслеживать выполнение макроса по шагам.
Меню Run (Запуск)
Команды меню Run позволяют начать выполнение макроса, прерывать или возобновлять его выполнение или возвращать прерванный макрос в состояние до выполнения.
Таблица 2.7. Команды меню Run
Команда	Горячая клавиша	Действие
Run Sub/User Form (запуск подпро-граммы/User Form)	F5	Приводит к тому, что VBA запускает макрос, который редактируется в данный момент, то есть VBA запускает макрос, на тексте которого находится курсор вставки. Если какая-либо форма активна, VBA запускает эту форму.
Break (прервать)	Ctrl+Break	Прерывает выполнение вашего кода VBA и приводит к тому, что Редактор VB переходит в режим прерывания (Break mode). (Break mode используется при отладке кода VBA.)
Resert <project> (сброс)		Устанавливает все переменные модульного уровня и Call Stack (список последовательности вызовов) в исходное состояние.
Design Mode (конструктор)		Включает и выключает Design mode (режим проектирования или разработки) для проекта. В этом режиме никакой код в вашем проекте не выполняется, и события от элементов управления не обрабатываются.
Среда Редактора Visual Basic
63
Меню Tools (Сервис)
Команды меню Tools не только позволяют выбрать макрос для выполнения, но и получить доступ к внешним библиотекам макросов и дополнительным элементам управления форм (кроме встроенных в VBA). Команды меню Tools обеспечивают также доступ к диалоговому окну Options (параметры) Редактора VB и свойствам проекта VBA текущего выбора в Project Explorer. В табл. 2.8 приведены команды меню Tools и их действия. Команды меню Tools не имеют «горячих клавиш».
Таблица 2.8. Команды меню Tools
Команда	Действие
References (ссылки)	Отображает диалоговое окно References, позволяющее устанавливать ссылки на библиотеки объектов, библиотеки типов или другой проект VBA. После установления ссылки объекты, методы, свойства, процедуры и функции в этой ссылке появляются в диалоговом окне Object Browser.
Additional Controls (дополнительные элементы)	Отображает диалоговое окно Additional Controls, позволяющее настраивать Toolbox (панель элементов) так, чтобы вы могли добавлять элементы управления в формы помимо встроенных в VBA. Диалоговое окно Additional Controls предназначено для добавления к панели элементов кнопок, которые позволяют добавлять к форме объекты, такие как рабочий лист Excel или документ Word.
Macros (макросы)	Отображает диалоговое окно Macros, позволяющее создавать, редактировать, выполнять или удалять макросы.
Options (параметры)	Отображает диалоговое окно Options, позволяющее выбирать различные опции для Редактора VB, такие как число пробелов в интервале табуляции (tab stop), когда VBA проверяет синтаксис ваших операторов, и так далее.
<project> Properties (свойства проекта)	Отображает диалоговое окно Project Properties, позволяющее устанавливать различные свойства вашего проекта VBA, такие как имя проекта, описание и файл контекстной справки. Это диалоговое окно позволяет также защищать проект, чтобы никто не мог его редактировать без указания пароля.
Digital Signature (цифровая подпись)	Отображает диалоговое окно Digital Signature, в котором можно задать для проекта сертификат цифровой подписи.
Меню Add-Ins
В этом меню находится всего одна команда, Add-In Manager, которая приводит к отображению диалогового окна Add-In Manager. Это окно позволяет регистрировать, загружать или выгружать и определять поведение дополнений.
Другие меню
В Редакторе VB имеются два дополнительных меню: Window (окно) и Help (помощь). Оба этих меню содержат команды, идентичные меню Window и Help, имеющимся в других приложениях Microsoft Windows. Команды в меню Window позволяют выбирать активное окно, разбивать текущее окно, размещать дочерние окна вертикально и горизонтально, организовывать дочерние окна VB в виде каскада или выравнивать значки минимизированных дочерних окон.
64
Глава 2
Команды меню Help также идентичны командам меню Help в Word, Excel и других приложениях Microsoft Windows. Меню Help Редактора VB позволяет получать контекстно-зависимую подсказку посредством справочной системы Microsoft Office и просматривать файлы справочной системы VBA для host-приложения, из которого вы запустили Редактор VB. Если у вас имеется модем или доступ к Internet, вы можете использовать Help | MSDN on the Web для соединения с разнообразными страницами Web, содержащими информацию о продуктах Microsoft и VBA.
Последняя команда в меню Help — это команда About Microsoft Visual Basic. Она отображает диалоговое окно, содержащее сведения об авторских правах на Microsoft Visual Basic. Диалоговое окно About Microsoft Visual Basic содержит также командную кнопку System Info, которая отображает информацию о вашей вычислительной системе: какие драйверы видеосистемы, звуковой системы и принтера установлены, какие программы загружены в память в данное время, какие программы зарегистрированы в системном реестре (Windows System Registry) и другую техническую информацию.
Знакомство с панелями инструментов Редактора VB
Для многих пользователей выбрать командную кнопку с помощью мыши легче, чем выбрать команду в меню. Поэтому Редактор VB предоставляет важнейшие и наиболее часто используемые команды в виде кнопок на панели инструментов. Если вы часто работаете с Редактором VB, можете заметить, что использование командных кнопок на различных панелях Редактора VB ускоряет вашу работу.
По умолчанию Редактор VB отображает только панель инструментов Standard, показанную на рис. 2.4. В конце панели, справа, находится кнопка (со стрелкой) More Buttons. Если вы хотите удалить с панели или добавить некоторые кнопки на панель Standard, нажмите на эту кнопку, а затем укажите соответствующую кнопку в появляющемся меню (рис. 2.5).	. .
1	3	5	7	9	11	13	15	17	19
® 3’@	! а
2	4	6	8	10	12	14	16	18
Рис. 2.4. Панель Standard Редактора VB содержит кнопки для важнейших и наиболее часто используемых команд:
1 - View host-приложение; 2 - Insert UserForm; 3 - Save module; 4 - Cut; 5 - Copy;
6 - Paste; 7 - Find; 8 - Undo; 9 — Redo; 10 — Run Sub/UserForm; 11 - Break; 12 — Reset;
13 - Design Mode; 14 - Project Explorer; 15 - Properties Window; 16 - Object Browser;
17 - Toolbox; 18 — Microsoft Visual Basic Help; 19 - More Buttons
Кроме панели Standard Редактор VB предлагает еще три панели: Edit (правка), Debug (отладка) и UseForm.
Панель Edit Редактора VB содержит несколько командных кнопок, полезных при редактировании текста в Code Window (окне кода). Эта панель предлагает даже пару команд, которых нет на панели Standard (стандарт). Панели Standard и Edit описываются далее в этом разделе.
Вы можете управлять тем, какие панели инструментов отображает Редактор VB с помощью команды View | Toolbars (вид | панели инструментов). Поскольку Редактор VB по умолчанию не отображает панель Edit, вам нужно будет выводить ее на экран вручную.
В следующих нескольких параграфах описываются сначала команды, имеющиеся на панели Standard, а затем — дополнительные команды, находящиеся на панели Edit.
Среда Редактора Visual Basic
65
Рис. 2.5
Кнопка More Buttons панели Standard
Редактора VB позволяет добавлять и удалять любые кнопки
Microsoft Visual Basic - Normal - [NtwMacros (Cod»}}
Зе Edft tfew insert Format Debug Bid loots Add-ins window Дор й ЗГ s E п т pr______________________
- Normal
* .... Merceoft word Object
nt 
«С Modulel
NewMacroe Module
Alphabetic jcaisgoreedl |§^|NewMacros
► 11  &	4 I# Ln 1,Col20
в
Sub выделитьТекс Я ’	*. В
' гдхделит- Гекс» ~7' £ ’ млгрог '»н'кса/'^ йк
•  *. ®>
With Selecti5’' Л .Name = -/
.Bold «= ™
. Italic I— * .underlie ’* .underli *  .Strikelff.
.Doubles.^
cm
Alt+Fll
Mcrosoftword Insert Object gave Normal cuj СРРУ Baste Epd. Cant undo Cant Redo Rid Sub/JserForm Break Beset Design Mode Eroject Explorer Properties y^ndow Object Browser Toobox Оправка Mcrosoft Visual Basic Fl
Standard
C«*S CM+x Ctri*C Ctrl+v Cfrl+F ctrt+z
Ctri+R
M
F2
FS ctrt+Break
tjacTpoCka


Сброс панели
Панель инструментов Standard
Панель инструментов Standard содержит 19 кнопок. Каждая кнопка является быстрой командой меню. При изучении таблицы 2.9 обращайтесь к рис. 2.4 для сопоставления имени каждой командной кнопки со значком на передней стороне кнопки.
Таблица 2.9. Кнопки панели инструментов Standard
Кнопка	Действие
View <host application> (вид <ко81-приложе-ние>)	Переключает на host-приложение VBA, из которого вы запустили Редактор VB. Значок этой кнопки изменяется в зависимости от конкретного приложения, из которого вы запускали редактор VB.
Insert UserForm (вставить UserForm)	Щелкните на кнопке со стрелкой вниз справа от этой кнопки, чтобы отобразить список объектов, которые вы можете вставить в текущий проект: UserForm, Module, Class Module или Procedure. Это можно выполнить и при использовании одноименных команд меню Insert (вставка).
Save (сохранить)	Сохраняет текущий проект так же, как File | gave.
Cut (вырезать)	Вырезает выделенный текст или объект и помещает его в Clipboard; так же, как команда Edit | Cut.
Copy (копировать)	Копирует выделенный текст или объект в Clipboard; так же, как команда Edit | Сору (правка | копировать).
Paste (вставить)	Вставляет текст или объект из Clipboard в Code Window или форму пользователя в позицию курсора так же, как команда Edit | Paste (правка | вставить).
Find (найти)	Открывает диалоговое окно Find для нахождения определенного слова или фразы в модуле; так же, как команда Edit | Find (правка | найти).
3 Программирование на VBA 2002
66
Глава 2 •
Кнопка	Действие
Undo (отменить набор)	Отменяет самую последнюю команду, если это возможно (не все действия могут быть отменены); так же, как команда Edit | Undo (правка | отменить набор).
Redo (вернуть набор)	Возобновляет самую последнюю отмененную команду; так же, как команда Edit | Redo.
Run Macro 1 (запуск подпрограм-। мы/UserForm)	Запускает текущую процедуру или форму так же, как команда Run | Sub/UserForm.
Break (прервать)	Прерывает выполнение кода VBA; так же, как команда Run | Break (запуск | прервать).
Reset (сброс)	Перезапускает код VBA, как команда Run | Reset (запуск | сброс).
Design Mode (конструктор)	При нажатии этой кнопки Редактор VB переходит в режим Design (конструктора) так же, как командой Run | Design Mode (запуск | конструктор).
Project Explorer (окно проекта)	Отображает Окно проекта (Project Explorer) так же, как команда View | Project Explorer) (вид ] окно проекта).
Properties Window (окно свойств)	Отображает Properties Window (окно свойств) так же, как команда View | Properties Window (вид | окно свойств).
Object Browser (просмотр объектов)	Отображает диалоговое окно Object Browser (просмотр объектов) так же, как команда View | Object Browser (вид | просмотр объектов).
Toolbox (панель элементов)	Отображает Toolbox (панель элементов) так же, как команда View | Toolbox (вид | панели элементов).
Office Assistant (помощник по Office)	Отображает окно Справочной системы Microsoft Office для контекстно-зависимой подсказки по текущей задаче.
Cursor position (положение курсора)	Эта область панели инструментов Standard фактически не является командной кнопкой и появляется только тогда, когда курсор находится в Code Window. Эта область показывает, в какой строке модуля и в каком столбце строки находится курсор вставки.
More Buttons	Позволяет добавить или удалить кнопки панели.
Панель инструментов Edit (правка)
По мере того как вы узнаете о написании кода VBA и все больше работаете в окне Code Window (программа), вы можете заметить, что использование панели Edit с целью получения «горячих клавиш» для различных команд редактирования экономит ваше время и усилия. Редактор VB не отображает автоматически панель Edit, если только вы сначала не вывели эту панель на экран, выполнив два шага, указанные в начале этого раздела. В табл. 2.10 приведены командные кнопки по умолчанию на панели инструментов Edit и описывается действие каждой кнопки. При изучении табл. 2.10 обращайтесь к рис. 2.6 для сопоставления имени каждой кнопки со значком на передней стороне кнопки на панели инструментов.
Среда Редактора Visual Basic
67
Таблица 2.10. Команды панели инструментов Edit
Кнопка	Действие
List Properties/Methods (список свойств/мето-дов)	Отображает раскрывающийся список свойств и методов, принадлежащих объекту, который вы только что ввелр; так же, как Edit | List Properties/Methods (правка | список свойств/методов).
List Constants (список констант)	Отображает раскрывающийся список предопределенных констант; так же, как Edit | List Constants (правка | список констант).
Quick Info (сведения)	Отображает всплывающее окно, показывающее правильный синтаксис для объектного метода; так же, как Edit | Quick Info (правка | сведения).
Parameter Info (параметры)	Отображает всплывающее окно, показывающее параметры (называемые также аргументами [arguments]) функции или оператора VBA; так же, как Edit | Parameter Info (правка | параметры).
Complete Word (завершить слово)	Завершает текущее ключевое слово VBA, как только вы введете достаточно символов, чтобы VBA идентифицировал слово, которое вы вводите; так же, как Edit | Complete Word) (правка | завершить слово).
Indent (увеличить отступ)	Сдвигает выделенный текст вправо на одну позицию табуляции; так же, как Edit | Indent (правка | увеличить отступ).
Outdent (уменьшить отступ)	Сдвигает выбранный текст влево на одну позицию табуляции; так же, как Edit | Outdent (правка | уменьшить отступ).
Toggle Breakpoint (точка останова)	Устанавливает или отменяет точку прерывания в исходном коде VBA; так же, как Debug | Toggle Breakpoint (отладка | точка останова).
Comment Block (закомментировать блок)	Превращает выделенный блок текста в Code Window в комментарии, добавляя символ комментария в начало каждой выделенной строки. Эквивалентной команды меню не имеется.
Uncomment Block (раскомментировать блок)	Удаляет символ комментария из блока выделенного текста в Code Window. Эквивалентной команды меню нет.
Toggle Bookmark (закладка)	Устанавливает или отменяет закладку в вашем исходном коде VBA; так же, как Edit | Bookmarks | Toggle Bookmark (правка | закладки | закладка).
Next Bookmark (следующая закладка)	Перемещает курсор вставки в Code Window к следующей закладке; так же, как Edit | Bookmarks | Next Bookmark (правка | закладки | следующая закладка).
Previous Bookmark (предыдущая закладка)	Перемещает курсор вставки в Code Window к предыдущей закладке; так же, как Edit | Bookmarks | Previous Bookmark (правка | закладки | предыдущая закладка).
Clear All Bookmarks (снять все закладки)	Удаляет все закладки в модуле; так же, как Edit | Bookmarks | Clear All Bookmarks (правка | закладки | снять все закладки).
3*
fi	t.
Глава 3
Редактирование простых макросов
После того как вы немного ознакомились со средой Редактора VB или, по крайней мере, с терминологией, связанной с компонентами редактора, пора рассмотреть более детально те макросы, которые вы должны были записать при помощи макрорекордера, и те, которые были написаны без рекордера и содержали только вывод краткого сообщения.
Редактирование макросов
Начнем с редактирования ранее записанных макросов, так как по мнению многих авторов книг в этой области такой подход быстро приносит определенную пользу. Многие опытные программисты предпочитают книги по программированию с большим количеством кода (конечно, код должен быть хорошего качества). Перед тем как вы сможете редактировать макрос, необходимо отобразить модуль, содержащий этот макрос. Например, чтобы редактировать макрос ВыделитьТекст в Word, который вы могли записать при чтении первой главы, вы должны сначала отобразить модуль в Normal.dot (где было предложено сохранить записываемый макрос), содержащий исходный код макроса ВыделитьТекст. Аналогично, для редактирования макроса FormatArialBoldl2 в Excel, который вы также записали в главе 1, вы должны сначала отобразить модуль в рабочей книге Personal.xls (где был сохранен записанный макрос), содержащей исходный код макроса Format-ArialBoldl2.
Отображение модуля
Как найти модуль, содержащий необходимый макрос? Для этого в Редакторе VB для Excel 2002 выполните следующую процедуру:
1.	Нажмите Alt+Fll, чтобы активизировать Редактор VB, если он еще не открыт.
2.	Выберите команду View | Project Explorer (Вид | Окно проекта), чтобы отобразить Project Explorer.
3.	Просмотрите дерево-список в Project Explorer, чтобы найти модуль, который вам необходимо отобразить. Если опция просмотра папок в Project Explorer включена, вы найдете все модули проекта в папке Modules вашего проекта (рис. 3.1).
4.	Дважды щелкните на модуле, который вам необходим. Редактор VB отображает этот модуль в Code Window (Окно программы).
После того как вы отобразите модуль, можете использовать список Procedure (процедура) в Code Window для получения определенного макроса в этом модуле. Вы можете также использовать метод, описанный в следующем разделе, для нахождения макроса без предварительного открытия модуля, содержащего этот макрос.
Редактирование простых макросов
69
Рис. 3.1
Все модули проекта вы найдете в папке
Modules
Как найти записанный макрос
Поскольку Word всегда сохраняет записанные макросы в модуле NewMacros документа или шаблонного файла, найти исходный код макроса в Word просто. Найти исходный код макроса в Excel может быть немного сложнее. Когда вы записывали макрос FormatArialBoldl2 в Excel 2002 во время изучения первой главы, вы сохранили его в рабочей книге Personal.xls. Если это был первый макрос, какой вы когда-либо записали и сохранили в Personal.xls, Excel сохранил макрос FormatArialBoldl2 в модульном листе с именем Modulel. Если бы вы затем записали другой макрос в том же самом сеансе работы, Excel также сохранил бы его в том же самом модуле (Modulel). Если вы выходили из Excel между временем записи вами макроса FormatArialBoldl2 и временем записи другого макроса, Excel сохранил последний макрос в другом модуле (скорее всего, в Module2).
Использование инструмента Object Browser
Вместо поиска по всему тексту во всех модулях определенного макроса вы можете использовать инструмент, называемый Object Browser, чтобы найти этот макрос, вывести на экран или редактировать, независимо от того, где он находится — в Word, Excel или других приложениях.
Для использования инструмента Object Browser в Excel выполняйте следующие шаги:
1.	Нажмите Alt+Fll, чтобы открыть Редактор VB.
2.	Выберите View | Project Explorer (Вид | Окно проекта) для отображения Project Explorer (рис. 3.2).
Рис. 3.2
Выделите проект в Project Explorer перед поиском макроса в окне
Object Browser
Project - VBAProject	®
Г '• [б]
IVHAPrnjert (PERSONAEJCESj!
(+ Microsoft Excel Objects
Cj Modules
* Й VBAProject (Важные_данные.х1$)
70
Глава 3
3.	В Project Explorer выделите проект VBA, в котором вам необходимо найти макрос. Например, на рис. 3.2 показана книга Personal.xls, выделенная в Project Explorer.
4.	Выберите команду View | Object Browser (Вид | Просмотр объектов). Редактор VB отобразит диалоговое окно Object Browser, показанное на рис. 3.3.
Project Library
Search Text
Search
'<AII Ubiaile«>
, Object Browser
Classes
View Definition
Show Search Results
Members of <globals>
* Abs
Й1 ActiveCell eS1 ActiveChart eS* ActivePnnter .............’
й? ActiveWmdow tS? ActiveWorkbook eS* Addins
AppActivate Й? Application о Asc о AcrR
globais>
Ш Addin
*51 Addins
Л Adjustments AllowEditRange AllowEditRanges Answerwizard oS AnswerWizardFiles
Application
Areas
6$ Assistant
<S*A AntnOnrrprt

Property ActlvaSheet As Object read only
Member of [jod
Рис. 3.3. Используйте диалоговое окно Object Browser для более легкого поиска макросов и модулей, в которых они сохраняются
5.	Убедитесь, что в раскрывающемся списке Project/Library (Проект/Библиотека) выделен элемент <AII Libraries> (<Все библиотеки;»). Окно Object Browser отображает все имеющиеся модули и объекты в списке Classes (Классы).
6.	Введите имя макроса, который вам необходимо найти, в текстовом окне Search (поиск). Например, чтобы найти исходный код для макроса FormatArialBoldl2 в Excel, введите FormatArialBoldl2 в поле Search Text (Образец поиска).
7.	Щелкните на кнопке Search (Поиск) в окне Object Browser (см. рис. 3.3). Object Browser выполняет поиск текста, который вы ввели в окно Search Text, в вашем • проекте VBA (а также в других открытых в данный момент библиотеках).
После выполнения поиска меняется вид окна Object Browser: оно отображает список Search Results, показанный на рис. 3.4. Если Object Browser обнаружил макросы, совпадающие с текстом в окне Search Text (образец поиска), они отображаются в списке Search Results (результаты поиска). В противном случае, в этом списке отображается сообщение No items found (элементы не найдены).
8.	Щелкните на макросе в списке Search Results, затем — на кнопке View Definition (описания) в окне Object Browser (см. рис. 3.4). Редактор VB открывает Code Window (программы) для модуля, содержащего этот макрос, и отображает исходный код макроса (см. рис. 3.5).
Просмотр модулей проекта с помощью Object Browser
Если ваш проект не содержит большого количества различных модулей, то легче находить макрос, выполняя следующую альтернативную процедуру:
1.	Нажмите Alt+Fll, чтобы открыть Редактор VB.
2.	Выберите View | Project Explorer (Вид | Окно проекта), чтобы отобразить Project Explorer.
Редактирование простых макросов
71
Рис. 3.4
Окно Object Browser после выполнения поиска макроса FofmatArialBold12
ши		All Uhrailes>	j ? I	Jt! FoimatAi’ialBo’idli	ftfT Search Results		
I	iffy л	Ipiasp		
Classes Math Л Modulel ' MsoAiertButtonType « MsoAlertCancelType J1 MsoAlertDefaultType	v		Members of 'Modulel' FormatArlalBold12	
Public Sub FormatArlalBold120 Member of	k1<><kibi1 Макрос записан 1/11/2003 (Владимир Кузьменко) Форматирует ячейку Arial Bold, 12			
Рис. 3.5
Код макроса
FofmatArialBold12 в Code Window
3.	В Project Explorer выделите проект VBA, в котором вам необходимо найти макрос.
4.	Выберите команду View | Object Browser (Вид | Просмотр объектов). Редактор VB отображает диалоговое окно Object Browser.
5.	Выделите имя вашего проекта в раскрывающемся списке окна Object Browser. Если только вы не изменили имени вашего проекта, он называется VBAProject в Excel (Project — в Word). Вы узнаете о том, как переименовать проект, позже в этой книге.
6.	Выделите модуль в списке Classes (Классы). Окно Object Browser отображает теперь все макросы в выделенном модуле в списке Members of <object> (компонент <объект>). (Точный заголовок этого списка изменяется в зависимости от объекта, выделенного в списке Classes.)
7.	Выделите макрос, исходный код которого вам необходимо увидеть, в списке Members of <object>.
72
Глава 3
8.	Щелкните на кнопке View Definition (Описания) в окне Object Browser. Редактор VB открывает Code Window для модуля, содержащего этот макрос, и отображает исходный код макроса.
Когда вы выделяете отдельный проект в списке Project/Library (Проект/Библио-тека) окна Object Browser, список Classes (Классы) будет содержать только те объекты, которые являются частью вашего проекта, — обычно один или больше модулей, сам документ Word или рабочую книгу Excel и (если ваш проект является рабочей книгой Excel) один или больше рабочих листов.
После того как вы отобразите макрос в Code Window (Окно программы), используя любой из методов, описанных в предыдущем разделе, можете просмотреть или отредактировать исходный код этого макроса. На рис. 3.5 показано Code Window, отображающее исходный код макроса FormatArialBoldl2, записанного в главе 1. Здесь Project Explorer и Properties Window были закрыты, чтобы размер Code Window был настолько большим, насколько это возможно. Теперь вы можете использовать горизонтальную и вертикальную линейки прокрутки для изменения позиции макроса в окне. Можно также использовать команду Edit | Find (Правка | Найти) для поиска имени макроса в модульном листе. Использование команды Edit | Find для поиска текста в модульном листе сходно с поиском текста в рабочем листе Excel, документе Word, презентации PowerPoint и т.д. (Подробнее о команде Edit | Find можно узнать из справочной системы Редактора VB.)
Составные части записанного макроса
Если вы рассмотрите несколько записанных макросов, то заметите, что все они имеют общие элементы. Листинг 3.1 показывает исходный код для макроса FormatArialBoldl2 в Excel, который вы записали при изучении главы 1. Листинг 3.2 показывает исходный код макроса ВыделитьТекст в Word, также записанный вами во время работы с главой 1.
Исходный код макроса в реальных модулях не включает номер каждой строки;
Лргх. в этой книге во всех листингах приведены номера строк, чтобы было легче обозна-xSrL-/ чать и обсуждать отдельные строки в различных листингах-примерах.
Листинг 3.1. Макрос FormatArialBold12, записанный в Excel
1	Sub FormatArialBoldl2()
2	'
3	' FormatArialBoldl2 Macro
4	' Макрос записан 11.02.2003 (Владимир Кузьменко)
5	' Форматирует текст ячейки: Arial, Bold, 12 б ' 7 '
8	With Selection.Font
9	.Name = "Arial"
10	.Fontstyle = "Полужирный"
11	.Size = 12
12	.Strikethrough = False
13	.Superscript	= False
14	.Subscript =	False
15	.OutlineFont	= False
16	.Shadow = False
17	.Underline =	xlUnderlineStyleNone
18	.Colorindex = xlAutomatic
19	End With
20	End Sub
Редактирование простых макросов
73
Листинг 3.2. Макрос, записанный в Word
1	Sub ВыделитьТекст()
2	'
3	' ВыделитьТекст Macro
4	' Macro recorded 07.02.03 by Владимир
5	' "Schr(10)^"Устанавливает Arial, Bold, 12 для выделенного текста
6	'
7	With Selection.Font
8	.Name	=	"Arial"
9	.Size	=	12
10	.Bold	-	True
11	.Italic	= False
12	.Underline = wdUnderlineNone
13	.Underlinecolor = wdColorAutomatic
14	.StrikeThrough = False
15	.DoubleStrikeThrough = False
16	.Outline = False
17	.Emboss = False
18	.Shadow = False
19	.Hidden = False
20	.Smallcaps = False
21	.AllCaps = False
22	.Color = wdColorAutomatic
23	.Engrave = False
24	.Superscript = False
25	.Subscript	=	False
26	.Spacing =	0
27	.Scaling =	100
28	.Position = 0
29	.Kerning =	0
30	.Animation	=	wdAnimationNone
31	End With
32	End Sub
В листинге 3.1 строка 1 является началом записанного макроса. Каждый макрос VBA начинается с ключевого слова Sub, за которым следует имя макроса. Строку, содержащую ключевое слово Sub и имя макроса, называют строкой объявления (declaration) макроса. За именем макроса всегда следуют пустые круглые скобки; назначение и использование этих скобок подробно описывается в следующих главах". Сейчас же вам необходимо знать только то, что круглые скобки всегда следуют за именем.
В листинге 3.1 строки 2-7 являются комментариями. Комментарий (comment) — это строка в макросе VBA, которая, действительно, не содержит инструкции, являющиеся частью этого макроса. Следует всегда помещать комментарии в исходный код макроса с информацией о его назначении. Обратите внимание на то, что каждая строка комментария начинается с апострофа ('). Для VBA любой текст, который следует за апострофом, представляет собой комментарий, начинающийся с апострофа и заканчивающийся в конце этой строки. В языках программирования, в которых допускаются многострочные комментарии, такие комментарии называют конечными.
Записанный макрос всегда начинается со строк комментариев, формулирующих имя макроса и содержащих текст, который вы ввели в текстовое окно Description (Описание) диалогового окна Record Macro (Запись макроса) в момент записи этого макроса. Конкретное количество и содержимое строк комментариев в записанном макросе зависит от длины вводимого вами описания.
Сразу за объявлением макроса следует тело (body) макроса (которое может включать или не включать строки комментариев). В листинге 3.1 строки 8-19 составляют тело макроса FormatArialBodyl2; в листинге 3.2 строки 7-31 составля
74
Глава 3
ют тело макроса ВыделитьТекст. Каждая строка в теле макроса состоит из одного или более операторов VBA. Оператор (statement) VBA — это последовательность ключевых слов и других символов, которые вместе составляют одну полную инструкцию для VBA. Макрос VBA состоит из одного или нескольких операторов.
Операторы VBA в записанном макросе содержат инструкции, соответствующие действиям, которые вы выполняли, когда записывали этот макрос. Например, строка 9 в листинге 3.1 устанавливает шрифт Arial, -строка 10 — размер шрифта и так далее. В листинге 3.2 строка 8 устанавливает шрифт Arial, а строка 9 устанавливает размер шрифта. Каждый из этих операторов соответствует действию, выполняемому при записи макроса.
За телом макроса следует строка, содержащая ключевые слова End Sub, которые сообщают VBA о том, что достигнут конец макроса. Макрос в листинге 3.1 заканчивается в строке 20, а в листинге 3.2 — в строке 10.
Когда вы запускаете макрос, VBA начинает выполнение кода с первой строки в теле этого макроса (первая строка после объявления макроса) и выполняет инструкции в этой строке последовательно слева направо. Затем VBA переходит к следующей строке и выполняет инструкции в ней и так далее, пока он не достигнет конца макроса, обозначенного оператором End Sub. VBA игнорирует любые строки комментариев, которые могут появиться в теле макроса.
Как вы могли уже заметить, многие строки в обоих записанных макросах имеют отступ от левого края. Каждый уровень отступа помогает отделять одну часть макроса от другой. Заметьте, что все тело каждого макроса смещено вправо между ключевыми словами Sub...End Sub для наглядного выделения тела макроса. В других местах (в строках 9-18 в листинге 3.1) операторы расположены с еще большим отступом. Этот второй, больший уровень отступа помогает определить все операторы, заключенные между ключевыми словами With...End With. В следующих главах оператор With...End With будет обсуждаться подробнее.
Макрорекордер при создании макроса автоматически делает отступы в коде, чтобы пользователю было легче читать записанный макрос. Когда вы будете писать собственные макросы, следует всегда делать отступы в коде для выделения различных секций макроса. Смещать строки не обязательно; макросы в листингах 3.1 и 3.2 будут так же выполняться, если все строки будут выровнены по левому краю модуля. Размещение строк с отступом выполняется хорошими программистами лишь для более легкого чтения и сопровождения их программ.
При использовании цветного монитора, когда вы будете просматривать записанный макрос на экране (используя редактор VB), то заметите, что различные части текста макроса отображаются различными цветами. Комментарии отображаются зеленым цветом, тогда как Sub, End Sub и другие ключевые слова VBA •— синим. Остальной текст в макросе отображается черным цветом для указания на то, что он содержит данные и программные операторы, созданные пользователем. VBA выполняет цветовое кодирование текста на экране, чтобы можно было легко определить, какую часть макроса или оператор вы просматриваете.
Редактирование текста макроса
При редактировании кода макроса в модуле вы можете использовать команды и методы, известные вам как пользователю Windows, Word или Excel. Редактирование текста в модуле, отображенном в Code Window, похоже на редактирование текста в Windows Notepad или в WordPad. Вы используете ту же клавиатуру, мышь или команды меню Edit (для добавления, удаления, выделения, вырезания, копирования или вставки текста в модуле), которые применяются в Windows Notepad, WordPad.
Для сохранения изменений, которые вы вносите в модуль, используйте команду File | Save (Файл | Сохранить) Редактора VB или щелкайте на кнопке Save (Сохранить) на панели инструментов. Любые изменения, которые вы выполняете в моду
Редактирование простых макросов
75
ле, также сохраняются всякий раз, когда вы сохраняете документ или файл рабочей книги, содержащий этот модуль. (Word автоматически сохраняет любые изменения в шаблоне Normal.dot, когда вы выходите из Word; Excel выдает запрос на сохранение любых изменений, выполненных в Personal.xls, при выходе.)
В качестве примера редактирования макроса сначала запишите новый макрос в Excel следующим образом:
1.	Запустите макрорекордер, устанавливая параметры в диалоговом окне Record Macro (запись макроса) так, чтобы макрос сохранялся в книге Personal.xls.
2.	Дайте макросу имя NewBook.
3.	Запишите следующие действия: выберите из меню File | New и Blank Workbook — в появляющемся в правой части экрана окне New Workbook для создания новой рабочей книги, выберите File | Save As для сохранения этой рабочей книги (используйте имя NewWorkbook). Сразу же после сохранения файла выберите File | Close, чтобы закрыть файл.
4.	Остановите макрорекордер.
Макрос, который будет записан в результате вышеприведенных действий,, имеет вид, представленный в листинге 3.3.
Листинг 3.3. Нередактированный макрос NewBook
1	Sub NewBook()
2	’
3	' NewBook Macro
4	' Macro recorded 13.02.2003 by Владимир
5	'
6
7	'
8	Workbooks.Add
9	ActiveWorkbook.SaveAs Filename:= _
10	"С:\Мои flOKyMeHTbi\NewWorkbook.xls", _
11	FileFormat:=xlNormal, Password, WriteResPassword:="", _
12	ReadOnlyRecommended:=False, CreateBackup:“False
13	End Sub
Листинг 3.4 показывает, как может выглядеть макрос NewBook после «косметического» редактирования. Исходный код этого макроса был переформатирован так, чтобы он был более читабельным.
Листинг 3.4. Отредактированный макрос NewBook
1	Sub NewBook()
2	'
3	' NewBook Macro
4	' Macro recorded 13.02.2003 by Владимир
5	'
6
7	’
8	Workbooks.Add
9	ActiveWorkbook.SaveAs Filename:= _
10	"С:\Мои AOKyMeHTbi\NewWorkbook.xls",
11	FileFormat:=xlNormal,	_
12	Password:_
13	WriteResPassword:_
14	ReadOnlyRecommended:=False, _
15	CreateBackup:“False
16	End Sub
76
Глава 3
Символ продолжения строки VBA
Посмотрите еще раз на строки 8-13 в листинге 3.4. Обратите внимание на символ подчеркивания (_) в конце каждой из этих строк. Заметьте также, что символу подчеркивания предшествует пробел, отделяя его от другого текста в строке. Эта особая комбинация символа пробела, за которым следует символ подчеркивания в конце строки, называется символом продолжения строки (line-continuation character) и сообщает VBA о том, что следующая строка макроса должна быть присоединена к текущей строке для образования единого оператора. В листинге 3.4 строки 8-13 являются одним оператором, в данном случае — командой, которая сохраняет рабочую книгу и устанавливает несколько опций для нее. Для того чтобы макрос был более читабельным, макрорекордер разделил эту единую логическую строку на несколько физических строк, используя символ продолжения строки, но это разделение (см. листинг 3.3) не намного улучшило читабельность кода. Поэтому код пришлось еще подправить (см. листинг 3.4).
Заметьте также, что операторы, разделенные (уместнее было бы говорить «объединенные») символом продолжения строки, размещаются с еще большим отступом, чтобы их было легче обнаружить при чтении кода.
Для того чтобы добавить комментарии к макросу NewBook, выполните следующие шаги:
1.	Переместите курсор вставки в конец строки 7 (см. листинг 3.4).
2.	Нажмите Enter, чтобы вставить пустую строку.
3.	Напечатайте апостроф (') — все комментарии начинаются с апострофа.
4.	Теперь введите комментарий, в данном случае, введите предложение: «Следующая строка создает новую рабочую книгу».
5.	Повторите шаги 1 и 2 для вставки пустой строки перед строкой 10 (см. листинг 3.4).
6.	Напечатайте апостроф, чтобы пометить строку как комментарий, а затем введите это предложение: «Следующая строка сохраняет рабочую книгу».
Листинг 3.5 содержит модифицированный макрос NewBook; добавленные комментарии являются теперь строками 8 и 10. На рис. 3.6 представлен этот макрос в Code Window.
Листинг 3.5. Макрос NewBook с добавленными комментариями
1	Sub NewBook ()
2	’
3	' NewBook Macro
4	’ Macro recorded 13.02.2003 by Владимир	,.
.5 '	’
6
7
8	' Следующая строка создает новую	рабочую книгу
9	Workbooks.Add
10	' Следующая строка сохраняет рабочую книгу
11	ActiveWorkbook . SaveAs Filenames
"С : \Мои flOKyMeHTbi\NewWorkbook. xls" ,
12	FileFormat:=xlNormal,	_
13	Password:="", _
14	WriteResPassword:_
15	ReadOnlyReconunended:=False, _
16	CreateBackup:=False
17	End Sub
Редактирование простых макросов
77
Рис. 3.6
Отредактированный макрос NewBook в Code Window
-ji Microsoft Visual Basic - Ьажные^данные.хЬ - [Module! (Code)]
* Эе &lt yiew Insert Format Qebug Run Xoofc 4dd-In$ i^bdow tjelp	- в *
а я-В, см   ► и - hg за су w ~ ua mi6,coi9 pGene< al| save Важные „данные xts|	Vj plewBoak
	Sub NewBook()	ж ’ h-*wFook ' Mat Г'» г*>.Л v 0/	' Ь/ **амм») ‘' иедсцлка	яс»уь р-лЧочую	- Workbooks.Add 1 "лецующая с^сока сохраняя'-’ рабочую кни' , ActiveWorkbook.SaveAs Е11епагое:="С:\Мои flOKyMeHTbi\NewWorkbook.xls", FileFormat.=xlNormal, Password:»”", _ WriteResPassword*»"", __	J ReadOniyRecommended.=False, _ JcreateBackup: «False End Sub	▼ ! ?_<J_	1	Jt."
При добавлении комментариев в макрос NewBook заметьте, что, когда вы вставляете новую строку и начинаете вводить текст, он отображается черным цветом. Когда вы перемещаете курсор вставки в любую другую строку, — либо нажимая на Enter, используя клавиши со стрелками, либо щелкая кнопкой мыши, — новая строка комментария становится зеленой. Это происходит из-за того, что VBA проверяет каждую новую строку, которую вы вводите (или существующую строку, которую вы изменяете) всякий раз, когда курсор вставки покидает эту строку.
VBA проверяет каждую новую или измененную строку в макросе для определения того, является ли эта строка правильной с точки зрения синтаксиса. Если новая или измененная строка имеет правильный синтаксис, VBA выполняет цветовое кодирование частей строки, используя схему цветового кодирования, описанную ранее. Если в строке имеется ошибка синтаксиса, VBA отображает всю строку красным цветом и может вывести одно или несколько возможных сообщений об ошибке синтаксиса. Сообщения о синтаксических ошибках описываются более подробно далее в этой главе.
Перемещение или копирование макроса из одного модуля в другой
Для копирования одного макроса используйте Clipboard, выполняя следующие шаги:
1.	Отобразите макрос, который вам необходимо копировать.
2.	Выделите весь текст исходного кода макроса. Убедитесь, что вы выделили весь макрос, включая строки Sub, End Sub и все строки между ними.
3.	Используйте команду Edit | Сору (Правка | Копировать) для копирования текста макроса в Clipboard.
4.	Отобразите модуль, в который вам необходимо копировать этот макрос.
5.	Используйте команду Edit | Paste (Правка | Вставить) для вставки текста макроса в модуль.
Вы можете пользоваться описанным выше методом для копирования макроса в тот же модуль, в другой модуль одного и того же проекта или в модуль другого проекта. Можно также использовать этот метод для вставки текста макроса в другие приложения Windows, такие как Notepad.
78
Глава 3
Сохранение и перенос модулей как текстовых файлов
Если вам необходимо сделать резервную копию всего модуля, вы можете сохранить его как текстовый файл. Сохранение целого модуля как текстового файла полезно, если вы хотите импортировать модуль в другой проект VBA, создать архивные копии вашей работы или перенести модули VBA в Visual Basic 6 Такое сохранение модуля называется экспортированием модуля. После тогр как вы экспортируете модуль, вы можете импортировать его в любой проект VBA или Visual Basic.
Экспортирование модулей
Для экспортирования модуля как текстового файла выполните следующее:
1.	Выделите в Project Explorer модуль, который хотите экспортировать.
2.	Выберите команду File | Export File (Файл | Экспорт файла). Редактор VB отображает диалоговое окно Export File (экспорт файла), показанное на рис. 3.7. Диалоговое окно Export File работает в основном так же, как любое диалоговое окно File Save (сохранение документа) Windows.
Рис. 3.7
Используйте диалоговое окно Export File для сохранения всего модуля в виде текстового файла
3.	Убедитесь, что в списке Тип файла (Save as type) выделен пункт Basic Files (A.bas). Расширение .bas определяет этот файл как файл исходного кода VBA или Visual Basic. Информация, сохраняемая в этом файле, — это читаемый текст.
4.	Введите имя экспортируемого файла в текстовое окно Имя файла (File Name). Редактор VB вводит имя модуля по умолчанию.
5.	Щелкните на кнопке Сохранить (Save), чтобы экспортировать файл. Редактор VB экспортирует выделенный модуль и закрывает диалоговое окно Export File. Когда вы экспортируете модуль, Редактор VB создает файл читаемого текста, содержащий все макросы в этом модуле. Если необходимо, вы можете просматривать или редактировать файлы .bas, созданные Редактором VBA, с помощью Windows Notepad или Visual Basic. На рис. 3.8 и 3.9 показан экспортированный в файл .bas модуль, содержащий макрос Newbook листинга 3.5, отображенный в Windows Notepad и Visual Basic 6, соответственно. Обратите внимание на то, что текст в файле .bas, отображенный приложением Notepad (на рис. 3.8), содержит строки, начинающиеся со слова Attribute и отсутствующие в модуле в Code Window на рис. 3.6. Редактор VB добавляет эти дополнительные строки к экспортированному файлу .bas, поскольку они содержат информацию, которая потребуется VBA или Visual Basic, если вы в дальнейшем будете импортировать файл .bas в другой проект.
Редактирование простых макросов
79
Рис. 3.8
Экспортированный модульный файл, отображенный Записной книжкой (Windows Notepad)
Modulel,bas - Notepad
tie Format Mew йФ
Attribute VB_Name = "Modulel"
Sub NewBookО
' NewBook Macro
' Macro recorded 13 02.2003 by Владимир
'Следующая строка создает новую рабочую книгу workbooks.Add 'Следующая строка сохраняет рабочую книгу Activeworkbook.SaveAs Filename:="C.\Mon документы\ме*№огкЬоок xls", _
FileFomat =xlNormal, _
Password_
WriteResPassword.="", _
ReadOnlyRecommended:=False, _
CreateBackup:=False
End Sub
, Microwfl Visual |des<n] - |Modu(e1 (Code)]
x
Й?’ Q’ й	M	►	& ES* Й W & Ln 1, Col 1
File Edit View Project Format 2ebug Run Query Diagram look ftdd-Ins Window Help
Xj
General j
llGenetal)
Sub NewBook ()
' Na* St uk taunt
‘	reru’-let
□
(proje(:tYj
I - M Modules
I <42 Modulel (Module! ba '
i UtewBook
Ca
P
6 □
<6>
ifln
Workbooks.Add
* ‘ ж " $ mu ы crppku сохрани *ч	гни >
ActiveWorkbook.SaveAs FileNaroe:_"C:\HoM докумем'гы\Ме®ЫогкЬоок.х1в"1
FileFormat:"xlNormal, _
Password:"’”’, _
WriteResPassword:"'”’,
ReadOn 1 yRecorttnended: "False, __
CreateBackup:«False
End Sub
^Module! Module
Alphabetic j Categorized j
(Name)
Returns the name used In code to
Рис. 3.9. Экспортированный модульный файл, отображенный при помощи Visual Basic 6
Импортирование модулей
Вы можете добавлять любой модуль, экспортированный вами как файл .bas, в любой из проектов VBA. Модуль добавляется в проект импортированием текстового файла .bas. Для того чтобы импортировать файл .bas, выполните следующее: 1. Выделите проект в Project Explorer, в который необходимо импортировать файл .bas.
2.	Выберите команду File | Import File (Файл | Импорт файла). Редактор VB отображает диалоговое окно Import File (Импорт Файла), отображенное на рис. 3.10. Диалоговое окно Import File работает в основном так же, как любое диалоговое окно открытия файла Windows.
3.	Используйте элемент Папка (Look In) для перемещения на диск и в папку, где содержится файл, который вам необходимо импортировать в ваш проект. Это должен быть файл, который вы создали, используя Редактор VB для экспортирования модуля.
4.	Убедитесь, что в списке Тип файлов (Files Of Туре) выделен пункт VB Files (*.frm, *.bas, *.cls).
80
Глава 3
Рис. 3.10
Используйте диалоговое окно Import File для добавления к любому проекту модуля, экспортированного ранее в виде текстового файла
5.	Щелкните мышью дважды на имени файла, который вам необходимо импортировать. Редактор VB читает файл и добавляет модуль в ваш проект. Если проект уже содержит модуль с тем же именем, что и модуль, импортируемый вами, Редактор VB добавляет число в конец имени модуля (1, 2, 3 и так далее) для создания уникального имени модуля.
Удаление модулей из проекта
Возможно, вы решите, что вам больше не нужны макросы, содержащиеся в определенном модуле. Вам может понадобиться удалить модуль из проекта, потому что макросы, которые он содержит, были заменены новыми версиями или потому, что этот модуль содержит экспериментальные макросы, ненужные вам более. Модуль можно удалить из проекта VBA, выполнив следующее:
1.	Выделите модуль, который хотите удалить из проекта, в Project Explorer Редактора VB.
2.	Выберите команду File | Remove <object> (Файл | Удалить <объект>). Редактор VB отображает окно сообщения, запрашивающее у вас, хотите ли вы экспортировать модуль перед тем, как удалить его (рис. 3.11).
Рис. 3.11
Редактор VB не сразу удалит указанный вами модуль
Microsoft Visual Basic
Do you want to export Module? before removing It?
Cancel
3.	Щелкните на кнопке Yes (Да), если хотите экспортировать модуль перед его удалением. (Настоятельно рекомендуется экспортировать модуль как файл .bas, если только вы не уверены абсолютно, что вам никогда не понадобятся макросы, содержащиеся в этом модуле). Иначе можно щелкнуть на кнопке No (Нет) для удаления модуля без его экспортирования.
4.	Если вы выберите экспортирование модуля перед его удалением, Редактор VB отображает диалоговое окно Export File, описанное ранее в этом разделе. Заполните диалоговое окно Export File, как было описано ранее, и щелкните на кнопке Сохранить.
В любом случае Редактор VB удаляет модуль из проекта.
Редактирование простых макросов
81
Написание новых макросов и процедур	’
Чтобы записать макрос без использования макрорекордера, вы можете ввести этот макрос в существующий модуль или создать новый модуль, который будет содержать этот макрос.
До сих пор в этой книге использовался термин макрос {macro) как для макросов, которые вы записываете рекордером, так и для макросов, которые пишите сами. Существует другой термин, помогающий различать эти макросы. Строго говоря, термин макрос применим только для инструкций, которые вы записываете с помощью макрорекордера (или создаете при помощи, например, Access Macro Builder). Иногда в литературе макросами называют программы, которые не имеют аргументов (вы, наверное, уже поняли, что записываемые рекордером макросы не могут иметь аргументов). Макросы, которые вы пишете заново более точно называются подпроцедурами (subprocedures) или просто процедурами (procedures). Далее в этой книге термин макрос относится к коду, записываемому с помощью макрорекордера, а термин процедура — к коду VBA, который вы пишете сами.
Вставка и переименование модуля
Если документ (шаблон, рабочая книга, презентация, рисунок) в котором вы хотите сохранить процедуру, еще не содержит модуль, вы должны вставить модуль перед тем, как сможете написать процедуру VBA в этом проекте. Вы можете также вставить новый модуль, если существующие модули заполнены (модуль может содержать не более 4000 строк) или если вы просто хотите создать новую процедуру VBA в ее собственном модуле.
Если вы решили написать процедуру VBA в новом модуле, выполните следующие шаги для добавления модуля в проект:
1.	Убедитесь, что в host-приложении VBA (Word, Excel, Outlook, PowerPoint, Visio или FrontPage) открыт тот документ, шаблон или рабочая книга, в котором вы хотите сохранить процедуру.
2.	Нажмите Alt+Fll для активизации Редактора VB.
3.	В Project Explorer выделите проект, в который хотите добавить модуль (скорее всего, в этот момент он там будет один).
4.	Выберите команду Insert | Module (Вставка | Модуль) или на панели Standard с помощью кнопки Insert <object> (вторая кнопка слева) выберите в раскрывающемся меню Module. Редактор VB добавляет новый модуль в проект и открывает Code Window для нового модуля.
Когда Редактор VB вставляет новый модуль, он дает ему имя в соответствии с правилами, изложенными ранее в этой главе; ваш новый модуль будет иметь имя по умолчанию Module (Модуль) с последующим номером. Всякий раз при вставке модуля следует переименовывать его, чтобы этот модуль имел описательное имя. Для переименования модуля выполните следующие шаги:
1.	Выделите в Редакторе VB модуль, который будете переименовывать.
2.	Если Properties Window (Окно свойств) еще не выведено на экран, выберите команду View | Properties Window (Вид | Окно свойств) (или щелкните на кнопке Properties на панели инструментов), чтобы отобразить его. На рис. 3.12 показано Properties Window для модуля; модули имеют только одно свойство — имя.
3.	В текстовое поле Name (Имя) в Properties Window введите новое имя для модуля. Как только вы уберете курсор вставки из текстового поля Name, Редактор VB переименует модуль.
82
Глава 3
Рис. 3.12
Изменяйте имя модуля, изменяя его свойство Name

Properties Module 1
Module 1 Module	3J
Alphabetic | categorized |
Выделение существующего модуля
Для написания новой процедуры в существующем модуле необходимо сначала открыть Code Window (Окно программы) для модуля, в котором вы хотите написать процедуру. Чтобы открыть Code Window для модуля, либо щелкните дважды на этом модуле в Project Explorer, либо выделите этот модуль в Project Explorer и затем выберите команду View | Code (Вид | Программа).
Написание текста процедуры
Чтобы написать исходный код для процедуры, независимо от того, добавляете ли вы процедуру в новый или в уже существующий модуль, поместите курсор вставки в Code Window в то место в модуле, куда вы хотите ввести новую процедуру-
Вы можете ввести исходный код новой процедуры VBA в любом месте в модуле, следя за тем, чтобы новая процедура начиналась после оператора End Sub, который заканчивает предыдущую процедуру, и перед оператором Sub, который начинает следующую процедуру в модуле. Для многих пользователей самым простым является добавление новых процедур в конец модуля.
Когда вы пишете новую процедуру, вы должны указать имя процедуры и включить ключевое слово Sub в начале процедуры и ключевые слова End Sub — в конце. Если вы опустите любой из этих трех элементов, синтаксис процедуры не будет верным и VBA отобразит сообщение об ошибке, когда вы попытаетесь запустить эту процедуру.
Первой классической программой в любом описании языка программирования является программа, отображающая на экране сообщение «Hello, World!»1. Листинг 3.6 показывает такую программу VBA, состоящую из единственной процедуры.
Листинг 3.6. Процедура HelioWorld
1	Sub HelioWorld()
2	MsgBox "Hello, World!"
3	End Sub
Для самостоятельного ввода этой программы VBA выполните следующие шаги:
1.	Откройте любой документ Word или рабочую книгу Excel или создайте новый документ или рабочую книгу.
2.	Нажмите Alt+Fll для активизации Редактора VB.
3.	В Project Explorer выделите документ или рабочую книгу, в которой хотите сохранить эту программу.
В первой главе эта традиция была нарушена, но там макрос создавался только в «рекламных» целях и деталям его создания внимания не уделялось.
Редактирование простых макросов
83
4.	Выберите Insert | Module (Вставка | Модуль), чтобы добавить новый модуль к вашему проекту. Редактор VB добавляет новый модуль и открывает для него Code Window.
5.	Переименуйте новый модуль, дав ему имя FirstProgram.
6.	Убедитесь, что курсор вставки находится в начале пустой строки в Code Window, и введите текст, показанный в листинге 3.6, нажимая на Enter в конце каждой строки для начала новой строки.
Вводите исходный код из листинга 3.6 в модуль точно так, как он выглядит в листинге, но без номеров строк.
Редактор VB содержит несколько возможностей, помогающих в написании процедур. Во-первых, как только вы нажмете на Enter после ввода ключевого слова Sub и имени процедуры, Редактор VB автоматически добавляет ключевые слова End Sub. Таким образом, вам не приходится беспокоиться о том, что вы можете случайно забыть об этом важном элементе процедуры.
Во-вторых, Редактор VB включает возможность, известную как Auto Quick Info (краткие сведения). Как только вы вводите MsgBox и нажимаете на клавишу пробела (строка 2 листинга 3.6), появляется всплывающее окно, показывая полный список аргументов для встроенной процедуры VBA или функции, которую вы только что ввели (MsgBox — в данном случае). На рис. 3.13 показано всплывающее окно с информацией об аргументах встроенной VBA-процедуры MsgBox. Аргумент, значение которого, как ожидается, вы теперь должны ввести, выделен полужирным шрифтом во всплывающем окне Auto Quick Info. [Аргумент (argument) — это информация, которая необходима процедуре для выполнения ее задачи; подробнее об аргументах вы узнаете далее]. Всплывающее окно Auto Quick Info закрывается, если вы нажимаете на Enter для начала новой строки в Code Window или используете клавиши со стрелками или мышь для перемещения курсора вставки с текущей строки на другую. Вы можете также закрыть окно Auto Quick Info, нажимая на клавишу Esc.
Рис. 3.13
Всплывающее окно
Auto Quick Info для
MsgBox
•S Microsoft Visual Basic - ChapterOS - (Modulel (Code)]
nx
EHe Edit yew insert Format Debug bun Tools Add-Ins ^hdow help .ex й jit ’ hi £5*	> 11 •	’
pGenetaif"	'""’“'Vj [HeHWoid —	—....
Sub HellWord ()
MsgBox |
End MsgBox(Prompr, [Sutfons As VbMsgBoxStyle = vbOKOnly] [Trffe], [HelpFile], [Context]) As ' VbMsgBoxResult
Если вас интересует возможность Auto Quick Info, вы можете включать и выключать ее с помощью команды Tools | Options (Сервис | Параметры) в Редакторе VB. Более подробно о диалоговом окне Options (Параметры) можно узнать из справочной системы Редактора VB.
Каждое объявление процедуры должно начинаться с ключевого слова Sub, за которым следует пробел и затем — имя процедуры. В листинге 3.6 именем процедуры является HelloWorld. Финальная часть объявления процедуры — это пара пустых круглых скобок. Эти скобки обязательны. (Вы узнаете о их назначении в следующих главах). Если вы не включаете эти скобки, VBA добавляет их в объявление процедуры, когда курсор вставки убирается вами из строки объявления.
84
Глава 3
Вторая строка в листинге 3.6 образует тело процедуры и является единственным оператором, выполняющим «полезную» работу. Тело процедуры может состоять из одного или многих операторов или не состоять ни из одного оператора. Оператор MsgBox отображает сообщение в диалоговом окне на экране и описывается более подробно далее в этой главе.
Третья и последняя строка процедуры HelloWorld — End Sub — завершает процедуру. Эта строка сообщает VBA о том, что это — конец процедуры; VBA прекращает выполнение процедуры при достижении им этой строки. Подобно объявлению процедуры, оператор End Sub должен быть первыми двумя словами в строке и должен быть один в строке, хотя вы можете добавлять конечный комментарий после него. Как было упомянуто ранее, Редактор VB автоматически добавляет эту строку, после того, как вы введете объявление процедуры.
После того как вы введете исходный код для процедуры HelloWorld, выполните ее, используя метод, о котором вы узнали в главе 1:
1.	Выберите команду Tools | Macros (Сервис | Макрос) для отображения диалогового окна Macros (макрос).
2.	Выберите процедуру HelloWorld в списке Macro Name (Имя макроса).
3.	Щелкните на кнопке Run (Запуск).
Когда VBA выполняет процедуру HelloWorld из листинга 3.6, он отображает диалоговое окно, показанное на рис. 3.14. Точный заголовок этого диалогового окна зависит от того, в каком host-приложении (Word, Excel и т.д.) вы создали процедуру. Щелкните на кнопке ОК для установки диалогового окна в исходное состояние и завершения процедуры.
Рис. 3.14
Это окно отображает процедура HelloWorld, приведенная в листинге 3 6
Hello, World1
Microsoft Word
OK
Заметьте, что даже в этой короткой процедуре тело процедуры расположено с отступом для отделения его от объявления и конца процедуры. Следует всегда размещать код с отступом, чтобы его было легче читать. Сравните листинг 3.6 со следующими далее строками кода; вы видите, что даже короткие процедуры легче читать, если строки в них расположены с отступом. 1 2 3
1: Sub HelloMacroQ
2: MsgBox "Hello, World1"
3: End Sub
Свойство Auto-Indent (автоотступ)
Текстовый редактор VBA содержит свойство, называемое автоматический отступ {auto indenting), позволяющее форматировать исходный код с различными уровнями отступа. Если свойство автоматического отступа включено, то всякий раз, когда вы нажимаете на Enter, чтобы начать новую строку, курсор вставки на новой строке автоматически перемещается в положение, совпадающее с уровнем отступа строки, расположенной выше. (Нажмите на Backspace, чтобы вернуться к предыдущему уровню отступа).
Для включения и выключения автоматического отступа устанавливайте или отключайте флажок Auto Indent (автоотступ) на вкладке Editor (редактор) диалогового окна Options (параметры). Свойство автоматического отступа является включенным по умолчанию.
Редактирование простых макросов
85
Запуск процедуры во время редактирования
Независимо от того, пишете ли вы новую процедуру или редактируете записанный макрос, вам потребуется запускать эту процедуру для проверки результатов ваших усилий. Вы уже знаете, как использовать диалоговое окно Macros для запуска макроса или процедуры; вы можете их также запускать непосредственно из модуля во время редактирования (как это было показано в первой главе).
Отображение сообщений для пользователя процедуры
Листинг 3.6 включает VBA-оператор MsgBox, который можно использовать для отображения процедурами сообщения на экране. Сообщения или другая информация, которую процедура отображает на экране, пересылает на принтер или записывает в дисковом файле, называется выходом (output). Оператор MsgBox является простейшей формой экранного выхода, которую вы можете включать в процедуры VBA.
Оператор MsgBox подобен встроенной в VBA процедуре. Строка в процедуре HelloWorld, содержащая оператор MsgBox, сообщает VBA, что необходимо вызвать эту встроенную процедуру. Оператор MsgBox из листинга 3.6 приводится ниже еще раз:
MsgBox "Hello, World!"
Текст, заключенный в кавычки, в этой строке после имени процедуры MsgBox — это текст сообщения, которое должно отображаться с помощью MsgBox. VBA передает эту дополнительную информацию процедуре MsgBox. Дополнительная информация, передаваемая процедуре, которую вызывает исходный код, называется аргументом (argument) для этой процедуры. Текст "Hello, World!" является аргументом для процедуры MsgBox. Двойные кавычки (") в аргументе "Hello, World!" указывают на то, что текст, заключенный в них, является данными для процедуры, а не инструкциями, которые должен выполнить VBA.
Обратимся еще раз к рис. 3.14 и заметим, что строка заголовка в диалоговом окне, отображаемом оператором MsgBox, содержит слова «Microsoft Word». По умолчанию диалоговое окно, отображаемое оператором MsgBox, имеет заголовок, указывающий на host-приложение, выполняющее процедуру VBA (в данном случае — Microsoft Word).
Вы можете изменить заголовок диалогового окна, которое отображает MsgBox. Листинг 3.7 показывает процедуру HelloWorld из листинга 3.6 с оператором MsgBox, измененным таким образом, что он отображает диалоговое окно, показанное на рис. 3.15. Сравните рис. 3.14 и 3.15 и обратите внимание, что теперь заголовком диалогового окна MsgBox является текст «Окно приветствия».
Листинг 3.7. Отображение настраиваемой строки заголовка с помощью MsgBox
1	Sub HelloMacroO
2	MsgBox "Hello, World!", , "Окно приветствия"
3	End Sub
Рис. 3.15
Заметьте, что заголовок диалогового окна отлтчается от показанного на рис. 3.14
Окно приветствия
НеИо, World1
ОК
86
Глава 3
Оператор MsgBox (строка 2 листинга 3.7) теперь отличается от используемого в предыдущем листинге, хотя все еще выполняет ту же самую задачу в процедуре — отображать сообщение для пользователя. В листинге 3.7 оператор MsgBox имеет три аргумента (которые следуют после него); каждый аргумент отделяется от других запятой.
Первый аргумент оператора MsgBox такой же, как в листинге 3.6, и является текстом, который должен быть отображен посредством MsgBox (показанный во всплывающем окне Quick Info как аргумент Prompt). Поскольку этот вариант оператора MsgBox имеет более одного аргумента, за первым аргументом следует запятая; списки аргументов {argument lists) в процедурах VBA отделяются запятыми, точно так, как элементы в каком-либо списке.
Как только вы ввели запятую, отделяющую первый аргумент от второго, вы, вероятно, заметили, что всплывающее окно Quick Info изменяется: аргумент Buttons в окне Quick Info выделяется полужирным шрифтом, тогда как аргумент Prompt отображается опять обычным шрифтом. В то же время, в модуле появляется раскрывающийся список; этот список содержит все возможные значения для аргумента Buttons. Появляющийся список является результатом свойства Auto Data Tips (подсказка значений данных) Редактора VB. Это свойство работает подобно свойству Auto Quick Info, но отображает списки допустимых значений для аргументов процедуры и других элементов в коде VBA.
Второй аргумент оператора MsgBox является необязательным; в данном примере необязательный второй аргумент опущен. Поскольку необязательный аргумент опускается, в списке аргументов имеется один символ пробела. Этот пробел указывает VBA на то, что в этом списке пропущен необязательный аргумент. За символом пробела следует запятая, чтобы отделить его от следующего аргумента в списке. Если вы не введете символ пробела между двумя запятыми, VBA добавляет его.
Необязательный второй аргумент в операторе MsgBox — это аргумент Buttons. Он появляется во всплывающем окне Auto Quick Info, заключенный в квадратные скобки для указания того, что это — необязательный аргумент. Аргумент Buttons определяет, сколько и какого типа командные кнопки появляются в диалоговом окне, отображаемом посредством MsgBox. Когда вы опускаете необязательный второй аргумент (как в этом примере), диалоговое окно, которое отображает MsgBox, содержит только одну кнопку — кнопку ОК. (Подробнее о необязательном аргументе Buttons описывается в следующих главах).
Третий и последний аргумент в операторе MsgBox определяет заголовок диалогового окна (см. рис. 3.15). Как только вы вводите запятую, отделяющую второй и третий аргументы в списке аргументов оператора MsgBox, всплывающее окно Auto Quick Info указывает, что вы теперь должны ввести значение аргумента для аргумента Title.
Подобно первому аргументу текст для строки заголовка диалогового окна заключается в кавычки (""). VBA всегда воспринимает заключенный в кавычки текст как данные, а не как текст, содержащий программные инструкции. Если вы опустите кавычки для текста сообщения MsgBox или для текста строки заголовка диалогового окна, VBA отобразит сообщение об ошибке. Поскольку третий аргумент является также и последним, никакой запятой после третьего аргумента не требуется.
Сообщения об ошибках во время написания, редактирования или выполнения процедуры
При написании или редактировании процедуры, вы можете сделать ошибки в операторах. VBA определяет многие из этих ошибок во время написания и редактирования вами исходного кода и может обнаружить некоторые ошибки при выполнении процедуры.
Редактирование простых макросов
87
Ошибки синтаксиса
Синтаксисом (syntax) — называется определенный порядок слов и символов, который образует правильный оператор VBA. Некоторые из наиболее общих ошибок, с которыми вы сталкиваетесь во время написания или редактирования процедур VBA, — это ошибки синтаксиса (syntax errors), например, пропущенные запятые, кавычки, аргументы и так далее.
Всякий раз, когда вы пишете новую строку кода или изменяете существующую, VBA анализирует (parses) строку, как только курсор вставки перемещается из новой или измененной строки. [Синтаксический анализ (parsing) — так называется процесс разбивки оператора VBA на составляющие части и определение того, какие части строки являются ключевыми словами, переменными или данными; этот процесс подобен анализу предложения в каком-либо языке для определения его составляющих частей — существительных, глаголов, прилагательных и так далее]. После выполнения анализа строки кода VBA компилирует эту строку кода. Компиляция (compiling) в VBA означает составление исходного кода в форме, которую VBA может непосредственно выполнять без необходимости снова анализировать код.
После того как VBA успешно завершит анализ и компиляцию строки кода в процедуре и не будет обнаружено никаких ошибок, выполнится цветовое кодирование различных частей строки. (Помните, ключевые слова в Редакторе VB отображаются синим цветом, комментарии — зеленым, а данные или другие операторы отображаются в виде черного текста.) Если, однако, VBA обнаруживает ошибку синтаксиса в строке в процессе анализа или компиляции, VBA отображает всю строку красным цветом и выводит на экран диалоговое окно с сообщением об ошибке.
Рассмотрим следующий фрагмент кода, представляющий неправильно написанный оператор MsgBox:
MsgBox "Hello, World1", , Окно приветствия
В этом примере кавычки, необходимые вокруг текста, определяющего заголовок диалогового окна, были случайно пропущены. В результате VBA не может определить, что два слова в последнем аргументе являются данными; вместо этого VBA воспринимает слово Окно как имя переменной. [Переменной (variable) называют место в памяти, используемое для сохранения данных. Переменные описываются в следующей главе.]
Поскольку третий аргумент воспринимается как переменная с именем приветствия, VBA «ожидает» запятую или конец списка аргументов для процедуры MsgBox. Вместо этого, VBA находит символ пробела, за которым следует, как это кажется, имя другой переменной. VBA отображает всю строку красным цветом, чтобы указать, что она содержит ошибку, выделяет слово или символ в том месте строки, где, по определению VBA, находится ошибка, и затем отображает диалоговое окно, показанное на рис. 3.16.
Если вы получаете подобное сообщение об ошибке синтаксиса или компилирования, щелкните на кнопке Help для доступа к справочной системе VBA и получения более подробной информации о конкретной встретившейся ошибке синтаксиса1. Чтобы удалить диалоговое окно, щелкните на кнопке ОК.
После удаления с экрана диалогового окна с сообщением об ошибке попробуйте устранить ошибку. Вы можете переместить курсор вставки со строки после удаления диалогового окна, но строка остается отображенной красным цветом для указания на то, что в ней содержится ошибка. VBA не анализирует и не компилирует строку, содержащую ошибку синтаксиса снова, пока вы не запустите проце-
1 К сожалению, в окне справочной системы появляется не описание конкретной синтаксической ошибки, а описание самого понятия синтаксической ошибки под заголовком Syntax error.
88
Глава 3
дуру или не отредактируете эту строку. VBA анализирует строки в процедуре только тогда, когда вы убираете курсор вставки со строки непосредственно после внесения изменений или когда запускаете процедуру. Если при выполнении процедуры встречается строка с синтаксической ошибкой, выполнение кода прекращается, отображается модуль, содержащий процедуру, в которой имеется ошибка синтаксиса, выделяется конкретная строка в модуле, где обнаружена ошибка и отображается диалоговое окно с сообщением об ошибке.
Рис. 3.16
VBA отображает сообщения об ошибках ситаксиса, анализируя каждую строку, которую вы вводите или изменяете
Ble Edit kiew insert Fyi mat bebug Bun Tools Add Ins Window yelp	« в1 >
й Д • U X I» »	> II  К gy и
[iGeneial)	ж] jHellWoKl
Sub
HellWord ()
End
MggEox	SorMi”, , Огне'
Sub
Microsoft Visual Basic
К
error
Syntax error
Help
Диалоговое окно, которое VBA отображает для ошибки синтаксиса, обнаруженной при выполнении процедуры, обычно содержит гораздо меньше деталей о конкретной ошибке, чем диалоговое окно, которое VBA отображает, когда обнаруживает ошибку синтаксиса после того, как вы напишете или измените строку. По этой причине (и для того, чтобы избежать проблем, вызванных неожиданным прерыванием выполнения процедуры) следует всегда стараться исправлять ошибки синтаксиса, когда VBA их обнаруживает впервые. VBA обнаруживает многие ошибки синтаксиса, информируя о пропущенных запятых, кавычках и так далее. Однако не всякое сообщение об ошибке такое понятное, как хотелось бы. В некого-, рых случаях VBA не может определить, что именно неверно в синтаксисе конкретного оператора, а только сообщает об имеющейся ошибке.
Ошибки времени исполнения
Вы можете создать синтаксически правильный оператор VBA, который все же не выполняется правильно. Ошибки, которые выявляются только при фактическом выполнении процедуры, называются ошибками времени исполнения (runtime errors) или runtime ошибками. Существуют различные типы таких ошибок. Они обычно вызваны пропуском аргументов процедуры, аргументами неверного типа данных, пропуском ключевых слов, попытками доступа к несуществующим драйверам диска и папкам каталога или ошибками в логике.
Рассмотрим следующий оператор VBA, который снова содержит неправильный оператор MsgBox:
MsgBox "Hello, World1", "Окно приветствия"
В этом примере VBA не находит ничего неверного в синтаксисе оператора MsgBox: текст данных правильно заключен в кавычки и список аргументов правильно разделен запятыми. (Поскольку все аргументы, кроме первого для MsgBox являются необязательными, VBA принимает два аргумента для MsgBox в качестве пра
Редактирование простых макросов
89
вильного синтаксиса.) Однако когда VBA пытается выполнить оператор в этой строке, он отображает диалоговое окно с сообщением об ошибке, показанное на рис. 3.17.
Это диалоговое окно информирует о том, что возникла ошибка при выполнении процедуры, и отображает сообщение, описывающее эту ошибку. В данном случае ошибкой является ошибка несоответствия типа (type mismatch). Если вы еще раз посмотрите на вышеприведенный оператор MsgBox, то можете заметить, что отсутствует запятая, отмечающая место для необязательного MsgBox-аргумента Buttons.
Рис. 3.17
VBA обнаруживает некоторые ошибки только во время выполнения процедуры и отображает диалоговое окно с сообщением об ошибке времени исполнения
File Edit View Insert Format Qeoug Kun Tools Addins vvndow Help
-вх
йд-н в* » - > ii «иjMi-уч'	g__________
((General)	"	V] (HellWoiil
Sub HellWordO MsgBox ’Hello, florid!'', "окно приветствия”
Microsoft Visual Basic
Run time error 13'
Type mismatch
Когда VBA анализирует этот оператор, заключенный в кавычки текст «Окно приветствия» компилируется как второй аргумент MsgBox, а не как третий аргумент из-за пропущенной запятой. Поскольку аргумент командной кнопки должен быть числом, а не текстом, VBA сообщает о том, что тип данных, передаваемый процедуре MsgBox, не совпадает с типом данных, ожидаемых для этого аргумента. (Более подробно о типах данных рассказывается в следующей главе.)
Диалоговое окно для сообщений об ошибках времени исполнения содержит несколько командных кнопок. Далее описывается каждая из этих кнопок:
	Continue (продолжить) — Выбирайте эту командную кнопку для продолжения процедуры. Некоторые ошибки времени исполнения позволяют продолжать выполнение процедуры; однако для большинства таких ошибок эта кнопка отключена.
	End (завершить) — Выбирайте эту кнопку, чтобы закончить процедуру.
	Debug (отладка) — Выбирайте эту кнопку для перехода в режим прерывания и используйте возможности отладки Редактора VB для отслеживания и решения любой проблемы, вызванной ошибкой времени исполнения.
	Help (справка) — Эта команда предоставляет доступ к справочной системе VBA и отображает текст подсказки, описывающий конкретную ошибку времени исполнения, которая возникла. Используйте эту кнопку, чтобы получить больше информации, если вам не понятно, что означает данная ошибка времени исполнения.
Если вы не понимаете, почему использование определенного ключевого слова VBA или процедуры приводит к ошибке времени исполнения, вы можете получить справку по этому конкретному ключевому слову или процедуре, поместив курсор на этом слове и нажав на клавишу F1. VBA отображает раздел справочной системы для этого ключевого слова или процедуры, если таковой имеется.
90
Глава 3
Печать исходного кода
В некоторый момент времени вам может понадобиться распечатать какой-либо исходный код VBA. Может появиться необходимость печати в целях архивирования или документирования, демонстрации или изучения.
При печати исходного кода VBA можно печатать все модули в проекте или только модуль текущего выбора. Нельзя выделять для печати отдельные процедуры.
Чтобы напечатать исходный код, выполняйте следующие шаги:
1.	В Project Explorer выделите модуль или проект, который вам необходимо печатать. Если вы хотите печатать только выделенный текст в модуле, выведите модуль на экран и выделите текст, который необходимо печатать.
2.	Выберите команду File | Print (Файл | Печать). Редактор VB отображает диалоговое окно Print (см. рис. 3.18).
Рис. 3.18
Вы можете задать различные параметры печати в диалоговом
окне Print
Print - Project	Я
Prrter HP LaserJet 5L	I °* I
Range C	Print What		; Cancel ’
Current Module Г Current Projec	|> Qode Setup. j
Print Quality jHigh	Т-Д Print to File	Help 1
3.	В группе элементов управления Range (Диапазон печати) укажите, будет ли печататься текст текущего выбора, выделенный модуль или весь проект.
4.	В группе элементов управления Print What (Печатать) должен быть установлен флажок Code (Программу) (чтобы печатать исходный код); если ваш проект содержит формы, установите флажок Form Image (рисунок формы) для печати рисунка формы.
5.	Установите любые другие параметры печати, какие необходимо, так же, как вы это делаете в любом приложении Microsoft Office.
6.	Щелкните на кнопке ОК, чтобы напечатать исходный код.
Когда вы печатаете проект или модуль, вы не можете предварительно просматривать печатаемый модуль. Отпечатанный листинг из модуля всегда форматируется одним и тем же образом [за исключением ориентации страниц, которую вы можете регулировать, щелкнув на кнопке Setup (настройка) в диалоговом окне Print].
Глава 4
Типы данных, переменные и константы
Из этой главы вы узнаете о типах данных, которыми может управлять VBA, и о том, как в VBA хранятся временные данные. Информация, изложенная в этой главе, применима к VBA в любом host-приложении, реализующем VBA, — Word, Excel, PowerPoint, FrontPage, Visio, Outlook и даже Access. В действительности, информация в этой главе также применима к Visual Basic, и все, что вы узнаете о типах данных, переменных и константах, справедливо в любой из реализаций Visual Basic, в которых вы будете программировать.
Обзор типов данных Visual Basic
Перед изучением переменных, следует понять, как VBA сохраняет различные виды информации. VBA, как и большинство других систем программирования, разделяет обрабатываемые данные на числа, даты, текст и другие типы. Тип данных (data type) — это термин, относящийся к определенным видам данных, которые VBA сохраняет и которыми может манипулировать.
В табл. 4.1 обобщены типы данных VBA, показано, какой объем памяти занимает каждый тип, кратко описаны типы данных и дан диапазон значений, которые данный тип может сохранять.
•••• (byte) — это единица измерения компьютерной и дисковой памяти Байтсосто-/дгх. ит из восьми......(bits) или двоичных разрядов Обычно один алфавитный сим-
вол требует для хранения одного байта памяти
Таблица 4.1. Типы данных VBA
Название типа	Размер в байтах	Описание и диапазон значения
Byte	1	Для хранения положительного числа от 0 до 255.
Boolean	2	Для хранения логическиих значений; может содержать только значения True или False.
Currency	8	От -922337203685477.5808 до 922337203685477.5807.
Date	8	Для хранения комбинации информации о дате и времени. Диапазон дат может быть от 1 января 100 года до 31 декабря 9999 года. Диапазон времени от 00:00:00 до 23:59:59.
92
Глава 4
Название типа	Размер в байтах	Описание и диапазон значения
Decimal	12	Переменные типа Decimal сохраняются как 96-битовые знаковые целые, масштабируемые значением некоторой степени числа 10. Степень десяти определяет число десятичных знаков справа от десятичной точки и может быть в диапазоне от 0 до28. Если степень масштабного коэффициента равна 0, наибольшее число типа Decimal может быть равно ±79 228 162 514 264 337 593 543 950 335. Для степени 28 наибольшее число: ±7.9228162514264337593543950335, а самое меньшее ненулевое значение равно ±0.0000000000000000000000000001.
Double	8	Отрицательные числа: от -1.79769313486232Е10308 до -4.94065645841247Е10-324. Положительные числа: от 4.94065645841247Е10-324 до 1.79769313486232Е10308.
Integer	2	Все целые числа от -32768 до 32767.
Long	4	Все целые числа от -2147483648 до 2147483647.
Object	4	Используется для доступа к любому объекту, распознаваемому VBA. Сохраняет адрес объекта в памяти.
Single	4	Отрицательные числа: от -3.402823Е1038 до -1.401298Е10-45 Положительные числа: от 1.401298Е10-45 до 3.402823Е1038
String (переменной длины)	10 байт 't-длина строки	Используется для хранения текста. Может содержать от 0 символов до (приблизительно) 2 миллиардов символов.
String (фиксированной длины)	Длина строки (один байт на один символ)	Используется для хранения текста. Может содержать от одного до (приблизительно) 654000 символов.
Variant	16 байт + 1 байт/символ	Тип Variant может хранить любой другой тип данных. Диапазон для данных типа Variant зависит от фактически сохраняемых данных. В случае текста диапазон соответствует строковому типу; в случае чисел диапазон такой, как у типа Double.
Далее в этом разделе более подробно описывается каждый из приведенных в табл. 4.1 типов данных, кроме типа Object (тип Object рассматривается в отдельной главе).
Типы данных, переменные и константы
93
Экспоненциальное представление
В табл. 4.1 вы встретились с представлением данных, называемым экспоненциальным представлением (scientific notation), которое используется для отображения на внешних устройствах (монитор, принтер и т.д.) очень больших и очень малых чисел в компактном формате. В экспоненциальном представлении значения записываются без начальных и конечных нулей и слева от десятичного знака имеется только одна цифра. Число умножается на 10 в некоторой степени, чтобы показать, где на самом деле находится десятичный знак. Экспоненциальное представление компактно и читабельно по сравнению с обычным представлением числа с 300 нулями после него.
Помните, что отрицательная степень приводит в результате к меньшему числу, а положительная — к большему. В исходном коде невозможно использовать надстрочные (superscript) символы, поэтому VBA использует вариацию экспоненциального представления, разработанную специально для компьютеров. В экспоненциальном представлении VBA используйте букву Е с последующей степенью. В следующей таблице приводятся примеры чисел в экспоненциальном и обычном представлении.
-2.43Е2	-243
-1.43Е-2	-0.0143
5.5Е10	55 000 000 000
ЗЕ9	3 000 000 000
4.5Е-10	0.00000000045
1.6Е2	160
Вы можете преобразовывать большинство типов данных, приведенных в табл. 4.1, в другие типы. В следующей главе описывается, как VBA автоматически преобразовывает данные и как вы сами можете это делать.
Тип Date
VBA использует тип Date для хранения дат и времени. Тип Date использует восемь байтов памяти для каждой сохраняемой комбинации дата/время. При работе с данными типа Date следует знать, что VBA-типы Date не являются одними и теми же, что типы данных, используемые в рабочих листах Excel или базах данных Access, хотя они во многом похожи.
Нет необходимости беспокоиться о том, как VBA хранит данные типа Date, — можно просто отображать, сохранять или манипулировать датами; VBA автоматически управляет всеми деталями преобразования последовательного числа в год, месяц, день и время. Когда VBA отображает даты, (например, при применении MsgBox), дата представляется в коротком формате, который используется данным компьютером. Аналогично, VBA отображает информацию о времени, сохраняемую с Date, используя 12- или 24-часовый временной формат для данного компьютера. (В Windows 98/NT 4.0/2000 вы можете изменять форматы дат и времени, выбрав значок Язык и стандарты на Панели управления.)
VBA-тип Date является типом последовательных дат (serial Dates). (Последовательные даты сохраняют дату как число дней от заданной стартовой даты.) Базовой датой для VBA-типа Date является 30 декабря 1899. VBA использует отрицательные числа для представления дат ранее 12/30/1899 и положительные — для дат после 12/30/1899. Число 0 представляет саму дату 12/30/1899. По этой схеме 1 января 1900 записывается числом 2 (1/1/1990 — это 2 дня после 12/30/1899),
94
Глава 4
однако число -2 является датой 12/28/1899 (два дня до 12/30/1899). Чтобы убедиться в этом, напишите (например, в VBA Outlook) простой макрос:
Sub DateTestO
MsgBox d
End Sub	.
В результате работы этого макроса на экран будет выдана базовая дата, как показано на рис. 4.1.
Рис. 4.1
Базовой датой для VBA-типа Date является 30 декабря 1899
12/31/1899
Некоторые host-приложения VBA, такие как Excel, имеют свои собственные типы данных последовательных дат. Excel for Windows, например, также использует числа последовательных дат, но с другой базовой датой: 1 января 1900.
VBA всегда использует одну и ту же базовую дату для последовательных дат типа Date, независимо от схемы дат host-приложения — VBA всегда использует дату 12/30/1899 в качестве базовой.
В значении последовательной даты целая часть (цифры слева от десятичного знака) — это общее число дней от базовой даты. Последовательная дата VBA может иметь цифры справа от десятичного знака; эти цифры обозначают время дня как часть дня. Один час — это 1/24 дня (приблизительно 0,0416. Аналогично, одна минута — это 1/1440 дня, а секунда — 1/86400 дня.
Вы можете вычитать одну дату из другой, добавлять к дате или вычитать числа для изменения ее значения. Например, если вам необходимо определить количество дней между двумя датами, просто вычитайте более раннюю дату из более поздней. Поскольку это значения типа Date, VBA «знает», что целью вычисления является получение разности в днях между двумя этими датами. Аналогично, если вам необходимо определить дату через 60 дней после данной даты, просто прибавьте 60 к этой дате.
В VBA имеется несколько встроенных процедур (описанных в следующих главах) для отдельного извлечения года, месяца, дня, часов, минут и секунд из переменной типа Date.
Числа
VBA имеет шесть различных численных типов данных: Byte, Integer, Long, Single, Double и Currency. Численные типы данных используются для хранения (и манипулирования) чисел в различных форматах, в зависимости от конкретного типа. Численные типы предоставляют компактный и эффективный способ хранения чисел. Численный тип, заполняющий большую часть памяти (имеющий самый большой диапазон возможных значений), занимает не более восьми байтов памяти для хранения чисел, которые могут иметь до 300 цифр.
Типы данных Byte, Integer и Long
Integer — это целое число безо всякой дробной части. Числа 1, 3768 и 12 — это все целые числа; числа 1,5; 3,14; 17,21 не являются целыми. (Число 1,0 — не
1 Здесь и далее для обозначения действительных чисел используется знак запятой (,) поскольку имеется в виду обычная математическая запись числа.
Типы данных, переменные и константы
95
целое, хотя дробная часть равна нулю; целые никогда не содержат десятичного знака, даже если десятичная часть является нулем).
VBA предоставляет три различных целых типа данных: Byte, Integer и Long. Тип Byte — это наименьший из трех целых типов данных VBA и предназначен для хранения чисел только от 0 до 255. Тип Byte использует только один байт памяти (255 — это самое большое число, какое вы только можете получить с восемью битами). Вы не можете хранить отрицательные числа в типе Byte. Обычно типы Byte используются для хранения двоичных данных (графических, звуковых файлов и так далее).
Тип Integer требует двух байтов памяти; диапазон чисел, которые вы можете хранить как тип Integer, составляет от -32768 до 32767. Поскольку диапазон для типа Integer сильно ограничен, в VBA имеется другой, больший тип: Long — (длинное) целое. Этот тип для хранения числа использует 4 байта памяти и имеет диапазон значений от -2147483648 до 2147483647.
Byte, Integer и Long типы имеют пару преимуществ по сравнению с другими численными типами данных: целые требуют меньше памяти для хранения чисел, чем другие численные типы данных VBA, а математические операции и операции сравнения над числами Byte, Integer и Long типов быстрее, чем эти же операции для численных типов данных с плавающей точкой. Типы Byte, Integer и Long имеют различное применение. Наиболее часто они используются для кумулятивных вычислительных операций вследствие их компактного размера и более быстрой скорости выполнения арифметических операций. Используйте типы Byte, Integer и Long для чисел, которые не имеют дробной части.
VBA автоматически преобразует данные типов Byte, Integer и Long в текст, когда вы выводите их на экран с использованием таких процедур, как MsgBox.
Числа с плавающей точкой
Числа с плавающей точкой (floating point numbers) могут иметь любое число цифр до или после десятичной точки (в пределах границ конкретного типа данных) и получили свое название вследствие того факта, что десятичная точка «плавает» из одной позиции в другую, в зависимости от того, сохраняется в памяти большое или малое значение. Числа 11,0123; -1107,1; 0,0125 и 435,67876 — это числа с плавающей точкой. Числа с плавающей точкой иногда называют также действительными (real) числами. Используйте типы данных с плавающей точкой всякий раз, когда вам требуется сохранить число, имеющее дробную часть.
VBA имеет два различных типа данных с плавающей точкой: Single и Double. Для данных типа Single требуется 4 байта памяти, и этот тип может использоваться для хранения отрицательных чисел от -3,402823 х 1038 до -1,401298 х 10 45 и положительных от 1,401298 х 10'45 до 3,402823 х Ю38. Числа, хранимые с использованием типа Single, называются числами одинарной точности (Single-precision numbers). Для данных типа Double требуется 8 байтов памяти, и этот тип может использоваться для хранения отрицательных чисел от -1,79769313486232 х Ю308 до -4,94065645841247 х 10-324 и положительных от 4,94065645841247 х 10-324 до 1,79769313486232 х 1О308. Числа, хранимые с использованием типа Double, называются числами двойной точности (Double-precision numbers).
Хотя числа одинарной и двойной точности имеют большие диапазоны, чем другие численные типы данных, у них имеется два небольших недостатка. Операции, выполняемые над числами с плавающей точкой, немного медленнее подобных операций над другими численными типами данных. Кроме того, числа, хранимые как типы данных с плавающей точкой, могут быть подвержены ошибкам округления. Как и в случае с целыми типами данных, VBA автоматически преобразует значения типа Single и Double в текст, когда вы отображаете их с помощью процедур, таких как MsgBox. Если число с плавающей точкой очень большое или очень малое, VBA отображает его в экспоненциальном представлении.
96
Глава 4
Тип данных Currency
VBA-тип Currency — это число с фиксированной точкой (fixed-point number), то есть десятичная точка всегда находится в одном и том же месте — справа от десятичной точки всегда имеется четыре цифры. Используйте тип Currency для хранения чисел, когда точность крайне важна, что бывает при «денежных» вычислениях.
Тип Currency требует 8 байтов памяти и может сохранять числа от -922337203685477,5808 до 922337203685477,5807. Математические операции над числами типа Currency имеют небольшие или не имеют ошибок округления, поэтому они точнее, чем операции над числами с плавающей точкой. Ошибки округления с числами типа Currency обычно возникают только тогда, когда вы умножаете или делите числа типа Currency на значения другого численного типа. Подобно обработке всех других численных типов данных VBA автоматически преобразует значения Currency в текст, когда вы их выводите на экран.
Текстовые строки
Любые текстовые данные, сохраняемые в программе VBA, называются строками (strings). Строки в VBA сохраняются с использованием типа данных String. Строки получили такое название, потому что текстовые данные обычно рассматриваются как строки символов. Строка может содержать текстовые символы любых типов: буквы алфавита, цифры, знаки пунктуации или различные символы. Строки в коде VBA всегда заключаются в двойные кавычки ("”). "Малый Браун", "Петр Первый”, "3,1" и ”1 000,00" — это строки. Существуют две категории строк: строки переменной длины, размер которых растет или уменьшается, и строки фиксированной длины, размер которых всегда остается одним и тем же. Все строки в VBA являются строками переменной длины, если только вы не задаете фиксированную длину (об этом будет рассказано далее в этой главе).
Типы String играют важную роль во многих программах VBA. Большинство данных ввода пользователей (в диалоговых окнах, ячейках рабочих листов) — это строковые данные. Кроме того, поскольку вы можете отображать на экране только текст, все другие типы данных должны быть преобразованы в строковые данные перед тем, как вы сможете их вывести на экран. Многие встроенные процедуры VBA (подобные Msgbox) используют строковые данные во всех или в некоторых своих аргументах. Если вы широко используете Word VBA, то могли заметить, что процедуры манипулируют исключительно строковыми данными.
VBA предоставляет несколько операторов для конкатенации (concatenate), то есть для соединения вместе и для сравнения строк. VBA имеет также несколько встроенных процедур, помогающих извлекать подстроки из более длинных строк, находить символы или слова в строке, изменять регистр букв в строке и так далее. В следующих главах описываются строковые операторы VBA и процедуры для манипулирования строками VBA.
Логические значения
Обычно VBA-программа (как и любые другие программы) «принимает» решения, проверяя, являются ли истинными различные условия. Для упрощения тестирования условий и обеспечения сохранения результатов такого тестирования в VBA имеется логический тип данных. Логические значения True и False называют булевыми (Boolean) значениями. (Их название связано с именем математика, разработавшего систему математической логики.) Логический тип данных VBA называют также типом Boolean.
Boolean-тип VBA требует двух байтов памяти и может иметь одно из двух значений: True или False. Если вы отображаете тип Boolean на экране, VBA автома-
Типы данных, переменные и константы
97
тически преобразует его в строку, содержащую либо слово True, либо False. Булевы значения получают как результат операции сравнения. Операция сравнения (comparison operation) имеет место при сравнении одного с другим, например, при сравнении двух чисел для определения, которое из них больше, или сравнении двух строк для определения, которая из строк находится ниже в алфавитном порядке. В следующей главе описываются различные операции сравнения VBA.
Тип данных Variant
Тип данных Variant — это особый тип данных, который может сохранять любые типы, приведенные в табл. 4.1, за исключением типа Object. VBA использует тип Variant для всех переменных, если только вы не объявляете явно тип переменной, как будет описано далее в этой главе.
Данные типа Variant принимают характеристики определенного типа, который они сохраняют в данный момент. Например, если данные типа Variant содержат строковые данные, Variant принимает характеристики типа String. Если данные типа Variant содержат численные данные, Variant принимает характеристики какого-либо численного типа, обычно — Double, хотя типы Variant могут также иметь характеристики типов Integer, Long, Single или Currency.
VBA использует для данных типа Variant наиболее компактное представление, возможное для конкретных значений, находящихся в данных. Если VBA сохраняет целое число в переменной типа Variant, это число обрабатывается как данные типа Integer или Long, в зависимости от его размера. Например, для VBA число 15 в типе Variant является данными типа Integer; VBA обрабатывает число 1 000 000 в Variant как данные типа Long.
VBA сохраняет большинство чисел с плавающей точкой в данных типа Variant как тип Double и использует тип Variant так, что вам не всегда приходится беспокоиться об указании типов переменных, которые вы используете в коде. Любые переменные, для которых вы не объявляете специально тип, становятся типом Variant.
Несмотря на то, что типы Variant удобны и избавляют от некоторой части работы при написании процедур, они требуют большего объема памяти, чем любой другой тип данных, за исключением больших строк. Кроме того, математические операции и операции сравнения над данными типа Variant выполняются медленнее, чем подобные операции над данными любого другого типа. В общем, следует избегать использования переменных Variant: если вы будете полагаться на переменные типа Variant, может сформироваться привычка неаккуратного программирования и вам будет трудно находить и устранять ошибки в программах.
Переменные
Переменные очень важны, поскольку они обеспечивают возможность в компьютерной программе временно сохранять и манипулировать данными. В этом разделе описывается, что такое переменная и как создавать переменные.
Что такое переменная?
Переменная (variable) — это имя, которое программист дает области компьютерной памяти, используемой для хранения данных какого-либо типа. Вы можете представлять себе переменную как ящик стола, в который можно положить любой отдельный элемент данных и хранить его для последующего использования. Имя переменной является идентифицирующей меткой для этого ящика стола. Содержимое ящика (значение переменной) может меняться, но наименование ящика
4 Программирование на VBA 2002
98
Глава 4
(имя переменной) остается тем же. Переменные VBA могут хранить любые типы данных, перечисленные в табл. 4.1.
В некотором смысле переменная подобна именованной ячейке рабочего листа. В Excel вы можете давать имя ячейке в рабочем листе, а затем ссылаться на эту ячейку по ее имени так, что вам не приходится использовать или даже запоминать фактический адрес ячейки из строки и столбца каждый раз, когда необходимо сослаться на данные или формулы в этой ячейке. VBA (как и все системы программирования) справляется со всеми деталями нахождения конкретных мест в памяти компьютера вместо вас. Нет необходимости беспокоиться о конкретных адресах данных какой-либо переменной, просто используйте имя этой переменной для ссылки на сохраняемые данные.
Переменные в операторах VBA используются таким же образом, что и переменные в алгебраических уравнениях. Переменная представляет числа, текстовые данные или другую информацию, которая точно не известна во время написания оператора, но будет в наличии и доступна при выполнении этого оператора.
Всякий раз, когда имя переменной появляется в операторе, VBA вставляет в этот оператор фактическое значение, хранимое в текущий момент в участке памяти, на который ссылается переменная. В следующем примере, если переменная AnyNum содержит число 2, то весь оператор будет иметь в качестве результата 4:
AnyNum + 2
В качестве другого, более сложного примера, рассмотрим формулу, вычисляющую, какую часть в процентах одно число составляет от другого:
Percent = (Part / Whole) * 100
В этом простом операторе переменные с именем Part и Whole представляют два различных числа. Формула в этом операторе вычисляет, какую часть составляет значение, хранимое в переменной с именем Part, от значения, хранимого в переменной с именем Whole, а в переменную с именем Percent помещается результат вычисления. При выполнении этого оператора VBA находит все числа, хранимые в памяти, на которые ссылаются Part и Whole, и вставляет их в оператор перед выполнением любых вычислений. Если, например, до начала выполнения этого оператора значение, хранимое в переменной под именем (можно просто значение переменной) Part, было равно 5, а значение переменной Whole — 20, то результатом, который будет сохранен в переменной Percent, станет число 25.
Выбор имен для переменных
Можно выбирать любое имя для переменной за небольшими исключениями. В этом разделе сначала объясняются правила и ограничения VBA для имен переменных, а затем описываются некоторые принципы, которыми следует руководствоваться при выборе имен переменных.
Идентификаторы
Идентификатор (identifier) — это имя, которое вы даете элементам в создаваемых вами процедурах и модулях, таким как переменные. Термин идентификатор основывается на том факте, что имена, которые вы создаете, определяют конкретные участки памяти (в случае имени переменной), группы инструкций (в случае имени макроса или процедуры) или другие элементы программы.
При выборе имени переменной необходимо соблюдать следующие правила:
	Имя переменной должно начинаться с буквы алфавита.
	После первой буквы имя переменной может состоять из любой комбинации цифр, букв или символов подчеркивания (_).
Типы данных, переменные и константы
99
	Имена переменных не могут содержать пробелы, точку (.) или любой другой символ, который VBA использует для обозначения математических операций и операций сравнения (=, +, - и так далее).
	Имена переменных не могут превышать 255 символов.
	Имя переменной не может дублировать определенные ключевые слова VBA. Если вы выберете имена переменных, дублирующие ключевые слова, называемые ограниченными ключевыми словами (restricted keywords), VBA отображает одно из нескольких возможных сообщений об ошибке синтаксиса.
	Имя переменной должно быть уникальным в рамках его области действия (scope). То есть имя переменной должно быть уникальным в пределах процедуры или модуля, в котором вы объявляете эту переменную.
Некоторые примеры правильных имен переменных:
Vari
Pay_Date
Ald_Item
Percent
Whole
Part
Linel2
Примеры неправильных имен переменных:
New Item — Неправильно, потому что содержит символ пробела
5thDimension — Не начинается с буквы
Dim — Дублирует ключевое слово VBA
Week/Day — Содержит неверный символ: VBA интерпретирует косую черту как оператор деления
_Рау — Содержит недопустимый символ в начале.
Имена переменных не «чувствительны» к состоянию регистра (not case-sensitive), то есть написание имени переменной прописными или заглавными буквами не имеет значения. Имена FirstMyVar и firstmyvar представляют для VBA одно и то же. VBA регулирует написание имен переменных в вашем коде на основе заглавных букв, которые вы использовали в последний раз, когда вводили имя той или иной переменной. Например, если вы вводите имя FirstMyVar, а затем позже — имя переменной firstmyvar, VBA заменяет все вхождения имени First-MyVar на firstmyvar.
При выборе имен переменных старайтесь делать их по возможности наиболее информативными: выбирайте имена, подобные AllSum, а не х или у. Хорошим именем для переменной, которая хранит значение, представляющее температуру в градусах Цельсия, является, например, CelsiusTemp или DegreesC. В примере с формулой процентного отношения из предыдущего раздела имена переменных Part и Whole были выбраны так, чтобы отражать назначение и использование чисел, которые они хранят.
Создание переменных
Самым простым способом создания переменной является использование ее в операторе VBA. VBA создает переменную и резервирует память для ячейки памяти переменной, когда эта переменная в первый раз появляется в операторе (обычно в операторе, сохраняющем значение данных в переменной).
Сохранение значения данных в переменной называется присваиванием переменной (assigning the variable или making an assignment). Присваивание выполняется с помощью оператора присваивания, представляемого знаком (=). Следующая строка является примером присваивания значения переменной:
MyVar = 25
4*
100
Глава 4
Этот оператор сохраняет численное значение 25 в ячейке памяти, заданной именем переменной MyVar. Если этот оператор первым использует данную переменную в процедуре, то VBA создает эту переменную, резервирует ячейку памяти для хранения данных этой переменной и затем сохраняет число 25 в ячейке памяти, заданной именем переменной.
Если переменная MyVar уже существует, то VBA сохраняет число 25 в ячейке памяти, на которую ссылается MyVar. Новое значение заменяет любое, ранее сохраненное в MyVar значение, и предыдущее содержимое MyVar теряется.
Создание переменной путем ее использования в операторе называется неявным объявлением переменной (implicit variable declaration). Используя переменную в операторе, вы неявно указываете (объявляете) VBA, что хотите создать эту переменную. Все переменные, которые VBA создает неявным объявлением переменной, имеют тип данных Variant. Неявное объявление переменных известно также как объявление переменных «на лету» (on-the-fly).
Неявное объявление переменных удобно, но имеет потенциальные проблемы. Например, когда вы имеете переменную с именем MyVar и сделаете позже ошибку в имени, набирая MVar. В зависимости от того, где появится в вашем коде неправильное имя переменной, VBA может выдать ошибку времени исполнения или просто создать новую переменную. Если VBA создаст новую переменную, у вас могут возникнуть проблемы, которые очень трудно обнаружить.
Неявное объявление переменных вызывает также проблемы, если вы записываете оператор присваивания, ошибочно полагая, что неявно объявляете новую переменную, тогда как вы на самом деле используете ранее созданную. В этом случае вы нечаянно уничтожаете ранее сохраненное значение. Это обычно не приводит к ошибке времени исполнения, но вызывает другие проблемы, причину которых трудно обнаружить.
По этим и другим причинам VBA предоставляет вам возможность выполнять явное (explicit) объявление переменных. Явное объявление переменных имеет следующие преимущества:
	Ускоряется выполнение кода. VBA создает все объявленные явно переменные в модуле или процедуре перед выполнением кода процедуры. Скорость выполнения кода увеличивается на то количество времени, которое иначе необходимо для анализа и создания неявно объявляемых переменных.
	Уменьшается количество ошибок в результате неправильного написания имени переменной.
	Код становится более читабельным и понятным. Видя все объявления переменных в начале модуля или процедуры, пользователь может легко определить, какие переменные используются в этом модуле или процедуре.
	С помощью явного объявления переменных можно нормализовать выделение заглавными буквами в имени переменной. Если вы явно объявляете переменную, VBA всегда изменяет заглавные буквы в имени переменной в операторе VBA в соответствии с именем в объявлении переменной. Например, если вы явно объявляете переменную с использованием заглавных букв в имени Му Value, а затем позже введете имя этой переменной как myvalue, VBA заменяет myvalue на MyValue для соответствия выделению заглавными буквами в явном объявлении:
MyValue	>
Для явного объявления переменных используйте VBA-оператор Dim со следующим синтаксисом:
СИНТАКСИС
Dim namel [, name2]
nameN — это любой допустимый идентификатор переменной. Например:
Типы данных, переменные и константы
101
Dim PentProfit
Dim PentProfit, Gross_Income, Total_Costs
Первый из вышеприведенных операторов указывает VBA создать переменную с именем PentProfit. (Ключевое слово Dim, между прочим, является сокращением слова Dimension). Все переменные, которые вы создаете с этой формой ключевого слова Dim, являются переменными типа Variant.
Всякий раз, когда VBA создает новую переменную, эта переменная инициализируется: строки инициализируются пустыми строками (не содержат символов), числа — значением 0, переменные Boolean — значением False, даты — 30 декабря 1899 года.
Переменную можно объявлять только один раз в отдельной процедуре или модуле. Так как оператор Dim находится перед любыми операторами, фактически использующими переменную, вы можете помещать его в любом месте в процедуре. В практике программирования хорошим правилом является собирать все явные объявления переменных в одном месте в начале процедуры.
В листинге 4.2 приведена процедура HelloWorld из предыдущей главы, модифицированная для явного объявления переменной с именем HelloMsg, которую она использует для хранения текста, отображаемого оператором MsgBox. (Процедура HelloWorld в листинге 4.1 отображает диалоговое окно, показанное на рис. 4.2).
Листинг 4.1. Процедура HelloWorld с явным объявлением переменной
1	Sub HelloWorld()
2	Dim HelloMsg	' переменная для MsgBox
3	HelloMsg = "Hello, World!"
4	MsgBox HelloMsg, , "Окно приветствия"
5	End Sub
Оператор Dim (в строке 2) листинга 4.1 объявляет переменную HelloMsg и резервирует для нее область памяти (в данной подпрограмме HelloMsg — это переменная типа Variant). Строка 2 включает конечный комментарий, указывающий назначение этой переменной. В строке 3 выполняется присваивание переменной HelloMsg строки "Hello, World!". Далее (в строке 4) переменная HelloMsg используется как один из аргументов для процедуры MsgBox. Функция MsgBox отображает то же окно сообщения, что и раньше. Хотя MsgBox получает теперь свой первый аргумент из переменной, эта переменная содержит ту же строковую информацию, что была ранее (в листингах предыдущей главы) записана непосредственно в оператор MsgBox. Заметьте, что в результате мы получили окно сообщений, которое не несет информации о том, в каком приложении работает исходный макрос (ранее эта информация находилась в заголовке окна).
Рис. 4.2
Окно сообщений, полученное
процедурой HelloWorld
Hello, World!
Окно приветствия
Задание типа данных переменной
Все переменные в VBA, независимо от того, объявляются ли они неявно или явно, являются переменными типа Variant, если только вы не задаете тип переменной в объявляющем ее операторе. Объявление типизированных переменных (переменных, тип данных которых вы задаете) имеет несколько преимуществ:
102
Глава 4
	Типизированные переменные ускоряют выполнение кода программ. Поскольку при объявлении вы указываете VBA тип переменной, выполнение программы ускоряется на то время, которое VBA потратил бы иначе на анализ переменной типа Variant, чтобы определить ее конкретный тип.
	Типизированные переменные повышают эффективность кода. Переменные типа Variant могут занимать гораздо больше памяти, чем переменные определенных типов. Типизированная переменная занимает только память, необходимую для этого определенного типа. Использование типизированных переменных может значительно сократить объем памяти, требуемый для вашей программы VBA; в некоторых случаях использование типизированных переменных может иметь значение с точки зрения того, достаточно ли памяти для работы вашей процедуры или нет.
	Программный код с типизированными переменными легче читать и понимать.
	Программы, использующие типизированные переменные, «помогают» обнаруживать некоторые типы ошибок программистов, например, недопустимое смешивание типов данных, потому что VBA отображает ошибки времени исполнения, которые не возникли бы, если бы переменные были нетипизированными. Существуют другие причины, по которым вам может понадобиться объявлять типизированные переменные. Например, несмотря на то, что переменные типа Variant могут сохранять даты, переменная типа Variant может неправильно сохранить дату из Excel. С переменными, объявленными явно с типом Date, такой проблемы не возникает.
Тип переменной объявляется в том же операторе, который используется для объявления самой переменной. Можно объявлять типизированную переменную либо при неявном объявлении, либо при явном — с помощью Dim. При объявлении переменных типа String, можно также задавать длину строки.
Использование Dim для объявления типизированных переменных
Для объявления переменной и ее типа с помощью оператора Dim добавьте ключевое слово As перед именем переменной, а затем введите имя типа данных для этой переменной. Вот общий синтаксис для использования оператора Dim при объявлении типизированных переменных:
СИНТАКСИС
Dim varnamel [As typel] [, varname2 [As type2] ] [As type]
VarnameN представляет любое допустимое имя переменной VBA, a type(N) — любое из имен типов данных VBA.
Следующие строки показывают примеры правильного синтаксиса для объявлений типизированных переменных:
Dim Счетчик As Single
Dim Цена As Currency
Dim ДатаПлатежа As Date
Dim Сообщение As String
Dim Counter As Integer
Dim PentProfit As Single, Gross_Sales As Currency, Message As String
Dim NetValue, PentProfit As Single
После объявления типизированной переменной, независимо от того, объявляется ли эта переменная явно или неявно, и как задается тип, эта переменная сохраняет тот же самый тип столько времени, сколько она существует. Нельзя пере-объявить переменную или переопределить ее тип.
Типы данных, переменные и константы
103
Использование символов определения типа для объявления типизированных переменных
При неявном объявлении можно также задавать тип переменной, добавляя специальный символ, называемый символом определения типа (type-definition character), в конец имени переменной. В табл. 4.2 приводятся символы определения типа VBA и типы, которые они обозначают.
Таблица 4.2. Символы определения типа
Символ определения	Тип
!	Single
@	Currency
#	Double
$	String
%	Integer
&	Long
Заметьте, что в этой таблице приведены только шесть символов определения типа; нет символов определения типа для Byte, Boolean, Date, Object или Array. Символы определения типа могут находиться только в конце имени переменной.
Символы определения типа в VBA имеют свою историю. В ранних разновидностях языка BASIC символы определения типа были единственным способом задать тип переменной. Несмотря на то, что следует знать, что такое символы определения типа и как они используются, необходимость в их применении бывает редкой — использование оператора Dim с ключевым словом As намного легче и понятнее. Большинство программистов, работающих на VBA, не используют символы определения типа.
В листинге 4.2 приведен еще один вариант процедуры HelioWorld, которая обсуждалась ранее.
Листинг 4.2. Явное и неявное объявление типа
1	Sub HelloWorld()
2	Dim HelloMsg As String
3	HelloMsg = "Hello, World!"
4	Title$ = "Окно приветствия"
5	MsgBox HelloMsg, , Title$
6	End Sub
Эта версия процедуры Hello World работает во многом так же, как и предыдущие. Строка 1 содержит объявление процедуры. В строке 2 оператор Dim явно объявляет переменную HelloMsg. Поскольку оператор Dim включает ключевое слово As и имя типа String, переменная HelloMsg имеет тип String. Строка 3 присваивает текст сообщения строковой переменной HelloMsg.
Строка 4 неявно объявляет переменную Title$ и в то же время присваивает переменной текст заголовка окна сообщения. Поскольку имя переменной Title$ имеет на конце символ определения типа для строки, эта переменная также имеет тип String. Наконец, строка 5 использует оператор MsgBox для отображения окна сообщения; в этом операторе и текст сообщения, и строка заголовка окна являются переменными: HelloMsg и Title$, соответственно.
104
Глава 4
После добавления символа определения типа к переменной необходимо включать символ определения типа каждый раз, когда вы используете имя переменной. Если бы символ определения типа был опущен в имени переменной Title$ в строке 5 (где Title$ используется первый раз после неявного типизированного объявления), то во время выполнения процедуры произошла бы runtime-ошибка.
Использование Dim для объявления
строковых переменных фиксированной длины
Независимо от того, объявляются ли переменные типа String с помощью оператора Dim или добавлением символа определения типа $, создаваемые вами строковые переменные по умолчанию являются строками переменной длины.
Строковые переменные переменной длины изменяют длину, в зависимости от длины строки, сохраняемой переменной. Иногда может понадобиться использовать строку фиксированной длины (fixed-length). Строки фиксированной длины всегда имеют одну и ту же длину. Они полезны, если необходимо обеспечить, чтобы текст, сохраненный в строковой переменной, всегда содержал одно и то же число символов.
Можно использовать строки фиксированной длины, например, для выравнивания информации в столбцах при ее отображении или для обеспечения того, чтобы строковые данные, сохраняемые в отдельной переменной, никогда не превышали определенной длины. Существует только один способ объявления строковой переменной фиксированной длины: необходимо использовать оператор Dim. Следующая строка показывает общий синтаксис для создания строки фиксированной длины:
СИНТАКСИС
Dim varname As String * N
Varname — это любое допустимое имя переменной, a N — это любое число от 1 до максимальной длины строки, равной примерно 2 миллиардам символов (Ранее 65 000 (64К) символов в Windows 3.1).
Следующий оператор является примером объявления строки фиксированной длины:
Dim LastName As String * 30
Символ (*), за которым следует число после ключевого слова String указывает VBA создать строковую переменную как строку фиксированной длины с заданной длиной (в этом случае — 30 символов).
Область действия: доступность переменных
Термин область действия (scope) относится к области процедуры или модуля VBA, где данная переменная, процедура или другой идентификатор, являются доступными. В этом разделе описываются два базовых уровня области действия: процедурный и модульный. Переменные, процедуры и идентификаторы, которые доступны только в процедуре, имеют область действия процедурного уровня, а те, которые доступны для всех процедур в модуле, имеют область действия модульного уровня.
*
Область действия процедурного уровня
Переменная, объявленная в процедуре, является доступной только в этой процедуре. Например, переменная HelloMsg из строки 2 листинга 4.1, является доступной только в процедуре HelloWorld; никакая другая процедура не имеет доступа к этой переменной. В действительности, переменная HelloMsg реально существует только в то время, когда VBA фактически выполняет процедуру HelloWorld.
Типы данных, переменные и константы
105
Поэтому говорят, что переменная HelloMsg имеет область действия процедурного уровня (procedure-level scope).
Может быть, сначала это незаметно, но VBA ограничивает доступ к переменным посредством своих правил области действия для упрощения работы программиста. Поскольку переменная с областью действия процедурного уровня недоступна ни для какой процедуры, за исключением той, в которой объявляется эта переменная, можно не очень беспокоиться о дублировании имен переменных.
Правила выбора имен переменных указывают, что имя переменной должно быть уникальным в ее области действия. Для переменных с областью действия процедурного уровня это означает, что вы не можете объявлять две переменные с одним и тем же именем в одной и той же процедуре. (Очевидно, что ни VBA, ни пользователь не могут определить, какую переменную вы намереваетесь использовать, если обе они имеют одно и то же имя).
Поскольку область действия процедурного уровня ограничивает доступ к переменной процедурой, в которой объявляется эта переменная, вы можете использовать то же имя переменной в разных процедурах. Листинг 4.3 показывает две законченные процедуры. (HelloWorld в этом листинге отображает то же окно сообщения, которое было показано ранее на рис. 4.1.)
Листинг 4.3. Область действия процедурного уровня
1 Sub	HelloWorld()
2 3 4 5 End 6 7 Sub	Dim HelloMsg	1 сохраняет текст для MsgBox HelloMsg = "HelloWorld!" MsgBox HelloMsg, , "Окно приветствия" Sub HelloDave()
8 9 10 11 End	Dim HelloMsg	' сохраняет текст для Msgbox HelloMsg = "Hello, Dave!" MsgBox HelloMsg, , "Другое окно сообщения" Sub
Строки 1-5 содержат ту же процедуру HelloWorld из листинга 4.1, которая работает точно так же. В модуль была добавлена процедура HelloDave, которая и начинается в строке 7 листинга 4.3. Процедура HelloDave работает так же, как процедура HelloWorld, просто она отображает другое текстовое сообщение и заголовок в своем диалоговом окне. На рис. 4.2 показано окно сообщений, отображенное процедурой HelloDave.
Заметьте, что в строках 2 и 8 обе процедуры используют оператор Dim для объявления переменных с именем HelloMsg. Это разумно, потому что HelloMsg является хорошим описательным именем для содержимого и назначения переменной в обеих процедурах.
Поскольку переменные HelloMsg объявляются внутри отдельных процедур и имеют область действия процедурного уровня, не возникает двусмысленности по поводу того, какую переменную будет использовать VBA. В процедуре HelloWorld VBA использует переменную HelloMsg, объявленную локально (строка 2 в листинге). В процедуре HelloDave VBA использует переменную HelloMsg, объявленную локально в этой процедуре (строка 8).
Область действия модульного уровня
Иногда необходимо, чтобы несколько процедур имели доступ к одной и той же переменной. Обычно эффективнее вычислить один раз какое-либо значение, сохранить его в переменной, а затем использовать эту переменную в нескольких процедурах, чем вычислять одно и то же значение снова и снова.
106
Глава 4
VBA позволяет объявлять переменные, доступные для нескольких процедур. Когда какая-либо переменная доступна всем процедурам в модуле, говорят, что эта переменная имеет область действия модульного уровня (module level). VBA ограничивает область действия переменной модульного уровня модулем, в котором объявляется эта переменная. (VBA предоставляет способы еще большего расширения области действия переменной; эти методы описываются далее.)
Для того чтобы переменная была доступной для всех процедур в определенном модуле, поместите оператор Dim для нее в начало модуля перед любыми объявлениями процедур. В листинге 4.4 приведен модуль, содержащий две простые процедуры и единственное объявление переменной модульного уровня. Процедура HelloWorld в листинге 4.4 отображает то же окно сообщения, которое показано на рис. 4.2.
Область в начале модуля перед любыми объявлениями процедур называют областью ............ (declaration) модуля, потому что именно туда следует помещать
объявления переменных модульного уровня и другие директивы для VBA, влияющие на весь модуль Вы можете легко переходить к области объявлений любого модуля, выбирая Declarations в списке Procedure окна Code
Листинг 4.4. Область действия переменной модульного уровня
1	Dim HelloMsg	' используется всеми процедурами в этом модуле
2
3	Sub HelloWorld()
4	HelloMsg = "Hello, World1"
5	MsgBox HelloMsg, , "Окно приветствия"
6	End Sub
7
8	Sub HelioDave ()
9	HelloMsg = "Hello, Dave1"
10	MsgBox HelloMsg, , "Другое окно сообщения"
11	End Sub
В этом листинге строки 3-6 содержат процедуру HelloWorld, а строки 8-11 — процедуру HelloDave. Обратите внимание на то, что ни одна из этих процедур не содержит операторов Dim. В строке 1 оператор Dim используется для объявления переменной с именем HelloMsg.
Поскольку строка 1 объявляет переменную HelloMsg на уровне модуля, эта переменная доступна для всех процедур в одном и том же модуле. В строках 4 и 5 процедуры HelloWorld VBA использует переменную модульного уровня HelloMsg. Аналогично, в строках 9 и 10 процедуры HelloDave VBA использует ту же переменную модульного уровня HelloMsg.
Использование переменных с одним и тем же именем в различных уровнях области действия
Имя переменной должно быть уникальным в ее области действия. Точно так же, как нельзя объявлять две переменные с одним и тем же именем в одной процедуре, нельзя объявлять две переменные модульного уровня с одним именем в одном и том же модуле (и по тем же причинам).
Однако можно иметь переменные с одним и тем же именем на разных уровнях области действия. Когда переменные имеют одно имя, но разные области действия, VBA использует переменную с наиболее локальной (local) областью действия. В листинге 4.3 были уже показаны две различные процедуры, каждая из которых объявляет свою переменную, но использует одно и то же имя для переменной. Поскольку эти переменные имеют область действия процедурного уровня, каждая процедура может использовать только свою локальную переменную. В листин
Типы данных, переменные и константы
107
ге 4.5 приведен модуль, содержащий три процедуры, каждая из которых используют переменные с одним и тем же именем.
	Листинг 4.5. Комбинированная модульная и процедурная область действия
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17	Dim HelloMsg	' используется всеми процедурами в этом модуле, ' которые не имеют своей переменной HelloMsg Sub HelloWorld() HelloMsg = "Hello, World!" MsgBox HelloMsg, , "Greeting Box" End Sub Sub HelioDave() HelloMsg = "Hello, Dave!" MsgBox HelloMsg, , "Другое окно сообщения" End Sub Sub AnotherMessage() Dim HelloMsg ' локальное объявление HelloMsg = "Еще одно окно сообщения" MsgBox HelloMsg, , "Еще одно окно сообщения" End Sub
В листинге 4.5 приведены три различные процедуры. Первые две уже использовались в листинге 4.4. Третья процедура AnotherMessage начинается в строке 13 и заканчивается в строке 17. AnotherMessage работает так же, как предыдущие процедуры, отображая сообщение в диалоговом окне с использованием оператора MsgBox.
Заметьте, что строка 1 этого листинга объявляет переменную модульного уровня HelloMsg. Строка 14 в процедуре AnotherMessage также объявляет переменную с именем HelloMsg. При выполнении процедуры HelloWorld VBA использует переменную HelloMsg, объявленную в строке 1. HelloWorld не имеет переменных, объявленных локально, здесь невозможна двусмысленность, поэтому VBA использует переменную модульного уровня. Аналогично, при выполнении процедуры Hello-Dave VBA также использует переменную HelloMsg, объявленную в строке 1.
Однако в процедуре AnotherMessage имеется свое объявление переменной HelloMsg (строка 14). При выполнении строк 15 и 16 VBA устраняет любую двусмысленность по поводу того, какую переменную HelloMsg следует использовать, выбирая наиболее локальную переменную: HelloMsg, объявленную как переменную процедурного уровня.
Переменная модульного уровня HelloMsg, объявленная в строке 1, недоступна для процедуры AnotherMessage.
Переменные процедурного уровня часто называют.........(local) переменны-
ми, потому что их объявления являются локальными для выполняемой в данный момент процедуры.
Персистенция: Определение того, как долго переменные удерживают свое значение
Персистенция (persistence) — это термин, используемый для ссылки на продолжительность времени, в течение которого любая данная переменная удерживает значение, присвоенное ей. Значения, присвоенные переменным сохраняются только, пока переменная является активной в ее области действия.
Когда переменная объявляется в процедуре, она существует только, пока VBA выполняет эту процедуру. Прй выполнении процедуры VBA резервирует область
108
Глава 4
памяти для всех переменных, объявленных локально в этой процедуре, независимо от того, объявляются переменные явно или неявно. После окончания процедуры VBA освобождает память, использовавшуюся локальными переменными, в общий пул имеющейся в наличии компьютерной памяти и локальные переменные этой процедуры прекращают существование.
Например, в начале выполнения процедуры HelloWorld в листинге 4.1 VBA резервирует область памяти для переменной HelloMsg. Ко1да VBA заканчивает выполнение HelloWorld, память, зарезервированная для переменной HelloMsg, возвращается в общий пул имеющейся в наличии памяти с уничтожением любого значения, которое было сохранено в HelloMsg.
Переменные процедурного уровня создаются каждый раз, когда процедура начинает выполняться, и уничтожаются, когда процедура перестает выполняться. Говоря более техническими терминами, локальная переменная является неопределенной или вне контекста (out of context) до тех пор, пока процедура, объявляющая ее, не начинает выполняться. Когда процедура, объявляющая переменную, перестает выполняться, переменная опять становится неопределенной.
Значения переменных, объявляемых на уровне модуля, удерживаются в памяти столь долго, сколько VBA выполняет процедуру в этом модуле.
При выполнении процедуры VBA фактически просматривает весь модуль, содержащий эту процедуру, и создает любые переменные модульного уровня. Пока VBA выполняет процедуру в этом модуле, значения переменных модульного уровня сохраняются.
Требование явного объявления переменных
Хотя неявное объявление переменных (объявление переменных просто их использованием) удобно, с ним связаны некоторые проблемы. Когда переменные объявляются неявно, существует риск нечаянно создать новую переменную, когда на самом деле необходимо использовать уже существующую, или использовать существующую переменную, когда пользователь намеревается создать новую. Обе эти ситуации приводят к ошибкам в коде, которые очень трудно отслеживать. (Bug — любая ошибка в коде, которая мешает его правильному выполнению или приводит к ошибочным результатам.)
В этой книге уже рассказывалось, как использовать оператор Dim для объявления переменных и уменьшения проблем, связанных с неявным объявлением. Использование только оператора Dim для объявления переменных не всегда помогает обнаруживать или предотвращать небольшие ошибки, относящиеся к неявному объявлению переменных.
Чтобы легче было в любое время обнаруживать ошибки, связанные с неявным объявлением переменных, VBA предоставляет команду Option Explicit. При использовании Option Explicit VBA требует объявления всех переменных (с помощью оператора Dim) перед их использованием. Команда Option Explicit в основном препятствует неявному объявлению переменных где-либо в модуле, содержащем эту команду.
Чтобы установить режим, при котором VBA требует явного объявления для всех переменных в модуле, добавьте команду Option Explicit в область объявлений модуля, то есть в начало модуля перед любыми объявлениями переменных или процедур. В листинге 4.6 приведен тот же модуль, что и в листинге 4.4, но с добавленной командой Option Explicit.
Листинг 4.6. Модульная команда Option Explicit
1	Option Explicit ' требует явного объявления переменных модуля
2	Dim HelloMsg	' используется всеми процедурами в этом модуле
3
Типы данных, переменные и константы
109
4	Sub	HelloWorld()
5		HelloMsg = "Hello, World1"
6		MsgBox HelloMsg, , "Окно приветствия"
7	End	Sub
8		
9	Sub	HelloDave()
10		HelloMsg = "Hello, Dave!"
11		MsgBox HelloMsg/ , "Другое окно сообщения
12	End	Sub
Кроме строки 1, все в этом модуле работает точно так же, как в листинге 4,4. Строка 1 модуля в листинге 4.6 содержит команду Option Explicit. Из-за этой команды все переменные в модуле должны объявляться оператором Dim. Если добавить неявное объявление переменных в этот модуль, VBA отображает сообщение об ошибке времени исполнения, утверждая, что эта переменная является необъявленной.
Такие команды, как Option Explicit, называются директивами компилятора (compiler directives'). Директивы компилятора не способствуют тому, чтобы VBA выполнял какое-либо действие. Компилятор VBA является частью VBA, которая читает исходный код и компилирует (compiles) его в машинные инструкции, необходимые компьютеру для выполнения поставленной задачи. Директива компилятора просто инструктирует VBA о специфических правилах, которым должен следовать VBA при компиляции вашего исходного кода.
Команда Option Explicit действует только на модуль, в котором она появляется. Если проект, содержащий этот модуль, содержит также другие модули, на них не действует команда Option Explicit. Необходимо включать команду Option Explicit в каждый модуль, для которого требуются явные объявления переменных.
Поскольку включение Option Explicit во все модули является очень полезным, Редактор VB предоставляет способ автоматически включать эту команду в каждый новый модуль при его создании. Для того чтобы Редактор VB добавлял команду Option Explicit в каждый новый модуль, выберите опцию Require Variable Declaration (явное описание переменных) на вкладке Editor (редактор) диалогового окна Options (параметры) Редактора VBA, выполняя следующие шаги:
1. Выберите команду Tools | Options (Сервис | Параметры). Редактор VBA отображает диалоговое окно Options.
2. Щелкните на вкладке Editor (Редактор) для отображения параметров редактирования, если необходимо.
3. Выберите флажок Require Variable Declaration (явное описание переменных).
4. Выберите ОК. Редактор VB закрывает диалоговое окно Options.
Теперь каждый раз, когда вы (или макрорекордер) вставляете новый модуль в проект, Редактор VB автоматически добавляет команду Option Explicit в начало модуля.
Выбор опции Require Variable Declaration в диалоговом окне Options влияет только на новые модули; если вы хотите запросить явное объявление переменных в существующем модуле, вы должны добавить Option Explicit, редактируя модуль самостоятельно. Требование явного объявления переменных действует на все приложения, использующие Редактор VB; при запуске Редактора VB из Excel и установке опции Require Variable Declaration новые модули в Word будут также требовать явного объявления переменных.
»
W
Глава 4
Константы
Константа (constant) — это значение в программе VBA, которое не меняется. Примеры процедур, уже приведенные в этой книге, используют строковые константы типа "Hello World!" и "Другое окно сообщения". Константы, подобные им, называют литеральными константами (literal constants), потому что литеральное значение записывается непосредственно в код.
В коде VBA можно также писать литеральные численные константы и даты; примеры численных литеральных констант включают числа 36, 3, 14 и 212. Примеры литеральных констант-дат включают даты #12/31/96# или #октябрь 28, 1997# (вы узнаете подробнее о написании констант-дат далее в этой главе). Если рассматривать большинство записанных макросов, то можно найти другие примеры литеральных констант. Константы можно изменять только редактированием исходного кода VBA.
Константы, подобные строковым константам в процедуре HelloWorld, используются для предоставления данных, которые не изменяются (в отличие от переменных, которые используются для предоставления изменяемых данных). Можно использовать константы как аргументы для процедур и в математических или операциях сравнения.
Константы не должны быть обязательно литеральными. VBA позволяет создавать именованные константы (named constants). Именованная константа, подобно переменной, имеет заданное ей имя; это имя представляет конкретное неизменяемое значение. Так же, как и в случае с переменной, VBA подставляет конкретное значение, на которое ссылается имя константы, в оператор в том месте, где VBA встречает именованную константу. Однако в отличие от переменной значение именованной константы никогда не изменяется; как и в случае с литеральной константой, единственным способом изменить значение, связанное с именованной константой, является редактирование исходного кода VBA.
Используйте именованные константы для повышения читабельности процедур. Например, процедура, выполняющая геометрические вычисления, легче читается и более понятна, если использовать именованную константу Pi вместо литеральной константы 3,14.
Именованные константы можно также использовать для более простого обновления и сопровождения процедур и программ. Например, в программе VBA, вычисляющей налогообложение фирмы, возможно изменение ставки налога когда-нибудь в будущем. Если поместить ставку налога в эту программу как литеральную константу, может оказаться затруднительным изменить программу, чтобы использовать новую ставку налога, — вам придется искать и изменять каждое вхождение значения ставки налога по всей программе. Если же вместо этого для ставки налога использовать именованную константу, то придется изменить значение ставки налога только в одном месте; в операторе, объявляющем именованную константу.
В общем, следует использовать именованные константы вместо литеральных для значений, которые вы используете неоднократно в процедуре или модуле или для значений, которые трудно запомнить или невозможно сразу понять.
Создание именованных констант
ч
При выборе имени константы соблюдайте те же правила и рекомендации, которым вы следуете при выборе имени переменной (см. раздел «Создание переменных» в начале этой главы). Как и в случае с переменной, необходимо объявлять именованную константу перед ее использованием. Однако в отличие от переменной необходимо всегда явно объявлять именованные константы, используя ключевое слово Const. Следующая строка показывает общий синтаксис для объявления именованных констант:
Типы данных, переменные и константы
111
СИНТАКСИС
Const namel = valuel [operator name2...] _
[, патеЗ = value3 [operator name4] ... ]
Здесь nameN представляет любой допустимый идентификатор, valueN — любое значение данных: численное, строковое или дата, a operator — арифметическая или операция сравнения между двумя именами ранее описанных констант. Следующие строки показывают несколько объявлений именованных констант:
Const Boilingpoint = 212
Const SalesTax = 8.25
Const Greeting = "Hello, Pete!"	,
Const PointTwo = 212, SalesTax2 = 8.25*2, Greeting2 = "Hello, "
Const DangerZone = BoilingPoint + 50
Область действия констант
Как и в случае с переменными, можно объявлять именованные константы в процедурах или в области объявлений в начале модуля. Константа, объявляемая в процедуре, имеет область действия процедурного уровня, а константа, объявляемая в области объявлений модуля, — область действия модульного уровня. Для именованных констант выполняются те же правила области действия, что и для переменных.
Поскольку одной из главных целей использования именованной константы является предотвращение повторения или дублирования значений литеральных констант в процедурах, как правило, бывает необходимо, чтобы именованные константы были доступны всем процедурам в модуле. Поэтому следует помещать объявления констант на модульном уровне, чтобы у них была наибольшая область действия.
Всякий раз, когда VBA встречает именованную константу в операторе, значение, связанное с константой, вставляется в этот оператор. Рассмотрим листинг 4.7, в котором показан законченный модуль. Эта процедура вычисляет площадь круга и сохраняет значение в переменной.
Листинг 4.7. Использование констант: вычисление площади круга
1	Const Pi = 3.14
2	Dim CircleArea As Single
3
4	Sub Calc_CircleArea()
5	Dim Radius	As	Single
6	Radius	= 5
7	CircleArea = Pi * (Radius * Radius)
8	MsgBox	CircleArea,	, "Area of Circle"
9	End Sub
Строка 1 листинга 4.7 объявляет константу модульного уровня Pi, которая представляет приближение числа л. Строка 7 листинга содержит оператор, вычисляющий площадь круга; при выполнении этого оператора VBA вставляет значение 3.14 в место, занимаемое именем константы Pi. В процедуре Calc_CircleArea оператор MsgBox (в строке 8) отображает число 78.5. Обратите внимание на то, что переменная CircleArea объявляется на уровне модуля для того, чтобы значение, вычисленное в процедуре Calc_CircleArea, было доступным для других процедур в том же модуле.
112
Глава 4
Написание литеральных констант
Даже если вы никогда не использовали литеральные константы в коде VBA (что невероятно), вам все же следует писать литеральные константы при объявлении именованных констант. Существует несколько правил, которые необходимо соблюдать при написании литеральных констант; далее описываются правила написания констант типа String, Integer, Date и Boolean.
Константы String
При написании литеральных строковых констант в коде VBA выполняйте следующие правила:
	Строковые константы должны быть заключены в двойные кавычки (”). Следующий пример не является допустимым, потому что не имеет кавычек:
This is not a valid string constant.
	Пустая строковая константа (называемая нулевой строкой — null string или empty string) обозначается двумя двойными кавычками, между которыми ничего нет ("").
	Строковая константа должна вся находиться на одной и той же строке. Нельзя использовать символ продолжения строки для продолжения литеральной строковой константы на другой строке. Ни один из следующих примеров не является правильным, потому что строковая константа находится более, чем на одной строке:
"Это пример
неправильной строковой константы"
"Это снова не_
правильная строковая константа"
Если любой из этих примеров будет включен в процедуру, VBA выдаст ошибку времени исполнения и прекратит выполнение процедуры. Далее следует пример правильной строковой константы:
"Пример правильной строковой константы"
Если же вам необходимо написать константу на двух строках, используйте оператор конкатенации (см. следующую главу) и символ перехода на следующую строку, как показано ниже:
"Теперь имеем " & _
"правильную строковую константу"
Численные константы
Данные правила применимы к литеральным численным константам; численные константы могут содержать любой из численных типов VBA.
	Численные константы должны состоять только из числовых символов от 0 до 9.
	Численная константа может начинаться со знака (-) и может содержать десятичную точку.
	Можно использовать экспоненциальное представление для численных констант.
	Никакие другие символы или знаки не допускаются в численных константах. Далее следуют примеры правильных численных констант:
12
-14.3
6.6Е2
Типы данных, переменные и константы
113
Константы Date
VBA распознает константы даты в любом из нескольких различных форматов; необходимо помещать все константы даты между знаками фунта (#). Следующие строки показывают некоторые из форматов констант дат, которые распознает VBA:
#2-5-97 21:17#
♦February 5, 1997 9:17рщ#
#	Mar-31-97#
#	15 April 1997#
Независимо от того, в каком из указанных форматов записывается литеральная константа типа Date, VBA переформатирует эту константу (когда курсор вставки будет убран со строки после записи константы) для соответствия одному из двух следующих форматов, в зависимости от того, содержит ли константа Date информацию о времени:
#	2/5/97 9:17:00 PM#
#2/5/97#
Если пропустить знак (#) при записи литеральной константы даты, VBA не сможет правильно интерпретировать константу даты как дату. Вместо этого, VBA пытается оценить информацию о дате как имена переменных, численные константы и математические операторы. Например, VBA пытается интерпретировать следующую дату (в которой пропущены знаки фунта) как математическое выражение, включающее деление:
3/12/94
Не заключайте литеральные константы типа Date в кавычки, потому что VBA будет интерпретировать дату как строковую константу. Например, VBA интерпретирует следующую строку как строковую константу, а не как дату:
"3/11/99"
Константы Boolean
Существует только две правильные константы типа Boolean: True и False. В операторах программ VBA для констант типа Boolean вы всегда должны использовать ключевые слова True и False. Когда вы записываете ключевые слова в макросы, пишите слова полностью и не используйте кавычки.
Задание типа константы
Когда вы объявляете именованную константу или используете литеральную константу, VBA «считает», что значение, представленное этой константой, имеет тип данных, наиболее согласующийся с выражением, присвоенным константе. Например, VBA работает с константой, содержащей строку, как с константой типа String при определении того, правильно ли константа сочетается с другими значениями данных.
В VBA можно задать тип константы. Объявление конкретного типа данных для константы может повысить точность вычислений. При объявлении константы типа Double, например, VBA вычисляет результат математических операций, включающих эту константу, используя больший диапазон типа данных Double. Можно также задать тип константы как Integer, Long, Currency или другой, чтобы результаты математических операций, использующих эту константу, имели определенный тип. (Как вы узнаете из следующей главы, VBA определяет тип данных для результата вычислений, основываясь на типе значений, используемых в вычислении.)
Для констант можно использовать типы данных Byte, Boolean, Integer, Long, Single, Double, Currency, Date или String (но не Object или Array). Объявление
114
Глава 4
типа для константы подобно объявлению типа для переменной, за исключением того, что объявление начинается с ключевого слова Const. Общий синтаксис для объявления типизированной константы следующий:
СИНТАКСИС
Const name As type = value [, name As type = value ]
Здесь name — это любое допустимое имя константы, type — имя любого из типов данных VBA и value — значение, которое вы присваиваете константе. Следующая строка иллюстрирует правильное объявление константы с определенным типом:
Const Pi As Double = 3.14
В этом примере константа Pi объявляется как тип Double. Можно также использовать символы определения типа для задания типа константы, как показано в следующем примере (действие которого такое же, как в предыдущем примере):
Const Pi# = 3.14
Внутренние константы
VBA предоставляет несколько внутренних констант (intrinsic constants), называемых также предопределенными константами (predefined constants). Внутренняя константа — это именованная константа, которая была определена разработчиками VBA. В Приложении р приведены все именованные константы VBA. В дополнение к константам, которые предопределяет VBA, host-приложение VBA также предопределяет несколько констант для использования с этим host-приложением. Например, Excel 2002 содержит несколько внутренних констант для использования с рабочими книгами Excel, таблицами и так далее. Аналогично, Word 2002 содержит несколько внутренних констант для работы с документами и шаблонами Word, тогда как Access 2002 содержит внутренние константы, имеющие отношение к различным операциям с базами данных и свойствам Access-объектов.
Внутренние константы, определяемые VBA, все начинаются с букв vb для указания того, что они определяются языком Visual Basic for Applications (или Visual Basic). Например, константы vbOKOnly, vbOKCancel и vbAbortRetrylguore определяются VBA. Внутренние константы Excel 2002 начинаются с букв xl, чтобы было понятно, что они определяются Excel; некоторые из внутренних констант Excel — это xlChart, xlCountrySetting и xlWorksheet. Внутренние константы Word 2002 начинаются с букв wd, чтобы было понятно, что они определяются Word; вот некоторые внутренние константы Word: wdBackward, wdForward и wdToggle.
Благодаря внутренним константам, легче использовать некоторые встроенные процедуры VBA, такие как оператор MsgBox, о котором вы уже знаете, и оператор InputBox, о котором рассказывается далее в этой главе. Хотя ни в одном из показанных уже примеров с оператором MsgBox не использовался его необязательный аргумент, вы можете вспомнить из предыдущих обсуждений, что MsgBox имеет необязательный аргумент, указывающий число кнопок в диалоговом окне; обычно для аргумента кнопок в MsgBox используются внутренние константы VBA.
Внутренние константы, определяемые Excel, Word или другим host-приложением VBA, упрощают использование различных свойств и методов, принадлежащих этому host-приложению. (Подробнее о свойствах и методах вы узнаете из следующих глав.)
Типы данных, переменные и константы
115
Поиск имеющихся внутренних констант с помощью Object Browser
Для того чтобы увидеть полный список имеющихся в наличии внутренних констант, определяемых VBA или host-приложением, используйте Object Browser и выполняйте следующие шаги:
1. Нажмите Alt+Fll для активизации Редактора VB.
2. Выберите команду View | Object Browser (Вид | Просмотр объектов) (или щелкните на кнопке Object Browser на панели инструментов). Редактор VB отображает диалоговое окно Object Browser. На рис. 4.3 показано диалоговое окно Object Browser со списком констант VBA.
После того как вы откроете диалоговое окно Object Browser, выполните следующие дополнительные шаги, чтобы увидеть внутренние константы VBA:
1.	Выберите VBA в раскрывающемся списке диалогового окна Object Browser.
2.	Выберите Constants в списке Classes (Классы).
3.	Чтобы получить более подробную информацию об отдельной внутренней константе, выберите эту константу в списке Members Of'Constants'.
После того как вы выберете константу в списке Members Of 'Constants', ее имя появится в нижней части диалогового окна Object Browser. Чтобы получить более подробную информацию о выбранной константе, щелкните на кнопке Help окна Object Browser (на кнопке со знаком вопроса).
Внутренние константы VBA — одни и те же во всех host-приложениях VBA. Внутренние константы для некоторых приложений, например для Excel, доступны только тогда, когда вы работаете с VBA в этом приложении. Например, вы не сможете найти константу xlWorksheet Excel в окне Object Browser в Word, так как константа xlWorksheet доступна только тогда, когда вы используете VBA в Excel.
Если для элемента, выбранного в списке Classes, имеется раздел справочной системы, кнопка Help окна Object Browser доступна, как показано на рис. 4.3. Щелкните на этой кнопке для доступа к справочному разделу для выбранного элемента. Не все объекты в окне Object Browser имеют дополнительный справочный раздел.
Рис. 4.3
Используйте Object Browser для просмотра списков констант, определенных в VBA и host-приложениях
Object Browser
|<All Llbiaiies»
Members of '«globals»' a ® Abs
ActiveDocument
eS? ActivePnnter
Й? ActiveWindow
e» Addins
Й? AnswerWizard
AppActivate
Й" Application
* Asc v ® AscB
Classes ° <globals> «3 Addin
<3 Addins
<3 Adjustments «3 AnswerWizard «3 AnswerWizardFiles 13 Application
«3 Assistant
<3 AutoCaption aS AutoCaptions
<AII Libraries»
Для просмотра списка внутренних констант, определяемых host-приложени-ем VBA, выполняйте те же шаги, что описаны выше, но вместо VBA выбирайте библиотеку host-приложения в раскрывающемся списке Project/Library (Проект/ Библиотека). Например, чтобы просмотреть внутренние константы Excel, выберите Excel в раскрывающемся списке Project/Library; чтобы просмотреть внутренние константы Word, выберите Word в списке Project/Library. Можно просматривать
116
Глава 4
внутренние константы только для host-приложения VBA, из которого был запущен Редактор VB, если только вы не создаете ссылку на библиотеку другого host-приложения.
f
Получение данных от пользователя
Информация этого раздела не связана с основной темой главы, но необходима для оставшегося материала этой и следующей главы.
Получение данных от пользователя, сохранение их в переменной и отображение результатов действий, выполненных над ними, являются основными элементами, необходимыми для написания интерактивных процедур. [Интерактивная (interactive) процедура — это процедура, обменивающаяся информацией с пользователем, то есть процедура взаимодействует с пользователем, отображая сообщения и получая ввод]. Интерактивные процедуры часто бывают более полезными, чем макросы, создаваемые исключительно путем записи. Получая информацию от пользователя, интерактивная процедура может выполнять одни и те же операции, используя различные данные.
Данные, вводимые пользователем, называются входными данными (input). Чтобы получить входные данные от пользователя процедуры, используйте функцию InputBox. [Функция (function) — это особый тип процедуры VBA, возвращающей значение]. Функция InputBox отображает диалоговое окно, содержащее текст, который запрашивает пользователя ввести некоторое значение, и текстовое окно для ввода этого значения. Диалоговое окно, отображаемое InputBox, содержит также командные кнопки ОК и Cancel.
Функция InputBox имеет следующий синтаксис:
СИНТАКСИС
stringvar = InputBox (Prompt [, Title])
Здесь stringvar представляет любую переменную, которая может сохранять строку (либо переменную типа String, либо — Variant). Аргумент Prompt представляет любое строковое значение (литерал, константу или переменную). InputBox отображает эту строку как запрос в диалоговом окне; необходимо всегда предоставлять аргумент Prompt, поскольку это — обязательный аргумент (required argument).
Аргумент Title является необязательным вторым аргументом для InputBox. Title представляет любое строковое значение (литерал, константу или переменную). InputBox отображает текст этой строки в строке заголовка диалогового окна. Если опустить аргумент Title, VBA отображает в строке заголовка диалогового окна InputBox слово "Input".
В листинге 4.8 приведен код модуля с одной процедурой. В коде имеется объявление константы и переменной модульного уровня. Эта процедура, подобно процедуре в листинге 4.7, вычисляет площадь круга, но радиус круга получает от пользователя процедуры.
Листинг 4.8. Получение входных данных при помощи оператора InputBox
1	Const Pi As Single =3.14	' аппроксимация значения pi
2	Dim CircleArea As Single ' сохраняет вычисленную площадь круга 3
4	Sub Calc__CircleArea ()
5	Const BoxTitle = "Площадь круга"
6	Dim Radius As Single, Temp As String
Типы данных, переменные и константы
117
7	Temp = InputBox("Введите радиус круга", BoxTitle)
8	Radius = CSng(Temp)
9	CircleArea = Pi * (Radius * Radius)
10	MsgBox CircleArea, , BoxTitle
11	End Sub
Строка 1 листинга 4.8 объявляет константу модульного уровня Pi. Строка 2 объявляет переменную модульного уровня CircleArea. Эти элементы объявляются на уровне модуля, чтобы они были доступны во всем модуле; другим процедурам в том же модуле может понадобиться доступ к значению Pi, а еще какой-то процедуре может понадобиться использовать значение для площади круга, после того, как оно будет вычислено.
Строка 4 содержит фактическое объявление процедуры; как и раньше, эта процедура имеет имя Calc_CircleArea. Строка 5 объявляет константу процедурного уровня BoxTitle; эта константа имеет только локальный доступ в процедуре Calc_CircleArea. BoxTitle была объявлена локально в этой процедуре, потому что маловероятно использование этой константы в какой-либо другой процедуре; ее назначение — предоставлять фиксированный текст для строки заголовка всех диалоговых окон, отображаемых Calc_CircleArea.
Обратите внимание на строку 7 листинга 4.8. Этот оператор вызывает функцию InputBox. Она отображает свой первый аргумент как текст в диалоговом окне, запрашивая у пользователя ввести значения какого-либо типа. В этом операторе InputBox отображает текст "Введите радиус круга", чтобы сообщить пользователям процедуры, какое значение они должны ввести. InputBox использует второй аргумент, представленный константой BoxTitle, в качестве заголовка диалогового окна. При выполнении оператора InputBox отображается диалоговое окно, показанное на рис. 4.4. Пользователь вводит число в текстовое окно и выбирает командную кнопку ОК или Cancel, чтобы закрыть диалоговое окно, как и любое другое окно Windows.
Всякий раз, когда вы вызываете какую-либо функцию, необходимо как-то использовать значение, возвращаемое функцией. [Значение, возвращаемое функцией, называется результатом функции (function result)]. Часто функции используют результат, присваивая его какой-либо переменной, как показано в строке 7 в случае с функцией InputBox, результат которой присваивается переменной Тетр.
Результат функции InputBox всегда является строкой (вот почему переменная Тетр была объявлена как String). Посмотрите еще раз на рис. 4.4. Если пользователь выбирает командную кнопку ОК, функция InputBox возвращает то, что пользователь ввел в текстовое окно, в качестве результата. Если пользователь выбирает командную кнопку Cancel (или нажимает клавишу Esc, или использует кнопку Close диалогового окна), InputBox в качестве результата возвращает пустую строку.
Рис. 4.4
Диалоговое окно ввода, отображаемое функцией InputBox (в строке 7 листинга 4.8)
Поскольку переменная Тетр была объявлена явно как String, значение строки должно быть преобразовано в численное значение перед тем, как можно будет его использовать в математических вычислениях. Строка 8 листинга 4.8 выполняет именно это, используя встроенную VBA-функцию CSng для преобразования пользовательских данных ввода в число с типом Single. CSng — это одна из нескольких функций преобразования данных, более подробно описанных в главе 5.
Глава 5
Выражения в Visual Basic
Теперь вы знаете, как записывать и редактировать макросы, писать собственные простые процедуры и создавать и использовать константы и переменные. В этой главе описывается, как объединять переменные и константы для создания новых значений.
Выражение (expression) — это значение или группа значений, выражающая отдельное значение. Каждое выражение вычисляется до (или имеет результатом) отдельного значения. Выражение 2+5, например, имеет результатом 7. Выражения состоят из одной или более следующих частей:
	Константы (литеральные или именованные)
	Переменные (любого типа данных)	'
	Знаки операций
	Массивы
	Элементы массива
	Функции
Все выражения имеют результатом одно значение определенного типа данных, о которых вы узнали в главе 4. Выражения могут также иметь результатом одно из специальных значений Empty или Null. VBA предоставляет ключевые слова Empty и Null для указания особых значений в переменной или выражении. Значение Empty представляет неинициализированную переменную типа Variant или результат выражения, содержащий неинициализированную переменную типа Variant. Значение Null представляет выражение, содержащее неверные данные.
Вот некоторые примеры выражений:
Выражение	Описание
7	Содержит одно значение и имеет результатом число 7.
"25"	Содержит одно значение и имеет результатом символьную строку ”25".
"То" & "day”	Содержит два строковых значения и знак операции; имеет результатом одну строку "Today”.
b /(р*10)	Возвращает число, полученное делением содержимого переменной b на значение, полученное после умножения содержимого переменной р на константу 10.
Value <= 17	Вычисляется до логического значения; в этом случае указывая, является ли содержимое переменной Value меньшим или равным константному численному значению 17.
Знаки (обозначения) операций1 используются для объединения, сравнения или других действий над определенными значениями в выражении. Операциям присвоены имена, и они могут иметь обозначающий их знак, например, операция
1 В некоторых источниках вместо «знака операции» используется термин «оператор» (operator). Автор считает это не совсем удобным, поскольку в программировании чаще всего под «оператором» понимают инструкцию (statement), выполняющую некоторую работу, например, оператор присваивания. В данном же случае мы имеем дело с элементами, из которых формируется выражение, обычно являющееся частью оператора, например, присваивания.
Выражения в Visual Basic
119
сложения имеет знак Когда вы используете какой-либо знак в выражении, элементы данных (переменные или константы), над которыми производится действие, называются операндами (operands); большинству операций требуется два операнда. В выражении 3+1, например, числа 3 и 1 являются операндами операции сложения (+). Выражение может содержать один, несколько знаков операции или ни одного.
Выражения используются для выполнения вычислений и сравнения значений, для предоставления переменных в качестве аргументов различным функциям и процедурам VBA. Все выражения Visual Basic вычисляются до значения, имеющего один из типов данных Visual Basic. Далее следует перечень различных типов выражений VBA:
	Выражение типа даты (date expression) — это любое выражение, которое вычисляется до значения типа Date. Выражения Date могут включать константы типа Date, переменные, содержащие даты или числа, численные константы, даты, возвращаемые функциями, и знаки арифметических операций.
	Численное выражение (numeric expression) — это любое выражение, которое вычисляется до числа любого типа — Byte, Integer, Long, Single, Double или Currency. Численные выражения могут включать переменные, хранящие числа, численные константы, функции, возвращающие числа, и знаки арифметических операций. Численные выражения могут также включать строковые выражения, которые VBA преобразует в число. (Если все символы в строке являются цифрами, то VBA может преобразовать эту строку в численное значение; например, строку "436" в число 436.)
	Строковое выражение (string expression) — это любое выражение, которое имеет результатом значение типа String. Строковые выражения могут включать переменные, которые хранят строки, строковые константы, функции, возвращающие строки, или знаки (обозначения) операций конкатенации строк. Строковые выражения могут также включать численные выражения, которые VBA может преобразовать в строку.
	Логическое выражение (logical expression) — это любое выражение, которое вычисляется до значения типа Boolean: True или False. Логические выражения могут состоять из переменных, содержащих значения Boolean, констант Boolean, функций, возвращающих значения типа Boolean, знаков операций сравнения или логических операций.
	Объектное выражение (object expression) — это любое выражение, которое имеет результатом ссылку на объект.
Совместимость типов данных
Не все типы данных совместимы друг с другом, и нельзя использовать несовместимые типы данных в одном и том же выражении. Например, не имеет смысла арифметическое сложение строки с числом, так как такое выражение не является значащим и VBA не может его оценить.
Многие типы данных совместимы друг с другом. Например, вы можете объединять различные численные типы данных в одном и том же выражении; VBA автоматически выполняет необходимые преобразования типа различных численных типов. VBA может также иногда автоматически преобразовывать другие типы данных так, чтобы все типы в выражении были совместимы, хотя это не всегда возможно. Например, типы String и Date совместимы с численными типами только при особых условиях, которые будут описаны далее.
Очень важно контролировать и знать тип выражения, потому что если выражения содержат несовместимые типы, VBA выдает ошибку времени исполне
120
Глава 5
ния — ошибку несовпадения типов (type-mismatch). При обработке выражения, содержащего различные типы данных VBA сначала «пытается» устранить любое различие типов, преобразуя значения в выражении в совместимые типы данных. Если устранить какие-либо различия преобразованием типов не удается, отображается ошибка времени исполнения и процедура прекращает выполняться.
Если вы присваиваете результат какого-либо выражения переменной, а тип переменной несовместим с типом результата этого выражения, VBA также отображает ошибку несовпадения типов. Аналогично, использование такого результата выражения в качестве аргумента для функции или процедуры также приводит к ошибке несовпадения типов, если тип данных аргументов и тип результата выражения являются несовместимыми.
VBA предоставляет различные функции для преобразования информации одного типа в другой, например, строк в числа, чисел в строки и так далее (в предыдущей главе встречалась функция CSng, используемая для преобразования типа String в численный Single). Функции преобразования данных VBA описываются более подробно в главе 6.
Автоматическое преобразование данных Visual Basic
VBA использует различные правила для автоматического преобразования данных в совместимые типы и выбирает правила преобразования данных применительно к определенному выражению на основе конкретных типов и операторов, используемых в выражении.
VBA выполняет автоматическое преобразование типов быстрее, если выражение содержит переменные типа Variant, потому что тип данных Variant не является фиксированным. Если выражение содержит литеральные константы, типизированные переменные или типизированные константы, VBA применяет более определенные правила преобразования типов, потому что тип данных этих элементов является фиксированным. (Помните, типизированная переменная или типизированная константа — это переменная или константа, для которой вы явно объявили тип данных либо с помощью ключевого слова As, либо символа определения типа, как было описано в предыдущей главе.)
Следующие выражения иллюстрируют, как от типов данных и оператора зависят преобразования, выполняемые VBA:
Выражение	Описание и тип результата
Num + Str	Создает ошибку несовпадения типов, когда Num объявляется как численный тип, a Str — как тип String. Выполняется строковая конкатенация, когда Num является Variant, a Str объявляется как тип String; результат является типом String.
Num + Str	Выполняется арифметическое сложение, когда Num объявляется как численный тип, a Str — как Variant, или когда и Num, и Str являются типом Variant; результат — численный тип.
Num + "3"	Вызывает ошибку несовпадения типов, если Num объявлен численным типом. Выполняется строковая конкатенация, если Num является типом Variant; результат имеет тип String.
3 + Str	Вызывает ошибку несовпадения типов, если Str объявлен как тип String. Выполняется арифметическое сложение, если Str является Типом Variant; результат является численным типом. (Заметьте, что это выражение никогда не имеет результатом строковую конкатенацию.)
Выражения в Visual Basic
121
Выражение	Описание и тип результата
Num & Str	Всегда выполняет строковую конкатенацию, независимо от типов переменных; результатом является тип String. Это выражение никогда не вызывает ошибки несовпадения типов.
Обратите особое внимание'на последнее выражение. В нем используется оператор строковой конкатенации (&), который соединяет («склеивает») вместе две строки. Поскольку можно использовать этот оператор только со строками, VBA преобразует типы данных в этом выражении в строки, независимо от их оригинального типа данных и независимо от того, имеют ли какие-либо переменные в выражении определенный тип. По мере описания отдельных операторов в дальнейших разделах этой главы описываются также особые правила преобразования данных, которые VBA применяет для каждого отдельного оператора.
Вы, наверное, уже заметили, что большинство из указанных выше выражений вызывают ошибку несовпадения типов только тогда, когда оба операнда в выражении имеют определенные и разные типы. Вы можете также заметить, что выражения не вызывают ошибку несовпадения типов, когда один из операндов является переменной типа Variant. Как было упомянуто выше, VBA легче всего выполняет автоматические преобразования типов с данными типа Variant. Не следует, однако, использовать типы Variant только для того, чтобы избежать ошибок несовпадения типов, поскольку игнорирование возможности использования встроенных типов может привести к другим ошибкам.
Преобразования численных типов
VBA обычно преобразует все численные типы данных в выражении в тип наибольшей точности, а затем дает этот тип результату выражения. Например, если выражение содержит численные значения с типами Integer и Single, результат выражения является типом Single — тип наибольшей точности в этом выражении.
Если вы присваиваете результат численного выражения переменной с наименьшей точностью, чем фактический тип результата выражения, VBA округляет результат выражения до тех пор, пока его точность не совпадет с ожидаемым типом. Например, если вы присваиваете численное выражение, имеющее результатом число типа Double, переменной типа Integer, VBA округляет число двойной точности до типа Integer.
Преобразования строк и чисел
При преобразовании числа в строку VBA создает строку, содержащую все цифры этого числа и десятичный знак (если число имеет его). Число 3413.721, например, преобразуется в строку "3413,72". Если число очень большое или очень маленькое, VBA может создать строковое представление числа в экспоненциальной записи; например, число 0.0000000004927 преобразуется в строку "4,927Е-11".
VBA может преобразовывать строку в число, если только эта строка содержит символьное представление числа в десятичном формате или экспоненциальном. Строки "988,6", "812", "-186,7”, ”1,ЗЕ10" представляют числа, и VBA может преобразовать их в числа. Строки "1.045", ”$74.550" и "С добрым утром!" не могут быть преобразованы в числа.
1 Точка используется для записи числа в коде.
122
Глава 5
Преобразования значений типа Boolean
Когда VBA преобразует значения типа Boolean в числа, значение True преобразуется в 1, а значение False — в 0. Когда VBA преобразует число в тип Boolean, нуль преобразуется в False, а любое другое значение преобразуется в True. Когда VBA преобразует значения типа Boolean в строки, VBA использует строку "True" для True и "False" — для False. VBA не может преобразовывать строковые выражения в тип Boolean, но может преобразовывать численные выражения в значения этого типа. Когда вы используете значения типа Boolean в арифметических выражениях, VBA всегда преобразует их в числа, даже если все другие части этого выражения также являются переменными или константами типа Boolean.
Преобразования значений типа Date
Когда VBA преобразует тип данных Date в число, результатом является численное значение — число типа Double, которое содержит количество дней от 30 декабря 1899 (отрицательное число представляет дату, более раннюю, чем 12/30/1899). Десятичная часть числа (если имеется) выражает время дня как часть дня; 0 — это полночь, а 0.5 — это полдень. В VBA преобразование численных типов данных в типы Date является просто обратным преобразованию типа Date в число.
Если выражение имеет результатом значение, находящееся вне диапазона типа данных для этого выражения, VBA отображает сообщение об ошибке переполнения. Если выражение содержит литеральную константу, иногда можно решить эту проблему, используя символ определения типа с литеральной константой, чтобы выражение имело результатом численный тип с большим диапазоном значений.
Оператор присваивания (=)
В предыдущей главе вы кратко познакомились с оператором {statement) присваивания (=). Этот оператор используется для присваивания результата выражения переменной. Оператор присваивания сохраняет любое значение, которое представлено выражением справа от оператора присваивания (=), в ячейке памяти, на которую ссылается переменная слева от оператора.
Оператор присваивания имеет две синтаксические формы, обе из которых являются одинаково приемлемыми и выполняют одну и ту же задачу. Первая форма оператора присваивания использует ключевое слово Let и имеет следующий общий синтаксис:
СИНТАКСИС
Let varname = expression
Переменная varname представляет любую переменную VBA, a expression — любое выражение VBA. Этот синтаксис является оригинальной формой оператора присваивания, использовавшейся в ранних версиях языка программирования Basic. Следующий оператор VBA является примером оператора присваивания Let:
Let х = у ' присваивает переменной х значение, представленное . ' переменной у
Вторая форма оператора присваивания более употребительна в программировании на VBA и широко используется в этой книге. Общий синтаксис этой формы оператора присваивания следующий:
varname = expression
Выражения в Visual Basic
123
Переменная varname — любая переменная, a expression — любое выражение. Далее следуют примеры этого более простого, более употребительного оператора присваивания (первая строка присваивает содержимое Y переменной X; вторая строка присваивает переменной SecondVar результат сложения 102 с содержимым FirstVar):
X = Y SecondVar = 102 + FirstVar
При выполнении оператора присваивания VBA сначала вычисляет выражение справа от оператора присваивания (=), а затем сохраняет результат выражения в переменной, имя которой находится слева от оператора присваивания. Новичкам в вопросах программирования бывают не сразу понятны операторы, подобные следующим:
Номер = Номер + 1
ОбщаяСумма = ОбщаяСумма + ПодСумма
Особенность этих операторов в том, что и слева, и справа от знака оператора появляется один и тот же идентификатор переменной. Чтобы понять, каким должен быть результат подобных инструкций, следует еще раз внимательно прочитать синтаксис оператора присваивания. Тогда станет ясно, что сначала в некоторую промежуточную ячейку памяти помещается результат вычисления (оценивания) выражения справа от оператора (для первого примера это — Номер + 1, для второго — ОбщаяСумма + ПодСумма), а затем этот результат помещается в ячейку памяти, соответствующую переменной, идентификатор которой находится слева от оператора "=".
Более короткая форма оператора присваивания используется гораздо чаще, чем длинная, в основном потому, что короткая быстрее вводится с клавиатуры. Длинная форма оператора присваивания с ключевым словом Let часто рекомендуется для начинающих программистов, поскольку помогает отличать оператор присваивания от операции сравнения (равенства)-
Хотя эти две конструкции используют один и тот же символ, не путайте оператор присваивания со знаком равенства (=), используемым для тестирования на равенство. Следующие два выражения приводят к совершенно разным результатам: первый — является оператом и присваивает значение 5 переменной First Vai; второй — является логическим выражением, которое имеет результатом True или False, в зависимости от того, содержит ли уже First Vai число 5:
FirstVal = 5	' присваивает число 5 переменной FirstVal
(FirstVal =5)	' сравнивает содержимое FirstVal с числом 5
Заметьте, что вторая строка, фактически, не является законченным оператором VBA (хотя является законченным выражением), поскольку результат логического выражения никаким образом не используется; подобная строка в ваших процедурах может вызвать ошибку синтаксиса. Чтобы получить синтаксически верный оператор VBA, необходимо каким-то образом использовать результат этого выражения: присвоить его переменной, передать его в качестве аргумента функции или процедуре.
Когда вы присваиваете результат выражения переменной с определенным типом данных, этот результат может иметь тип данных, совместимый с типом переменной, получающей новое значение. Во многих случаях, VBA может преобразовывать тип данных результата выражения в тип, совместимый с типом переменной, принимающей новое значение, если результат выражения и переменная еще не имеют совместимых типов. Переменным типа Variant может быть присвоен любой тип данных.
124
Глава 5
Запомните следующее:	-	.	.	>.
	Можно присваивать любую численную переменную или выражение любой другой переменной численного типа или переменной типа Variant. Если присваивается численное выражение типизированной переменной с меньшей точностью или диапазоном (как при присваивании типа Double типу Long), VBA округляет значение выражения для совпадения с точностью переменной, принимающей новое значение.
	Если переменной типа String присваивается переменная типа Variant, содержащая число, VBA автоматически преобразует это число в строку. (При присваивании типизированных численных переменных или численных констант переменной типа String происходит ошибка несовпадения типов.)
Арифметические операции
VBA может выполнять все обычные арифметические операции (реализуемые посредством арифметических выражений): сложение, вычитание, умножение и деление, а также возведение чисел в указанную степень и предоставляет дополнительные особые математические операции для целочисленного деления и деления по модулю. В табл. 5.1 приводятся знаки операций, которые можно использовать при написании арифметических VBA-выражений. (В этой таблице Ni — это любое допустимое численное выражение VBA.)
Таблица 5.1. Знаки операций (обозначения), используемые в арифметических VBA-выражениях
Знак	Синтаксис	Имя/Описание
+	Nl + N2	Сложение. Прибавляет N1 к N2.
-	Nl - N2	Вычитание. Вычитает N2 из N1.
*	Nl * N2	Умножение. Умножает N1 на N2.
/	Nl/ N2	Деление. Делит N1 на N2.
\	Nl\ N2	Целочисленное деление. Делит N1 на N2, отбрасывая любую дробную часть так, чтобы результат был целым числом.
Mod	Nl Mod N2	Деление по модулю. Делит N1 на N2, возвращая только остаток операции деления.
	Nl Л N2	Возведение в степень. Возводит N1 в степень N2.
Далее описывается подробно использование каждого знака.
Сложение (+)
Знак операции сложения (+) используется для выполнения операции простого сложения. Оба операнда должны быть численными выражениями или строками, которые VBA может преобразовать в число. Знак операции сложения можно также использовать для построения арифметических выражений с данными типа Date.
Для большего понимания следующего материала войдите в редактор VBA (выберите Сервис | Макрос | Редактор Visual Basic). Далее щелкните на кнопке View Code в Project Window. В появившемся Code Window набирайте предлагаемые далее небольшие программы и, если вам этого будет не достаточно, можете проводить свои собственные эксперименты с кодом.
Выражения в Visual Basic
125
Введите в Code Window код листинга 5.1.
Листинг 5.1. Пример использования знака операции "+"
1	Sub list5_01()
2	' Примеры арифметических выражений со знаком "+"
3	Dim Nl, N2, N3 As*Integer 4
5	Nl	=	1	'	присваивание значения	переменной	N1
6	N2	=	2	'	присваивание значения	переменной	N2
7	N3	=	Nl	+	N2	'	сложение; результат —	в N3
8	MsgBox	(N3)	'	Вывод N3 в диалоговом	окне
9
10	End Sub
Видимо, здесь нечего объяснять. Понятно, что при запуске этого кода (Run | Run Sub/UserForm) на экране появится диалоговое окно с числом 3.
Тип данных результата выражения сложения обычно тот же, что и наиболее точный тип в этом выражении. Например, если выражение содержит оба типа Integer и Long, результатом такого выражения будет тип Long. Однако существуют некоторые исключения, в частности, если выражение включает переменные типа Variant. Далее перечисляются эти исключения:
1.	Результатом сложения типа Single и Long является Double.
2.	Если складывать тип Date с любым другим типом данных, результатом выражения всегда будет тип Date.
3.	Если результат выражения сложения присваивается переменной Variant, имеющей в данный момент тип Integer, и если результат выражения больше, чем (переполняет) диапазон значений для типа Integer, то VBA преобразует результат в Long. После присваивания переменная Variant также имеет тип Long.
4.	Если результат выражения сложения присваивается переменной Variant, имеющей в данный момент тип Long, Single или Date, и если результат выражения переполняет диапазон численного типа, VBA преобразует результат в Double. После присваивания переменная типа Variant также имеет тип данных Double.
5.	Если любой операнд в выражении сложения является равным Null или вычисляется до Null, то результатом выражения сложения также будет Null. (Null — это особое значение, которое можно присваивать только переменным типа Variant для обозначения того, что они не содержат действительных данных.)
Порядок точности для численных типов данных VBA от наименее точного до наибо-ZffOu лее точного следующий: Byte, Integer, Long, Single, Double, Currency.
В листинге 5.2 содержится код, демонстрирующий правила преобразования выражений со знаком ”+", приведенные в последнем перечне.
Листинг 5.2. Преобразования типов в выражениях со знаком "+"
1	Sub list5_02()
2	' Примеры арифметических выражений со знаком "+" 3
4	Dim	SI	As	Single
5	Dim	LI	As	Long
6	Dim	II	As	Integer
126
Глава 5
7	Dim DI As Date
8	Dim VI, V2 As Variant
9 10	’ инициализация переменных
11	si = з.ззз
12	Ll = 3.333
13	Il = 1111
14	DI = Now ' получить значение текущей даты'и времени
15 16	MsgBox TypeName(SI + Ll) , vbOKOnly, "Single + Long"
17	MsgBox TypeName(DI + Ll), vbOKOnly, "Date + Long"
18 19	VI = Il	' переменная типа Variant становится типа Integer
20	MsgBox TypeName(VI), vbOKOnly, "V1=I1"
21 22	VI = VI + 99999 ' переменная типа Variant становится типа Long
23	MsgBox TypeName(VI), vbOKOnly, "VI + 99999”
24 25	VI = Dl ' переменная типа Variant становится Date
26	VI = VI + 99999999 ' переменная типа Variant становится Double
27	MsgBox TypeName(Vl), vbOKOnly, "VI = Dl; VI = VI + 99999999"
28 29	VI = Null + 1	' переменная типа Variant становится Null
30	MsgBox TypeName(VI) , vbOKOnly, "VI = Null + 1"
31 32	Ena Sub
На рис. 5.1 приведен ряд диалоговых окон, которые отображаются на экране во время выполнения кода листинга 5.2.
Заметим, что довольно часто начинающие программировать не уделяют этим вопросам должного внимания; это иногда приводит к непонятным для них результатам.
Рис. 5.1
Диалоговые окна, отображаемые при выполнении кода листинга 5 2
Вычитание (-)
Знак операции вычитания (-) выполняет две задачи. Он используется либо для построения арифметических выражений вычитания, либо для обозначения унарного минуса.
Унарный минус {unary minus) — это знак минус, который помещают перед числом для указания того, что это — отрицательное число. Знак минус можно также помещать перед переменной или другим выражением для обозначения того, что значение переменной или выражения должно быть отрицательным. Поместить унарный минус перед переменной или выражением означает то же, что умножить это число на —1. Следующие выражения содержат унарный минус:
Выражения в Visual Basic
127
-10	литеральная отрицательная константа
-MyVar	делает отрицательным любое число, сохраненное в MyVar
-(MyVar +10)	делает отрицательным результат сложения 10 и MyVar
Следующие несколько выражений показывают примеры использования знака вычитания для построения арифметических выражений:
Now - 60	результат выражения имеет тип Date
40 - MyVar	разность между 40 и MyVar
AnyVar - SomeVar	разность между AnyVar и SomeVar
Оба операнда в выражении вычитания должны быть численными переменными или выражениями, или строковым выражением, которое VBA может преобразовать в число. Знак операции вычитания можно также использовать для построения арифметических выражений с данными типа Date. Тип данных результата выражения вычитания обычно является тем же, что и наиболее точный тип данных в этом выражении.
VBA следует тем же правилам для определения типа данных результата выражения вычитания, что и для выражений, использующих знак операции сложения, но имеются следующие дополнительные правила:
	Если один из операндов в выражении вычитания является типом Date, то результат выражения имеет тип Date.
	Если оба операнда в выражении являются типом Date, то результат выражения имеет тип Double.
В листинге 5.3 приведен код, демонстрирующий эти дополнительные правила.
Листинг 5.3. Дополнительные правила преобразования типов в выражениях со знаком операции "
1	Sub list5_03()
2	' Примеры арифметических выражений со знаком
3	Dun DI, D2 As Date
4
5	DI = Now	' получить значение текущей даты и времени
6	D2 = Now - 5
7
8	gg = MsgBox(TypeName(D2), vbOKOnly, "Now - 5")
9	gg = MsgBox(TypeName(DI - D2), vbOKOnly, "DI - D2")
10
11	End Sub
На рис. 5.2 приведены диалоговые окна, которые отображаются на экране во время выполнения кода листинга 5.3.
Рис. 5.2
Диалоговые окна, отображаемые при выполнении кода листинга 5.3
128
Глава 5
i—S Несмотря на то, что можно конкатенировать (объединять) две строки вместе с по-мощью знака (+), нельзя использовать знак (-), чтобы отделить какую-либо стро-ку. Вместо этого для отделения строк можно использовать VBA-функции Mid, Left или Right. Эти функции описываются в следующей главе.
Умножение (*)
Знак операции умножения (*) используется для построения арифметических выражений с умножением; результатом выражения умножения является произведение двух операндов. Оба операнда в выражении умножения должны быть численными выражениями или строками, которые VBA может преобразовать в число. Следующие примеры иллюстрируют правильный синтаксис для арифметических выражений с умножением:
4 * 10	'	умножение	4	на 10; результат равен 40
NumVar *	2	'	результат	—	произведение NumVar и 2
NumVar *	OtherVar	'	результат	—	произведение NumVar и OtherVar
Тип данных результата выражения умножения обычно тот же, что и наиболее точный тип в этом выражении. VBA следует тем же правилам для определения типа данных результата выражения умножения, что и для выражений, использующих сложение. В выражениях умножения все переменные Variant, которые содержат значения типа Date, преобразуются в численные значения.
Деление (/)
Знак операции деления (/) иногда называют знаком деления чисел с плавающей точкой или действительных чисел, чтобы отличать от знака целочисленного деления, который описан в следующем разделе. В выражениях деления первый операнд делится на второй операнд; результатом деления является частное. Оба операнда в выражении деления с плавающей точкой должны быть численными выражениями или строками, которые VBA может преобразовать в числа. Следующие выражения иллюстрируют использование знака операции деления:
27/3	' деление 27 на 3
MyNumVar / 20	1 деление значения в переменной MyNumVar на 20
MyNumVar / MyOtherVar ' делит значение в переменной MyNumVar
' на значение в переменной MyOtherVar
Если любой операнд в выражении деления имеет значение Null, то результатом выражения также является Null. Тип данных выражения со знаком деления с плавающей точкой — обычно Double, но имеется следующее исключение:
 Если оба операнда в выражении деления имеют тип Integer или Single, то результат выражения деления с плавающей точкой имеет тип Single, если только результат выражения не переполняет диапазон значений для типа Single. Если результат переполняет диапазон для типа Single, то VBA преобразует результат в тип Double.
Деление любого числа на нуль приводит к ошибке времени исполнения. Правила математики утверждают, что деление числа на нуль невозможно. Из-за этого мате-J магического правила VBA всегда генерирует ошибку времени исполнения, когда встречает выражение, у которого делитель равен нулю. Понятно, что трудно представить себе программу, в которой в качестве делителя будет выступать литеральный нуль. Обычно деление на нуль возникает в результате того, что за несколько шагов до выполнения деления переменная-делитель «неожиданно» для программиста становится равной нулю. Если вы не уверены в «адекватности поведения» делителей в вашем коде, вставляйте операторы тестирования этих делителей на равенство нулю перед выполнением деления. После самого полного тестирования кода эти операторы можно будет либо убрать совсем, либо закомментировать до следующей модификации программы.
Выражения в Visual Basic
129
Целочисленное деление (\)
Целочисленное деление подобно делению с плавающей точкой, кроме того, что выражения, использующие оператор целочисленного деления (\), всегда имеют результатом целое число без дробной части. Оба операнда в выражении целочисленного деления должны быть численными выражениями или строками, которые VBA может преобразовать в числа. Следующие примеры выражений иллюстрируют правильный синтаксис для целочисленного деления:
4 \ 3	' деление 4 на 3; возвращает значение 1
9 \ NumVar	' деление 9 на содержимое NumVal
MyVar \ NumVar ' деление MyVar на NumVar
В целочисленном делении VBA округляет каждый операнд (если необходимо) до числа типа Integer или Long перед выполнением операции деления.
VBA отбрасывает любой дробный остаток результата выражения целочисленного деления. Например, выражение деления с плавающей точкой 19/5 имеет результатом 3.8, в то время как выражение целочисленного деления 18 \ 5 имеет результатом 3. Заметьте, что VBA не округляет частное целочисленного деления, результат просто укорачивается до целого числа.
Тип данных результата выражения целочисленного деления — либо Integer, либо Long; VBA использует наименьший тип данных, который соответствует результату выражения. Если какой-либо операнд в выражении целочисленного деления является равным Null, то результатом выражения также будет Null.
Деление по модулю (Mod)
Деление по модулю дополняет целочисленное деление. При делении по модулю выражение возвращает только остаток операции деления как целое. Оба операнда в выражении деления по модулю должны быть численными выражениями или строками, которые можно преобразовать в число. Следующие примеры выражений иллюстрируют деление по модулю:
8 Mod 2	' возвращает значение О
5.1 Mod 3	' возвращает значение 2
6 Mod NumVar ' если NumVar содержит 3, возвращает О
При делении по модулю VBA округляет каждый операнд (если необходимо) до числа типа Integer или Long перед выполнением деления так же, как при целочисленном делении. Тип данных результата выражения деления по модулю — это Integer или Long. VBA использует наименьший тип, который подходит для результата выражения. Если какой-либо операнд в выражении деления по модулю является Null, то результатом выражения также будет Null.
Возведение в степень (л)
Знак операции возведения в степень (") используется в арифметических выражениях для возведения в степень числа или выражения. Показатель степени указывает, сколько раз число (или выражение) должно быть умножено на самое себя: З3 — это то же, что и 3 х 3 х 3. Чтобы записать З3 как арифметическое выражение VBA, используйте следующее:
3 Л 3
Оба операнда в выражении возведения в степень должны быть численными выражениями или строками, которые VBA может преобразовать в числа. Операнд слева от знака возведения в степень может быть отрицательным числом, только если операнд справа является целым. Если какой-либо операнд является равным Null, то результатом выражения возведения в степень также будет Null; иначе результат выражения будет иметь тип Double.
5 Программирование на VBA 2002
130
Глава 5
Операции сравнения
Операции сравнения иногда также называют операциями отношения (relational operators). Чаще всего операции сравнения используются для того, чтобы задать критерии для принятия решения или сформулировать описание условий, при которых группа команд должна быть повторена (организация циклов).
Результатом любой операции сравнения является значение типа Boolean: True или False. Операции сравнения используются для сравнения литеральных, константных или переменных значений любого сходного типа.
В табл. 5.2 перечислены имеющиеся в VBA знаки операций сравнения и описано их назначение (Е в этой таблице представляет любое действительное выражение VBA).
Таблица 5.2. Знаки (обозначения) операций сравнения
Операция/ Оператор	Синтаксис	Наименование/описание
=	El = Е2	Равенство. True, если El равно E2, иначе — False.
<	El < Е2	Меньше, чем. True, если El меньше, чем Е2, иначе — False.
<=	<=	Меньше, чем или равно. True, если Е1 меньше или равно Е2, иначе — False.
>	>	Больше, чем. True, если Е1 больше, чем Е2, иначе — False.
>=	>=	Больше, чем или равно. True, если Е1 больше или равно Е2, иначе — False.
о	о	Не равно. True, если Е1 не равно Е2, иначе — False.
Is	El is E2	Оба операнда должны быть значениями типа Object. True, если El ссылается на тот же самый объект, что и Е2, иначе — False.
Like	El Like E2	Подобие. Оба операнда должны быть значениями типа String. True, если El совпадает с образцом, содержащимся в Е2, иначе — False.
Если оба операнда в выражении сравнения имеют один и тот же тип данных, VBA выполняет простое сравнение для этого типа. Если, например, оба операнда являются строками, VBA выполняет сравнение строк; если оба операнда являются датами, то VBA выполняет сравнение дат и так далее.
Следующие выражения иллюстрируют использование различных операторов сравнения:
MyVal	= 55	результат True, если MyVal содержит 55
7 <> 5		результат True: 7 не равно 5
NumVar <57		True, если NumVar меньше, чем 57
Now >	#5/30/1997	True, если текущая дата (результат функции Now) больше, чем 30 мая 1997
"Joe" <	' "Sam"	True; "Joe" меньше, чем "Sam" (в соответствии с алфавитом)
"Pat"	c "Patricia"	True; "Pat" короче, чем "Patricia"
Выражения в Visual Basic
131
Помните, что значения дат VBA могут включать информацию о времени. Когда сравниваются значения дат, VBA, фактически, сравнивает информацию о дате и времени. Поэтому, даже если месяц, день и год двух дат являются одними и теми же, они могут не быть равны друг другу, если временные части значения даты различны. Например, дата #1/10/97# меньше, чем дата #1/10/97 9:00:00АМ#. В первой дате нет никакого значения времени, и VBA «полагает», что время составляет 00:00:00. Несмотря, на то что год, месяц и день во второй дате те же, что и в первой, она имеет более позднее время и, следовательно, является большей, чем первая дата.
Если оба операнда в выражении сравнения имеют определенные типы (либо — константы, либо — типизированные переменные) и эти типы не являются совместимыми, VBA выводит на экран сообщение об ошибке несовпадения типов.
Если один или оба операнда в выражении сравнения являются переменными типа Variant, VBA «пытается» преобразовать тип Variant в какой-либо совместимый тип, если необходимо. Если преобразование данных необходимо, a VBA не может преобразовать Variant в совместимый тип, отображается сообщение об ошибке времени исполнения.
Поскольку не всегда легко определить, будет ли VBA выполнять численное сравнение или строковое, когда в выражении сравнения смешаны численные и строковые значения, следует всегда использовать одну из VBA-функций преобразования типов (например, CStr) для явного преобразования значений в числа или строки/чтобы оба операнда в выражении сравнения имели один и тот же тип данных. (Функции преобразования описаны в следующей главе.)
Сравнение строк
Сравнение строк немного сложнее, чем сравнение чисел. В VBA строка равна другой строке, только когда обе строки содержат точно такие же символы в точно таком же порядке и обе строки имеют одну и ту же длину.
Рассмотрим следующие выражения:
"abc" =	"abc"	True; обе строки одинаковые
"abc" =	abc	False; строки не одинаковые
В первом выражении строки равны одна другой: обе содержат те же символы и в том же порядке и имеют одну и ту же длину. Во втором выражении строки не равны одна другой, строка в правой части оператора имеет по одному символу пробела в начале и в конце строки. VBA не игнорирует начальные или конечные символы пробела при сравнении строк. При сравнении строк операторами отношения, VBA сравнивает каждую строку слева направо посимвольно.
Следующие несколько примеров выражений иллюстрируют сравнение строк:
"abb" <	"abc"	True
"aab" <	"abb"	True
2abc" <	"abc	True
“abed”	> “abc”	True
Будьте внимательны при сравнении строк фиксированной и переменной длины. Помните, что строки фиксированной длины всегда содержат одно и то же количество символов и что размер строки переменной длины увеличивается и уменьшается в зависимости от размера строки, сохраняемой в ней.
5*
132
Глава 5
Двоичное и текстовое сравнение строк
До сих пор в этой главе выражения сравнения строк включали только строки, состоящие из символов нижнего регистра. VBA предоставляет два различных способа сравнения символов различных регистров. Первый метод, который VBA использует для сравнения строк, называется бинарным {binary) или двоичным сравнением и является методом сравнения по умолчанию.
Чтобы понять, как работает двоичное сравнение, необходимо помнить, что вся информация в компьютере сохраняется в виде чисел. Для сохранения текста компьютер использует схему, в которой каждый отображаемый символ имеет уникальный номер. Для представления в компьютере все буквы некоторого алфавита имеют уникальные последовательные номера. Обычно буквы верхнего регистра (например, A-Z) имеют меньшие номера, чем буквы нижнего регистра (a-z). Число, соответствующее определенной букве или другому символу, называется кодом символа {character code).
При выполнении двоичного сравнения строковой информации, VBA использует фактический бинарный эквивалент числа для каждого символа, так как при этом сравнивается каждая пара символов. Поскольку буквы верхнего регистра имеют меньшие двоичные номера, буквы верхнего регистра располагаются в алфавитном порядке перед буквами нижнего регистра. Другими словами, для VBA при двоичном сравнении строк, строка "ААА" меньше, чем строка "ааа”.
Второй тип сравнения, предлагаемый VBA, называется текстовым {text) сравнением. В текстовом сравнении VBA не использует двоичный эквивалент для каждого символа и «рассматривает» буквы верхнего регистра как эквивалентные буквам нижнего регистра. В текстовом сравнении строка "АВС" равна строке "abc”.
Выбор метода сравнения строк
Для выбора метода сравнения строк, имеющегося в VBA (двоичного или текстового), используйте директиву Option Compare:
Option Compare [Text I Binary]
Чтобы задать двоичное сравнение строк, используйте ключевое слово Binary: 
Option Compare Binary
Директиву Option Compare можно использовать только на модульном уровне, и она влияет только на сравнения, выполняемые процедурами в этом отдельном модуле. Обычно директиву Option Compare помещают в область объявлений модуля перед объявлениями переменных или процедур. Если команды Option Compare в коде нет, VBA использует двоичные сравнения.
Сравнение строки с шаблоном
Оператор1 Like дает возможность выполнять особый тип операции сравнения строк и его можно использовать только со строками.
Like тестирует строку для определения того, совпадает ли она с заданным шаблоном (образцом). Оператор Like можно использовать для выполнения поиска в текстовой информации для нахождения всех слов или фраз, совпадающих с определенным шаблоном. Поиск такого типа часто называют нечетким поиском {fuzzy search).
Строго говоря, Like является обозначением операции сравнения и входит в состав логического выражения. То же самое касается и оператора Is, и логических операторов, рассматриваемых далее.
Выражения в Visual Basic
133
Общий синтаксис для оператора Like следующий:
СИНТАКСИС
StrExprl Like StrExpr2
StrExprl — любое строковое выражение VBA. StrExpr2 — строковое выражение, специально созданное для задания шаблона, который оператор Like сравнивает с StrExprl.
Результатом выражения Like является True, если первый операнд (StrExprl) совпадает с шаблоном во втором операнде (StrExpr2); иначе результатом выражения будет False. Оба операнда в этом выражении должны быть строковыми выражениями, или VBA отобразит сообщение об ошибке несовпадения типов.
Шаблон, с которым должна сравниваться строка, задается с использованием различных специальных символов. В табл. 5.3 содержатся методы и символы для создания образцов совпадения для оператора Like.
Таблица 5.3. Символы совпадения с образцом для оператора Like
Символ образца	Соответствие
#	Любая одиночная цифра от 0 до 9.
*	Любое количество символов в любой комбинации или отсутствие символов.
?	Любой одиночный символ.
[list]	list — это список определенных символов. Совпадение с любым одиночным символом в списке.
[Hist]	list — это список определенных символов. Совпадение с любым одиночным символом, не имеющимся в списке.
Следующее выражение является равным True, если AnyStr содержит строки такие, как "Sadie”, "Salone", "Sophie”, "Steve" и так далее:
AnyStr Like "S*e"
Следующее выражение является равным True, если AnyStr содержит строки такие, как "Реппу", "Percy", "Patty" и так далее:
AnyStr Like "Р???у"
Используйте две последние спецификации символов совпадения из табл. 5.3 для указания отдельных символов, совпадение или несовпадение с которыми вам необходимо. Следующие выражения показывают, как использовать квадратные скобки с символьным списком.
Данное выражение является равным True, если AnyStr содержит "big" или "bid", или — False, если оно содержит "bit" или "bin":
AnyStr Like "bi[dg]"
Следующее выражение является равным True, если AnyStr содержит "big", "bid" или "bin", или — False, если оно содержит "bit":
AnyStr Like "bi[!t]"
Еще одно выражение является равным True, если AnyStr содержит "bin" или "bit", или — False, если AnyStr содержит "bid" или "big":
AnyStr Like "bi[!dg]"
Можно также использовать квадратные скобки для указания диапазона символов, совпадение или несовпадение с которыми необходимо:
134
Глава 5
AnyStr Like "ci[a-f]"	,
AnyStr Like "ci[!a-f]”
Результат первого из приведенных выше примеров является равным True, если AnyStr содержит "cia", "cib", "cic", "cid", "cie" или "cif" и False — иначе. Второе выражение обратно первому и является равным False, если AnyStr содержит одну из строк ”cia”, "cib", "cic", "cid", "cie", "cif". Второе выражение является равным True для любой строки, содержащей первые две буквы ci и не заканчивается на буквы от а до f.
Когда вы указываете диапазон символов, необходимо указывать диапазон от наименьшего до наибольшего символа. Например, [a-f] — правильный диапазон, но [f—а] — нет. VBA игнорирует пары квадратных скобок, в которых ничего не заключено ([]).
Поскольку левая квадратная скобка ([), знак вопроса (?), символ номера (#) и символ (*) имеют особое значение в строке шаблона, необходимо заключать их в квадратные скобки, если вы хотите, чтобы они были частью шаблона. Например, если необходимо узнать, заканчивается ли строка вопросительным знаком, используйте следующее выражение (которое является равным True, если AnyStr содержит любое число или комбинацию символов, заканчивающуюся знаком вопроса): ,
AnyStr Like "*[?]"
Правая скобка (]) и восклицательный знак (!) также имеют особое значение в строке шаблона; для достижения совпадения с этими символами необходимо помещать их вне квадратных скобок списка символов. Например, чтобы определить, заканчивается ли строка восклицательным знаком, используйте следующее выражение (которое является равным True, если AnyStr содержит любое число или комбинацию символов, заканчивающуюся восклицательным знаком):
AnyStr Like "*!"
Для совпадения со знаком дефиса в строке шаблона поместите дефис в начало или в конец списка символов внутри квадратных скобок. Помещение дефиса в любое другое место задает диапазон символов. Следующее выражение показывает, как сопоставлять с символом дефиса (это выражение является True, если AnyStr содержит "big-headed", "pig-headed", "plug-ugly", "tag-along" и так далее):
AnyStr Like ”*д[-]*"	' True
На результат сравнения строк, которое использует оператор Like, оказывает также влияние инструкция Option Compare. Если задано двоичное сравнение строк, то оператор Like различает буквы верхнего и нижнего регистра. Если выбрана установка текстового сравнения, оператор Like не чувствителен к состоянию регистра.
Использует ли VBA в данный момент двоичное или текстовое сравнение, также влияет на то, какие символы оператор Like включает в различные диапазоны, задаваемые пользователем. Если, например, был задан диапазон [e-i], а опция сравнения установлена на двоичное сравнение, то только символы е, f, g, h и i совпадают с указанным диапазоном. Если опция сравнения установлена на текстовое сравнение, то диапазон [e-i] включает еще несколько символов — (Е, е, И, и, Й, й, К, к, Ё, ё, F, f, G, g, Н, h, I) и i.
Если необходимо только узнать, является ли строка частью другой строки, исполь-/^у\ зуйте VBA-функцию Instr вместо оператора сравнения Like. Например, если необ-ходимо только определить, является ли строка "big" частью строки "bigger", исполь-зуйте функцию Instr, функции VBA описываются в главе 6
Выражения в Visual Basic
135
Сравнение объектов
VBA имеет следующий оператор сравнения — Is. Этот оператор можно использовать только для сравнения выражений типа Object. Выражения, включающие оператор Is, всегда имеют результатом значение типа Boolean.
Результатом оператора Is является True, если оба выражения типа Object ссылаются на один и тот же объект; в противном случае результатом является False. VBA предоставляет оператор Is, потому что никакой другой из операторов сравнения не является значащим, когда он используется с выражениями типа Object. Выражения типа Object, на самом деле, являются адресами в памяти, ссылающимися на определенный объект в host-приложении (Excel, Word, Access или каком-либо другом приложении, реализующем VBA). Более подробно объекты описываются в главе 10.
Логические операторы
Чаще всего логические операторы VBA используются для объединения результатов отдельных выражений сравнения, чтобы создать сложные критерии для принятия решений в процедуре, или для создания условий, при которых группа операторов должна повторяться.
Можно использовать любое действительное выражение, имеющее результат типа Boolean, в качестве операнда для логического оператора или число, которое VBA может преобразовать в значение типа Boolean. Для VBA 0 является эквивалентным Boolean-значению False, а любое другое численное значение — значению True.
Обычно результатом логической операции является значение типа Boolean, хотя некоторые логические операции могут иметь результатом особое значение Null, если один или больше операндов имеют значение Null. Поскольку VBA интерпретирует особое значение Empty как 0, операнды в логических выражениях, содержащие Empty, обрабатываются так, как если бы они содержали Boolean-значение False.
В табл. 5.4 приведены логические операторы, имеющиеся в VBA, вместе с синтаксисом и кратким описанием работы. (Е в этой таблице представляет собой любое допустимое выражение с результатом типа Boolean, такое как операция сравнения.)
Таблица 5.4. Логические операторы
Оператор	Синтаксис	Имя/Описание
And	El And E2	Конъюнкция. True, если оба Е1и Е2 имеют значение True, иначе — False.
Or	El Or E2	Дизъюнкция. True, если одно выражение или оба (Е1 и Е2) являются равными True; иначе — False.
Not	Not El	Отрицание. True, если Е1 имеет значение False; False, если El является равным True.
Xor	El Xor E2	Исключение. True, если Е1 является равным True или Е2 является равным True; иначе — False.
Eqv	El Eqv E2	Эквивалентность. True, если Е1 имеет то же самое значение, что и Е2; иначе — False.
Imp	El Imp E2	Импликация. False, когда Е1 является равным True и Е2 равно False; иначе — True.
136
Глава 5
Логические VBA-операторы And, Not и Or подобны функциям рабочего листа AND, NOT и OR, встроенным в Excel. Однако Excel не имеет эквивалентных функций для VBA-операторов Eqv, Imp или Хог.
Таблицы истинности
Таблица истинности (truth table) — это таблица, показывающая все возможные комбинации значений для определенного типа логической выражения и его результаты. Большинство таблиц истинности имеют три столбца. Первый столбец предназначен для значения первого операнда, второй — для значения второго операнда, а последний столбец всегда содержит значение результата выражения. Каждая строка в таблице предназначена для определенной комбинации значений. Рассмотрим следующую строку из таблицы истинности оператора And:
False True False
В этой строке первый операнд — это False, второй операнд — True, а результат операции And является равным False. Эта строка в таблице истинности означает, что результатом выражения False And True является False.
And
Оператор And выполняет логическую конъюнкцию. Результатом операции And является значение True, только когда оба операнда являются равными True; иначе — False.
Оператор And имеет следующий синтаксис:
СИНТАКСИС » г
Operandl And 0perand2
Operandl и Operand.2 являются любыми допустимыми логическими выражениями VBA. (Логическое выражение (logical expression) — это любое выражение VBA, которое имеет результатом значение типа Boolean: True или False.]
Следующая таблица истинности показывает результаты операции And.
Operandl	Operand2	Результат выражения
True	True	True
True	False	False
False	True	False
False	False	False
Оператор And можно использовать не только для двух операндов. Результатом этого оператора с несколькими операндами будет значение True, если все операнды в выражении равны True. Например:
(2 > 5) And (7 > 3) And (3 > 1)
Это выражение имеет результатом False. Обратите внимание, что операнды в этом выражении являются выражениями сравнения; заметьте также круглые скобки вокруг выражений, которые составляют операнды оператора And: Круглые скобки указывают VBA на необходимость вычислить выражение внутри скобок перед вычислением других частей этого выражения. Кроме того, круглые скобки делают выражение более читабельным, группируя вместе связанные части выражения. Скобки, используемые для группировки частей выражения в подвыражение, являются общей особенностью выражений всех типов: численных, строковых, дат и сравнения, так же как и логических выражений.
Выражения в Visual Basic
137
Or
Оператор Or выполняет логическую дизъюнкцию и его часто называют включающим «ИЛИ» (inclusive or). Результатом операции Ог является значение True, когда хотя бы один из операндов равен значению True; иначе (если все операнды — False) результатом является значение False.
Оператор Or имеет следующий общий синтаксис:
СИНТАКСИС
Operandl Or 0perand2
Operandl и Operand.2 являются любыми допустимыми логическими выражениями VBA.
Следующая таблица истинности показывает результаты операции Or.
Operandl	Operand2	Результат выражения
True	True	True
True	False	True
False	True	True
False	False	False
Оператор Or можно использовать не только для двух операндов. Результатом оператора с несколькими операндами будет значение True, если хотя бы один операнд в выражении равен True. Например:
(2 > 5) Or (7 > 3) Or (3 > 1)
Это выражение имеет результатом True. Сравните с предыдущим примером.
Операторы And и Or можно комбинировать в одном выражении. Например, значение следующего выражения равно True:
( (2 > 5) Or (7 > 3) ) And ( (3 > 1) Or (8 < 10) )
Not
Оператор Not выполняет логическое отрицание; он инвертирует любое значение, к которому применяется. Оператор Not использует только один операнд и имеет результатом значение True, если операнд является равным False, или — False, если операнд — True.
Оператор Not имеет следующий общий синтаксис:
СИНТАКСИС
Not Operand
Operand — это любое допустимое логическое выражение VBA.
Следующая таблица истинности' показывает результаты операции Not:
Operand	Результат выражения
True	False
False	True
Подумайте над результатом следующего выражения и используйте среду VBA для проверки своих рассуждений.
138
Глава S
((2 > 5) Or (7 > 3) ) And Not ((3 > 1) Or (8 < 10))
Код для тестирования этого выражения совсем простой (см. листинг 5.4) и приведен только с целью напомнить о том, что мы изучаем программирование на VBA. Все, что мы обсуждаем, следует проверять, даже если вам кажется это очень понятным.
«
Листинг 5.4. Очень простой тест логического выражения
1 Sub list5_04()
2
3 dd = ( (2 > 5) Or (7 > 3) ) And Not ((3 > 1) Or (8 < 1C) )
4 gg - MsgBox(dd, vbOKOnly)
5
6 End Sub
Xor
Оператор Xor выполняет логическое исключение. Чаще его называют исклю чающим «ИЛИ» (exclusive or). Результатом операции Хог является True, когда какой-либо операнд (но не оба), является равным True; иначе результатом будет значение False.
Оператор Хот имеет следующий общий синтаксис:
п'.; СИНТАКСИС	. ?
Operandl Xor Operand2
Operandl и Operand2 — это любые допустимые логические выражения VBA.
Следующая таблица истинности показывает результаты операции Хот:
Operandl	Operand2	Результат выражения
True	True	False
True	False	True
False	True	True
False	False	False
Листинг 5.5 содержит код, полученный из кода листинга 5.4 заменой оператора Or на Хот. Проверьте, совпадает ли ожидаемый вами результат с тем, который выдает VBA.
Листинг 5.5. Отличие оператора Or от Хог
1	Sub	list5	04 ()
2			
3		dd =	((2 > 5) Xor (7 > 3)) And Not ((3 > 1) Xor (8 < 10))
4		gg =	MsgBox(dd, vbOKOnly)
5			4
6	End	Sub	
Eqv
Оператор Eqv является операцией логической эквивалентности; использование оператора Eqv подобно тестированию на равенство. Результатом операции Eqv является значение True, когда оба операнда будут равными True; иначе — False.
Выражения в Visual Basic
139
Оператор Eqv имеет следующий синтаксис:
СИНТАКСИС	'-"Ш
Operandl Eqv Operands
Operandl и Operand.2 — это любые допустимые логические выражения VBA.
Следующая таблица истинности показывает результаты операции Eqv:
Operandl	Operand2	Результат выражения
True	True	True
True	False	False
False	True	False
False	False	True
Если любой операнд в выражении операции Eqv является равным Null, то результатом также будет значение Null.
Imp
Оператор Imp выполняет логическую операцию импликации. Оператор Imp тестирует взаимосвязь между двумя логическими значениями, когда справедливость одного значения подразумевает справедливость другого значения; в качестве результата операция Imp имеет значение True, только когда второй операнд не противоречит первому. Оператор Imp имеет следующий синтаксис:
СИНТАКСИС	х вл -
Operandl Imp Operands
Operandl и Operand2 — это любые допустимые логические выражения VBA.
Следующая таблица истинности показывает результаты операции Imp.
Operandl	Operand2	Результат выражения
True	True	True
True	False	False
False	True	True
False	. ,	False	True~
Результат логической импликации может быть равным True, даже когда первое условие является значением False, в то время как второе условие является значением True. Однако результат логической импликации не может быть значением True, если первое условие является равным True, а второе — False. Результаты логической импликации не являются такими же интуитивными и понятными, как результаты других логических операторов; к счастью, использование оператора логической импликации редко бывает необходимо.
Конкатенация строк
VBA дает возможность объединять (склеивать) строки вместе для образования более длинных строк. Присоединение одной строки к другой называется конкате
140
Глава 5
нацией (concatenation) строк. Конкатенация строк чрезвычайно полезна и довольно проста, хотя имеются некоторые трудности, о которых необходимо знать.
Использование конкатенации строк
Конкатенацию строк чаще всего используют для формирования строк из различных источников в процедуре, чтобы создавать пользовательские сообщения и выводить на их экран. В листинге 5.6 приведена процедура VBA Excel, которая запрашивает у пользователя имя файла рабочей книги, открывает эту рабочую книгу и затем выбирает определенный рабочий лист (в данном случае — рабочий лист с именем Отчет о продажах).
Листинг 5.6. Конкатенация строк
1	Sub Open2DataEntry()
2	' Демонстрация конкатенации строк
3
4	Const BoxTitle = "Установка входных данных"
5	Const ShtName = "Отчет о продажах"
6
7	Dim Fname As String
8
9	' получить от пользователя имя рабочей книги
10	Fname = InputBox("Введите имя рабочей книги:", BoxTitle)
11
12	Workbooks.Open FileName:=Fname	1 открыть книгу
13
14	Activeworkbook.Sheets(ShtName).Select ' выбрать рабочий лист
15
16	' сообщение пользователю о том, что книга открыта
17	MsgBox "Рабочая книга " & Fname & " открыта, " & ShtName & _
18	" выбран.", , BoxTitle & " завершена"
19	End Sub
Заметьте, что оператор конкатенации используется только в строках 17-18. Вся остальная часть программы предназначена для описания строковых констант и подготовки строковых переменных, используемых в операторе MsgBox, в котором получается строка из нескольких констант и переменных.
Если вы выполняете эту процедуру и вводите имя Bookl при запросе на ввод имени файла, оператор MsgBox в строках 17-18 отображает диалоговое окно, показанное на рис. 5.3. (Этот пример предполагает, что вы действительно имеете рабочую книгу с именем Bookl.xls в текущей папке; в противном случае VBA отображает ошибку времени исполнения. Если вы будете экспериментировать с этим листингом, убедитесь, что вы вводите правильное имя рабочей книги.)
Рис. 5.3
Оператор InputBox (строка 10) отображает окно для ввода наименования рабочей книги; оператор MsgBox (строки 17-18) отображает окно с сообщением о результате
Выражения в Visual Basic
141
Операторы конкатенации строк
VBA имеет два знака операции для конкатенации строк; в следующих параграфах описывается каждый из этих знаков и их использование.
Знак & можно использовать только для конкатенации строк; этот знак не имеет другого назначения или функции в VBA. Все примеры в этой книге используют знак & для конкатенации .строк — это предпочтительный знак конкатенации строк, потому что он не оставляет никаких сомнений относительно того, какую операцию вы намереваетесь выполнить. Общий синтаксис знака & такой:
СИНТАКСИС
Operand! & Operands [& Operands ...]
Operandl и Operand2 — любые допустимые строковые или Численные выражения. Если один или оба операнда являются численными выражениями, VBA преобразует числа в строки перед выполнением операции конкатенации. Тип данных результата конкатенации строк — это всегда тип String. Если операнд в выражении конкатенации строк является равным Null или Empty, VBA интерпретирует этот операнд как строку нулевой длины (то есть строку, которая не содержит никаких символов).
Если вы не отделяете знак & от имени переменной (перед ним), по крайней мере, одним пробелом, VBA «полагает», что вы хотите использовать символ & как символ определения типа Long вместо знака операции конкатенации. Эта ситуация имеет различные результаты: в некоторых случаях VBA преобразует переменную или результат выражения в число с типом данных Long (как в листинге 5.7), в других случаях отображает сообщение о какой-либо ошибке синтаксиса или времени исполнения. Если вы уже объявили все переменные с конкретными типами (что является хорошей практикой в программировании), VBA отобразит сообщение об ошибке.
Листинг 5.7.
1	Sub list5_07О
2	dd& = 99
3 дд = MsgBox(TypeName(dd), vbOKOnly, " dd& = 99 ")
4	End Sub
Рис. 5.4
Результат выполнения кода листинга 5.7
Для конкатенации строк можно также использовать знак операции "+". Знак операции "+" имеет синтаксис и требования к операндам такие же, как и знак &, только с одним главным отличием. Знак операции имеет исторические корни в оригинальных версиях языка программирования BASIC. В этих ранних версиях языка BASIC не уделялось большого внимания различию между конкатенацией строк и сложением. Однако в VBA главным назначением знака "+" является арифметическое сложение. Всякий раз при обработке выражения, использующего знак "+", VBA сначала «пытается» выполнить арифметическое сложение. VBA выполняет конкатенацию строк со знаком ”+", только если один из операндов является строковым выражением и не может быть преобразован в число или если оба операнда являются строками.
142
Глава 5
Используйте знак & для конкатенации строк, чтобы избежать двусмысленности по поводу того, какую операцию необходимо выполнять, и чтобы обеспечить выполнение конкатенации строк VBA. Не используйте знак "+" для конкатенации строк, потому что выражения, использующие этот знак, могут быть неоднозначными для VBA и пользователей, которые будут читать ваш код.
Приоритеты выполнения операций при вычислении сложных выражений
Сложное (составное) выражение (complex expression) — это любое выражение, образованное из двух или более выражений. Многие из записываемых вами выражений — это сложные выражения, особенно, если они определяют управление последовательностью выполнения кода в процедурах или представляют различные математические формулы.
При вычислении сложных выражений VBA следует таким правилам:
	Части выражения, заключенные в круглые скобки, всегда вычисляются в первую очередь. Если выражение, заключенное в круглые скобки, является другим сложным выражением, VBA применяет эти же правила к выражению в круглых скобках.
	Конкретные операции выполняются в зависимости от иерархии операторов. (Иерархия различных операторов VBA показана в табл. 5.5.)
	Когда операторы имеют равный уровень приоритета, они вычисляются в порядке слева направо.
VBA вычисляет выражения в следующем порядке:
	Знаки арифметических операций.
	Знаки конкатенации строк.
	Операторы сравнения.
	Логические операторы.
В табл. 5.5 приведена иерархия операторов VBA. Операторы/операции перечислены в порядке от самого высокого приоритета до самого низкого. Операторы, помещенные в одной и той же строке этой таблицы, имеют равный приоритет. Операторы с равным приоритетом вычисляются слева направо так, как они появляются в выражении.
Таблица 5.5. Иерархия операторов/операций от наивысшего до самого низкого приоритета
Оператор/знак	Комментарии
	Возведение в степень, наивысший приоритет.
! -	Унарный минус.
*,/	Умножение и деление имеют равные приоритеты; они вычисляются по мере появления в выражении слева направо.
\	
Mod	
I +, -	Сложение и вычитание имеют равный приоритет; они вычисляются по мере появления в выражении слева направо.
Выражения в Visual Basic
143
Оператор/знак	Комментарии
&	Всякая конкатенация строк выполняется после любых арифметических операций в выражении и перед любыми операциями сравнения или логическими операциями.
Like=, <>, Is	Все операторы сравнения имеют равные приоритеты и вычисляются по -мере появления в выражении слева направо. Используйте круглые скобки для группирования операторов сравнения в выражениях.
Not	
And	
Or	
Xor	
Eqv	
Imp	
 НЛПМ Лк
Использование функций Visual Basic
Вы уже пользовались встроенными VBA-функциями: InputBox и MsgBox. Теперь, когда вы знаете все о выражениях, пора научиться включать функции в выражения. При чтении этой главы не очень полагайтесь на правильность синтаксиса приведенных здесь функций. Печатные издания часто содержат ошибки. Ошибки встречаются и в справочных системах локализованных продуктов. Правильнее будет рассматривать эту главу как введение в мир функций и получение общего представления о функциях как необходимых составляющих системы программирования. Точный синтаксис каждой функции следует проверять в справочной системе VBA.
Функции
Функция (function) — это встроенная формула, выполняющая действия над выражениями и генерирующая значение. Функция всегда возвращает значение, которое VBA вставляет в программу в том месте, где появляется имя функции. Функции VBA делятся на несколько групп в зависимости от типа операции или вычисления, которое они выполняют. Функции используются для выполнения таких задач, как:
	Преобразование текстовых строк в другие типы данных.
	Получение данных о текстовых строках.
	Преобразование других типов в текстовые строки.
	Форматирование чисел или других типов данных для отображения.
*	Манипулирование или генерирование значений данных.
*	Получение информации о файлах, драйверах диска или среде, в которой VBA работает в данный момент времени.
В этой главе рассказывается о различных категориях функций и описываются подробно наиболее важные функции VBA и их использование. В последующих главах описываются другие функции VBA, перечисленные в этой главе и связанные с темами последующих глав. Кроме того, вы узнаете, что можно создавать собственные функции для использования в процедурах VBA.
В этой книге вы уже встречались с примерами процедур и функций VBA. Не путайте термины функция и процедура. Обычно процедура выполняет определенную задачу (или группу задач) подобно тому, как определенная команда меню в Excel, Word или другом приложении выполняет конкретную задачу. Функция оперирует одним или более значениями и возвращает некоторое результирующее значение (как формула в ячейке рабочего листа Excel).
Использование функций в выражениях
Чтобы использовать функцию, просто вводите имя функции в оператор VBA вместе с любыми аргументами, которые требуются для этой функции, в том месте в операторе, где вам необходимо использовать результат функции. [Помещение
Использование функций Visual Basic
145
имени функции в оператор VBA для активизации функции называют вызовом (calling) функции.] При использовании функций в выражениях следуйте таким правилам:
	Можно использовать результат функции как часть выражения.
	Можно присваивать результат функции какой-либо переменной.
	Можно использовать результат функции для предоставления значения в список аргументов другой процедуры или функции.
	Функции имеют списки аргументов, заключенные в круглые скобки.
В основном функцию можно использовать для предоставления значения в любом месте в любом операторе VBA, где может быть оправданно использование значения константы или переменной. В листинге 6.1 приведена процедура для демонстрации вызова функции в выражениях.
Листинг 6.1. Использование функций
1	Sub FuncDemo()
2	Dim s__Date As String
3	Dim d_Time As Date
4	s_Date	= CStr(Now)
5	d_Time	= Time
6	MsgBox	"Сегодня: "	&	s_Date
7	MsgBox	"Текущее время:	"	&	d_Time
8	End Sub
В строках 2-3 объявлены две переменные: s_Date с типом String и d_Time с типом Date. В строке 4 переменная s_Date получает значение текущей даты в виде строки, так как после вызова функции Now (получить системную дату) результирующее значение преобразуется функцией CStr в строку. Переменная d_Time принимает значение системного времени. В строках 6-7 с помощью оператора MsgBox значения переменных выводятся на экран (рис. 6.1) в диалоговых окнах. Обратите внимание на то, что, поскольку выражение в строке 7 содержит оператор конкатенации строк (&), для вывода в диалоговом окне переменной d_Time нет необходимости преобразования ее в строку. Поскольку эта синтаксическая «вольность» отсутствует во многих других языках программирования, я бы не советовал часто пользоваться этими VBA-возможностями. К тому же это не способствует стремлению к аккуратности при написании кода.
Рис. 6.1
Результат выполнения кода листинга 6.1
Аргументы и возвращаемое значение функции
Как вы уже видели в листинге 6.1, некоторые функции требуют одного или более аргументов, другие — нет. Функции, которые не требуют аргументов, обычно просто выбирают значение, недоступное иначе. Например, функция Time, возвращающая текущее системное время компьютера, не требует никаких аргументов, а функцию CStr вызывать без аргументов бессмысленно. Чтобы использовать функцию, не имеющую аргументов, просто введите имя функции в программу, как в следующих операторах:
СистемноеВремя = Time
MsgBox Now
146
Глава б
Другие функции требуют одного или более аргументов. Функция Sqr, например, возвращает корень квадратный числа; чтобы Sqr вычислила корень квадратный, необходимо предоставить число, как показано в следующих операторах:
r_Val =16
Root = Sqr(r_Val)
Значения предоставляются функции помещением их в список аргументов. Список аргументов следует заключать в круглые скобки и, если в списке находится более одного аргумента, отделять каждый аргумент запятой.
Тип данных значения, возвращаемого функцией, зависит от этой конкретной функции. Большинство функций возвращают значения типа Variant, хотя некоторые функции возвращают данные определенных типов, таких как String, Double и Integer. VBA во многих случаях может автоматически преобразовывать результат какой-либо функции в данные типа, совместимого с другими типами значений в выражении, содержащем эту функцию, точно, как VBA преобразует типы данных в присваиваниях переменных и вычислении выражений. Все правила совместимости типов данных, приведенные в главе 5, которые применимы к переменным Variant и типизированным переменным и константам, применимы также к значениям, возвращаемым функциями.
Игнорирование результата функции
Как правило, значение, возвращаемое функцией, должно быть каким-либо образом использовано: путем включения результата функции в выражение, в список аргументов, или путем присваивания его некоторой переменной. Однако в некоторых случаях можно не использовать возвращаемое функцией значение.
Ранее было упомянуто, что VBA-процедура MsgBox имеет необязательный второй аргумент, позволяющий определять, сколько командных кнопок появляется в окне сообщения. Можно использовать этот аргумент командных кнопок в процедуре MsgBox для отображения сообщения, которое задает пользователю вопрос и дает возможность ответить на него путем выбора командной кнопки в окне сообщения.
Если вы используете этот необязательный аргумент для MsgBox, то можно получить от MsgBox значение, указывающее, какую кнопку выбрал пользователь. В действительности, процедура MsgBox является функцией, хотя чаще всего используется как процедура.
До сих пор во всех примерах этой книги аргумент командных кнопок в операторах MsgBox был опущен. Если при вызове MsgBox аргумент командных кнопок не указывается, MsgBox отображает диалоговое окно, содержащее только одну кнопку. Поскольку диалоговое окно MsgBox до сих пор содержало только одну кнопку, не имело значения, каков результат функции MsgBox, и поэтому результат функции MsgBox игнорировался в коде.
VBA предоставляет несколько встроенных констант для определения кнопок в окне сообщения MsgBox (Далее в книге эти константы описываются более подробно. Список всех VBA-констант приведен в Приложении Б.) Одна из этих констант (vbYesNo) указывает MsgBox, что в отображаемое окно сообщения следует включить кнопку Yes и кнопку No. Следующий оператор выводит диалоговое окно, показанное на рис. 6.2:
MsgBox "Вам видны две кнопки?" , vbYesNo, "Демонстрация кнопок"
При использовании этого оператора имеется одна проблема: результат пользовательского выбора никаким образом не возвращается; код по-прежнему не использует результат функции MsgBox.
Для выборки результата функции Msgbox необходимо изменить этот оператор: нужно заключить список аргументов в круглые скобки и изменить оператор так, чтобы он каким-то образом использовал результат функции. Обычно резуль
Использование функций Visual Basic
147
тат функции MsgBox присваивается какой-либо переменной и можно позже тестировать этот результат в другом операторе, чтобы определить, какую кнопку, фактически, выбрал пользователь процедуры. Следующая строка показывает оператор MsgBox, измененный так, что он возвращает значение:
Код_ответа = MsgBox ("Вам видны две кнопки9" , vbYesNo, _ "Демонстрация кнопок")
При выполнении этого оператора VBA отображает то же самое диалоговое окно, показанное на рис. 6.2. Когда пользователь выбирает кнопку Yes или No, VBA закрывает диалоговое окно и сохраняет число, соответствующее выбранной кнопке, в переменной Код_ответа.
Рис. 6.2 Диалоговое окно MsgBox, демонстрирующее результат включения в список параметров аргумента кнопок	Демонстрация кнопок
	Вам видны две кнопки9
	Yes |	К(о j
	
Два последних примера использования MsgBox иллюстрируют важный факт, касающийся функций: опуская круглые скобки вокруг списка аргументов функции, вы указываете VBA на то, что необходимо игнорировать результат функции. Когда круглые скобки опускаются, VBA интерпретирует вызов функции, как если бы это был вызов процедуры, и не возвращает результат.
Вернемся опять к примерам в начале этой главы и в функциях, использовавшихся в листинге 6.1, обратим внимание на то, что все операторы, вызывающие функцию VBA, включают круглые скобки вокруг списка аргументов функции, даже когда список аргументов содержит только один аргумент. Функции, не имеющие аргументов, не требуют круглых скобок при их вызове.
Нет смысла в игнорировании результата каждой функции VBA, и не всегда это желательно. Игнорирование результата функции полезно только при работе с функциями (такими как MsgBox), которые выполняют некоторую задачу, а возвращение ими результата является только частью их работы. Результат функции игнорируют, когда хотят, чтобы функция выполняла некоторые действия, но результат этих действий необязательно использовать в коде. Функция MsgBox, например, выполняет отображение сообщения в диалоговом окне в качестве основной задачи. (В главе 8 показано, как использовать MsgBox, чтобы дать возможность пользователю программы делать выбор, влияющий на выполнение программы.)
При попытке игнорировать результат функции, не имеющей аргументов (такой, как функция Now), или любой другой функции, результат которой не может не использоваться, VBA отображает сообщение об одной из нескольких возможных ошибках времени исполнения в зависимости от конкретной функции, хотя обычно появляется сообщение об ошибке синтаксиса или несовпадения типов. Обычно VBA запрещает игнорирование результата функции, имя которой является ключевым словом VBA (такой, как CStr или других функций преобразования), и тех функций, единственным назначением которых является предоставление некоторого возвращаемого значения, например, математических.
Использование именованных аргументов функции
Ранее в книге указывалось, что аргументы процедуры необходимо перечислять в определенном порядке. Также необходимо перечислять в определенном порядке и аргументы функции. Функции с несколькими аргументами используют
148
Глава 6
положение аргумента в списке аргументов для определения того, какое значение получает конкретный аргумент. Например, для MsgBox первый аргумент является сообщением, второй — это число и тип кнопок для диалогового окна, третий — заголовок диалогового окна.
Несмотря на то, что второй аргумент MsgBox, определяющий командные кнопки для диалогового окна, является необязательным и был опущен во всех примерах и упражнениях до сих пор в книге, все же необходимо включать отмечающие запятые для второго аргумента в список аргументов. Пропуск отмечающих запятых для второго аргумента приводит к ошибке несовпадения типов.
Как вы могли уже заметить, легко нечаянно опустить отмечающие запятые или переставить значения аргументов в функциях, имеющих необязательные аргументы или несколько аргументов, несмотря на помощь свойства Auto Quick (Краткие сведения) Редактора VB. Пропуск или перестановка аргументов в списке аргументов функции могут привести к ошибкам несовпадения типов. Ошибка (что еще хуже) может быть не обнаружена.
Чтобы предотвратить ошибки программирования и сделать более легким использование функций, имеющих необязательные аргументы, VBA предоставляет альтернативу перечислению значений в списке аргументов в определенном порядке. Можно также передавать значения аргументов функции, используя именованные аргументы (named, arguments) функций. Следующие строки показывают два оператора MsgBox, которые имеют один и тот же результат; первый оператор использует обычный метод перечисления аргументов, а второй — метод именованных аргументов (оба оператора игнорируют результат функции MsgBox):
MsgBox AnyMsg, , AnyTitle
MsgBox Prompt:=AnyMsg, Title:=AnyTitle
Второй оператор использует именованные аргументы для Prompt (сообщение или запрос) и Title (определяет заголовок окна сообщения), присваивая значение каждому именованному аргументу.
Символ, который присваивает значение именованному аргументу (:=), не является в точности тем же обычным оператором присваивания (=). Если опустить двоеточие (:) во время присваивания значения именованному аргументу, VBA не обязательно обнаружит ошибку синтаксиса, но не может интерпретировать этот оператор правильно. Когда VBA выполняет этот оператор, он отображает одну из нескольких возможных ошибок времени исполнения, часто — ошибку несовпадения типов.
При использовании именованных аргументов нет необходимости включать отмечающие запятые для необязательных аргументов. Обратите внимание, во втором из приведенных выше операторов нет отмечающей запятой между аргументами для запроса и заголовка в отличие от первого оператора. На самом деле, именованные аргументы не должны появляться в каком-либо определенном порядке. Вс втором операторе можно поместить аргумент Title перед аргументом Prompt, кав показано далее:
MsgBox Title:=3аголовок0кна, Prompt:=Сообщение
MsgBox все равно использует значение, присвоенное аргументу Title, в качест ве заголовка диалогового окна. При использовании именованных аргументов VB/ использует имя аргумента для определения того, какое значение этот аргумент представляет.
После столь долгого повествования о пользе функции MsgBox приведем, нако нец, ее полный синтаксис.
СИНТАКСИС
MsgBox(Prompt [, Buttons} [, Title] [, HelpFile, Context}}
Единственным обязательным аргументом для MsgBox является аргумент Prompt, который может быть любым строковым выражением и содержит ин
Использование функций Visual Basic
149
формацию, выводимую в диалоговом окне. Все другие аргументы являются необязательными (об этом говорят квадратные скобки, в которые заключены эти аргументы вместе с разделяющими запятыми).
Аргумент Title содержит строку для заголовка диалогового окна. Без этого аргумента в заголовке будет выведено наименование host-приложения, из которого запускается программа на VBA.
Аргумент HelpFile — это строковое выражение, содержащее имя справочного файла Windows; обычно это — файл, который вы уже должны были создать с помощью Windows Help Compiler. Аргумент Context — это численное выражение, указывающее раздел в справочном файле, относящийся к отображаемому диалоговому окну, например, 0 обычно относится к оглавлению справочного файла. Аргумент Buttons является численным выражением, которое задает количество и тип кнопок в диалоговом окне MsgBox. Buttons указывает также кнопку по умолчанию в диалоговом окне и, содержит ли это диалоговое окно стандартные значки Windows: Critical, Information, Exclamation или Question для предупредительных сообщений и запросов пользователя. В табл. 6.1 приведены значения аргументов-констант функции MsgBox и их назначение, а в табл. 6.2 — возвращаемые значения-константы функции.
Таблица 6.1. Аргументы-константы функции MsgBox
Константа	Назначение
vbAbortRetrylgnore	Отображает командные кнопки Стоп, Повтор, Пропустить (Abort, Retry, Ignore).
vb ApplicationM odal	Для продолжения работы с приложением пользователь должен ответить на запрос (или закрыть) этого диалогового окна. Любые другие приложения Windows, работающие в фоновом режиме, продолжают выполняться.
vbCritical	Отображает в диалоге значок критического предупредительного сообщения (Critical Message) Windows (красный кружок).
vbDefaultButtonl	Первая командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbDefaultButton2	Вторая командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbDefau!tButton3	Третья командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbDefaultButton4	Четвертая командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbExclamation	Отображает значок ("!") предупреждения (Warning Message); обычно используется для отображения важной информации или предупреждения, не требующего ответа.
vblnformation	Отображает значок ("i”) информации (Information Message); обычно используется для отображения важной информации, кроме предупреждения.
vbMsgBoxHelpButton	Добавляет к диалоговому окну кнопку Справка (Help); при щелчке на кнопке Справка открывается файл, который задан в аргументе HelpFile, в разделе, заданном аргументом Context.
150
Глава б
Константа	Назначение
vbOKCancel	Отображает кнопки OK и Отмена (OK, Cancel).
vbOKOnly	Отображает только кнопку ОК; то же самое происходит при опускании аргумента Buttons.
vbQuestion	Отображает значок запроса (Query icon) Windows ("?"); обычно используется, чтобы задать пользователю очень важный вопрос или выдать предупредительное сообщение, требующее ответа.
vbRetryCancel	Отображает кнопки Повтор и Отмена (Retry, Cancel).
vbSystemModal	При отображении диалоговое окно остается впереди других окон (даже при переключении на другое приложение), пока не будет закрыто.
vbYesNo	Отображает кнопки Да и Нет (Yes, No).
vbYesNoCancel	Отображает кнопки Да, Нет и Отмена (Yes, No, Cancel).
Таблица 6.2. Возвращаемые значения-константы функции MsgBox
Константа	Означает, что пользователь выбирает кнопку
vbAbort	Стоп (Abort)
vbCancel	Отмена (Cancel)
vblgnore	Пропустить (Ignore)
vbNo	Нет (No)
vbOK	ОК
vbRetry	Повтор (Retry)
vbYes	Да (Yes)
Другой наиболее часто используемой для обмена данными с пользователем функцией является InputBox. В главе 4 был приведен краткий синтаксис этой функции, а ниже — полный:
СИНТАКСИС
InputBox(Prompt [, Title] [, Default] [, XPos][, YFos] [, HelpFile, Context])
Prompt — это любое строковое выражение. Аргумент Prompt является единственным обязательным аргументом для InputBox; все другие — необязательные. Title — это строка, используемая в качестве заголовка для окна ввода (как и для функции MsgBox).
Default также является любым строковым выражением и используется как значение по умолчанию для пользовательского ввода.
Следующий оператор, например, запрашивает пользователя ввести имя файла и предлагает имя NEWFILE в качестве значения по умолчанию. Диалоговое окно, выводимое на экран этим оператором и отображающее значение по умолчанию, показано на рис. 6.3.
User_Input = InputBox("Введите имя файла: ", _ "Создать файл", "NEWFILE")
Использование функций Visual Basic
151
Рис. 6.3
Используйте необязательные аргументы функции InputBox для задания значения по умолчанию
Как вы могли уже заметить, диалоговое окно InputBox отображается в центре экрана. Можно выводить это окно в другом месте на экране, особенно, если необходимо, чтобы были открыты и оставались видимыми другие диалоговые окна.
Аргументы XPos и YPos могут быть любыми численными выражениями. Эти аргументы позволяют указать, где в активном окне появляется окно ввода, и являются координатами верхнего левого угла диалогового окна: XPos — горизонтальное расстояние от левого края окна; YPos — это вертикальное расстояние от верхнего края окна. Оба расстояния измеряются в твипах (twips); один твип равен 1/20 точки (точка — это измерение шрифта печати). Поскольку точка составляет 1/72 часть дюйма, то один твип приблизительно равен 0,0007 дюйма.
Будьте внимательны при задании положения диалогового окна InputBox. Вы можете задать позиции для аргументов XPos и YPos настолько большими, что диалоговое окно совсем не появится на экране, потому что его положение выйдет за правый или нижний край окна. При этом, хотя диалоговое окно и невидимо, оно является активным, ни один из элементов управления, которые вы видите на экране, не будет работать до тех пор, пока вы не отреагируете на «невидимое» диалоговое окно.
Последние два необязательных аргумента для функции InputBox — это HelpFile и Context. Они имеют то же назначение, что и подобные аргументы функции MsgBox.
Если вы задаете HelpFile или Context, необходимо задавать оба аргумента (эти аргументы заключены в одни квадратные скобки). Всякий раз, когда указывается справочный файл для окна ввода, VBA автоматически добавляет командную кнопку помощи в диалоговое окно. VBA не включает Windows Help Compiler; если вы хотите создать собственные пользовательские справочные файлы, необходимо от Microsoft получить Windows Help Compiler отдельно или использовать средства независимых поставщиков программного обеспечения.
При вызове InputBox можно использовать именованные аргументы. Для этого просто применяйте имена аргументов: Prompt, Title, Default, XPos, YPos, HelpFile и Context. Следующий оператор выдает такое же диалоговое окно, что и показанное на рис. 6.3, но здесь применяются именованные аргументы:
User_Input = InputBox(Prompt:="Введите имя нового файла: ”, _
Title:="Создать файл", Default:="NEWFILE”)
Обратите внимание, что этот оператор имеет круглые скобки вокруг списка аргументов. Необходимо всегда заключать список аргументов в круглые скобки при использовании результата функции, независимо от того, используете ли вы именованные аргументы при вызове функции.
Нельзя смешивать именованные аргументы с обычным списком аргументов в одном и том же вызове функции. Необходимо использовать либо именованные аргументы, либо список обычных аргументов для каждого отдельного вызова функции.
Для определения имен аргументов функции используйте всплывающее окно Auto Quick Info (Краткие сведения), появляющиеся при вводе имени функции (в Редакторе VBA). Можно также использовать Object Browser для вставки имени функции и добавления в список именованных аргументов в программном коде, как описано далее в этой главе.
152
Глава 6
Использование других функций VBA
Встроенные функции VBA делятся на несколько категорий на основе общего назначения функций (математические, преобразования данных, даты и времени, строковые и работы с диском). В следующих разделах обсуждаются категории функций и описываются их действия.
К сожалению, невозможно описать подробно каждую функцию VBA в рамках этой книги. Однако большинство функций VBA, такие как математические функции, являются довольно ясными из их названия и не требуют подробного объяснения. Другие функции, такие как функции преобразования типа данных и обработки строк, описаны более подробно. VBA-функции обработки строк имеют важное значение, поэтому отдельный раздел этой главы посвящен способам их использования.
Математические функции
VBA предоставляет стандартный набор математических функций. В табл. 6.3 приведены математические функции, имеющиеся в VBA. В этой таблице N означает любое численное выражение; все аргументы функций являются обязательными, если только не указано иначе.
Таблица 6.3. Математические функции VBA
Функции(ар-гументы)	Возвращает/действие
Abs(N)	Возвращает абсолютное зфчейке N.
Atn(N)	Возвращает арктангенс N как угол в радианах.
Cos(N)	Косинус угла N, где N — это угол, измеренный в радианах.
Exp(N)	Возвращает константу е, возведенную в степень N. (е — это основание натуральных логарифмов и она (приблизительно) равна 2,718282).
Fix(N)	Возвращает целую часть N. Fix не округляет число, а отбрасывает любую дробную часть. Если N является отрицательным, Fix возвращает ближайшее отрицательное целое большее, чем или равное N.
Int(N)	Возвращает целую часть N. Int не округляет число, а отбрасывает любую дробную часть. Если N является отрицательным, Int возвращает ближайшее отрицательное целое меньшее, чем или равное N.
Log(N)	Возвращает натуральный логарифм N.
Rnd(N)	Возвращает случайное число; аргумент является необязательным. Используйте функцию Rnd только после инициализации VBA-генератора случайных чисел оператором Randomize.
Sgn(N)	Возвращает знак числа: -1, если N — отрицательное; 1, если N — положительное; 0, если N равно 0.
Sin(N)	Возвращает синус угла; N — это угол, измеренный в радианах.
Sqr(N)	Возвращает корень квадратный из N. VBA отображает ошибку времени исполнения, если N — отрицательное.
Tan(N)	Возвращает тангенс угла; N — угол в радианах.
Использование функций Visual Basic
153
Функции Fix и Int укорачивают целые, то есть они отбрасывают дробную часть числа без округления. Единственное различие между функциями Fix и Int — это то, как они обрабатывают отрицательные числа.
Дополнительные тригонометрические функции можно выводить из базовых математических функций VBA. Например, если необходимо вычислить котангенс угла, для его нахождения можно использовать формулу 1/Тап(х). В главе 7 описывается, как писать собственные функции для создания производных математических функций.
Функции преобразования данных
Visual Basic предоставляет несколько функций для преобразования одного типа данных в другой. Используйте эти функции для устранения ошибок несовпадения типов и обеспечения явного контроля за типами данных в выражениях.
Например, при получении сообщения об ошибке несовпадения типов в определенном выражении можно преобразовать значения в выражении в типы, совместимые друг с другом, используя функции преобразования. Или же можно сохранять результат выражения в диапазоне численного типа Single (большинство численных выражений имеют результатом значение типа Double); в таком случае следует использовать функцию CSng для преобразования результата выражения в число типа Single, как показано в листинге 6.2.
Листинг 6.2. Использование функции CSng
1	Sub CSngDemoO
2	Dim d_Varl As Double
3	Dim s_Var2
4	d_Varl = 412
5	s_Var2 = CSng(352 / 17)
6	MsgBox TypeNartie(s_Var2)
7	End Sub
Проверьте, как работает код листинга 6.2.
В табл. 6.4 приведены функции преобразования данных в VBA. В этой таблице N — это любое численное, S — любое строковое, а Е —- выражение любого типа. Аргументы каждой функции являются обязательными, если не указано иначе.
Таблица 6.4. Функции преобразования данных
Функция(ар-гументы)	Возвращает/действие
Asc(S)	Возвращает число кода символа, соответствующее первой букве строки S. Буква "А", например, имеет код символа 65.
Chr(N)	Возвращает строку из одного символа, соответствующего коду символа N, который должен быть числом между 0 и 255, включительно. Код символа 65, например, возвращает букву "А".
Format(E, S)	Возвращает строку, содержащую значение, представленное выражением Е, в формате в соответствии с инструкциями, содержащимися в S.
Hex(N)	Возвращает строку, содержащую шестнадцатиричное представление N.
Oct(N)	Возвращает строку, содержащую восьмиричное представление N.
154
Глава 6
Функция(ар-гументы)	Возвращает/действие
RGB(N, N, N)	Возвращает целое типа Long, представляющее значение основных цветов изображения. N в каждом аргументе должно быть целым в диапазоне 0 — 255, включительно. Аргументы (слева направо) — это значения для красного, зеленого и синего цвета.
Str(N)	Возвращает строку, эквивалентную численному выражению N.
Val(S)	Возвращает численное значение, соответствующее числу, представленному строкой S, которая должна содержать только цифры и одну десятичную точку, иначе VBA не может преобразовать ее в число. Если VBA не может преобразовать строку в S, то функция Vai возвращает 0.
CBool(N)	Возвращает Boolean-эквивалент численного выражения N.
CByte(E)	Возвращает численное значение типа Byte (от 0 до 255); Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CCur(E)	Возвращает численное значение типа Currency; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CDate(E)	Возвращает значение типа Date. Е может быть любым допустимым выражением (строкой или числом), представляющим дату в диапазоне 1/1/100 — 12/31/9999, включительно.
CDbl(E)	Возвращает численное значение типа Double; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
Cint(E)	Возвращает численное значение типа Integer; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CLng(E)	Возвращает численное значение типа Long; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CSng(E)	Возвращает численное значение типа Single; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CStr(E)	Возвращает значение типа String; Е — любое допустимое численное или строковое выражение.
CVar(E)	Возвращает значение типа Variant; Е — любое допустимое численное или строковое выражение.
Наиболее часто используемые функции — это функции (объединенные в конце табл. 6.4 в группу), начинающиеся с буквы С (от слова conversion), за которыми следует сокращение имени типа: CStr, CSng, CDbl и так далее.
Функции даты и времени
VBA-функции даты и времени обычно используются для получения текущей даты и времени, разбиения значения даты на ее составляющие части или для преобразования строк и чисел в значения типа Date.
Использование функций Visual Basic
155
В таблице 6.5 приведены VBA-функции даты и времени и их действие. В этой таблице N — любое допустимое численное выражение, a D — любое допустимое выражения типа Date (включая значения типа Date, числа или строки, которые VBA может преобразовать в дату). Все аргументы функций в этой таблице являются обязательными, если не указано иначе.
Таблица 6.5. функции даты и времени
Функции(аргумен-ты)	Возвращает/действие
Date	Возвращает системную дату. Можно также использовать эту функцию как процедуру для установки системных часов компьютера. Более подробно можно узнать из справочной системы VBA.
Time	Возвращает системное время компьютера как значение типа Date. Можно также использовать эту функцию как процедуру для установки системных часов. Более подробно можно узнать из справочной системы VBA.
Now	Возвращает системную дату и время.
Year(D)	Возвращает целое, являющееся частью выражения типа Date и содержащее год. Год возвращается как число между 100 и 9999.
Month(D)	Возвращает целое, являющееся частью выражения типа Date, содержащее месяц. Месяц возвращается как число между 1 и 12, включительно.
Day(D)	Возвращает целое, являющееся частью выражения типа Date и содержащее день. День возвращается как число между 1 и 31, включительно.
Weekday(D)	Возвращает целое, содержащее день недели для выражения типа Date. День недели возвращается как число между 1 и 7, включительно; 1 — это воскресенье, 2 — понедельник и так далее.
WeekdayName(Nl, B, N)	Возвращает строку с наименованием дня недели, номер которого задается параметром N1.
Hour(D)	Возвращает целое, содержащее часы как часть времени, содержащегося в выражении типа Date. Часы возвращаются как число между 0 и 23, включительно. Если выражение D не содержит значения времени, то Hour возвращает 0.
Minute(D)	Возвращает целое, содержащее минуты как часть времени в выражении типа Date. Минуты возвращаются как число между 0 и 59, включительно. Если выражение D не содержит значения времени, Minute возвращает 0.
Second(D)	Возвращает целое, содержащее секунды как часть времени в выражении типа Date. Секунды возвращаются как число между 0 и 59, включительно. Если выражение D не содержит значения времени, Second возвращает 0.
DateAdd(S, N, D)	Возвращает значение [тип Variant (Date)], содержащее дату, к которой добавлен заданный интервал времени.
156
Глава 6
Функции(аргумен-ты)	Возвращает/действие
DateDiff(S, Dl, D2[, N1 [, N2 ]])	Возвращает значение [тип Variant (Long)] числа временных интервалов между двумя определенными датами.
DatePart(S, D,[, N1 [, N2]])	Возвращает определенную часть [тип Variant (Integer)] заданной даты.
DateSerial(N, N, N)	Возвращает значение последовательной даты для заданной даты. Слева направо аргументы представляют год, месяц и день. Аргумент года должен быть целым числом между 100 и 9999, месяца — между 1 и 12, дня — между 1 и 31 (все диапазоны являются включающими).
TimeSerial(N, N, N)	Возвращает значение последовательного времени. Слева направо аргументы представляют часы, минуты и секунды. Аргумент часов должен быть целым числом между 0 и 23, аргументы минут и секунд должны оба быть числами 0 и 59 (все диапазоны являются включающими).
DateValue(E)	Возвращает значение типа Date, эквивалентное дате, заданной аргументом Е, который должен быть строкой, числом или константой, представляющей дату.
TimeValue(E)	Возвращает значение типа Date, содержащее время, заданное аргументом Е, который может быть строкой, числом или константой, представляющей время.
Timer	Возвращает число, представляющее количество секунд от полуночи в соответствии с системным временем компьютера.
Некоторые из перечисленных функций уже использовались в примерах этой книги, другие — будут использоваться далее.
Строковые функции
Строковые функции VBA часто применяются для нахождения заданных строк внутри других строк, для сравнения одной строки с другой и копирования выбранных частей строк. Строковые функции VBA используются довольно часто, потому что строковые данные очень важны и встречаются в каждом приложении VBA — Word, Excel, Access или другом host-приложении VBA. Часто необходимо манипулировать строковыми данными, полученными как пользовательский ввод функцией InputBox. В других случаях строковые данные появляются в коде VBA как имена файлов для документов Word, рабочих книг Excel, баз данных Access и других типов данных, сохраняемых в файлах на дисках.
В Word важность манипулирования строковыми данными очевидна: данные, сохраняемые в документах Word, в основном являются ничем иным, как строковыми данными. Строковые данные также важны в Excel в качестве имен рабочих листов, именованных диапазонов данных и так далее. В этом разделе приводятся имеющиеся в VBA строковые функции; в последующем разделе более подробно описывается, как использовать наиболее важные и полезные строковые функции.
В табл. 6.6, где приведены основные строковые функции VBA, N — это любое допустимое численное выражение, aS — это любое допустимое строковое выражение. Все аргументы функций являются обязательными, если не указано иначе.
Использование функций Visual Basic
157
Таблица 6.6. Строковые функции
Функция(аргумент)	Возвращает/действие
InStr([Nl,] SI, S2[, N2])	Возвращает положение S2 в SI. Nl — начальное положение для поиска; N2 определяет тип сравнения. N1 и N2 необязательны. Если N2 опускается, то для поиска используется текущая установка Option Compare.
InStrRev(Sl, S2 [, Nl[, N2]])	Возвращает позицию появления строки S2 внутри S1, в направлении от конца (или N1) к началу строки. N2 определяет тип сравнения. Если N2 опускается, то для поиска используется текущая установка Option Compare.
LCase(S)	Возвращает строку (тип String), содержащую копию S со всеми символами верхнего регистра, преобразованными в символы нижнего регистра.
Left(S, N)	Возвращает строку; копирует N символов из S, начиная с левого крайнего символа S.
Len(S)	Возвращает число символов в S, включая начальные и конечные пробелы.
LTrim(S)	Возвращает копию строки S после удаления символов пробела из левой части строки (начальные пробелы).
Mid(S, Nl, N2)	Возвращает строку; копирует N2 символов из S, начиная с позиции символа в S, заданной аргументом Nl. N2 является необязательным; если N2 опущен, то Mid возвращает все символы в строке S от позиции N1 до конца строки.
Right(S, N)	Возвращает значение типа String; копирует N символов из S, начиная с правого крайнего символа S. Например, Right("outright", 5) возвращает строку "right".
RTrim(S)	Возвращает копию строки S после удаления символов пробела из правой части строки (конечные символы).
Space(N)	Возвращает строку пробелов длиной N символов.
StrComp(Sl, S2, N)	Сравнивает SI с S2 и возвращает число, обозначающее результат сравнения: -1, если SI < S2; 0, если SI = S2; 1, если SI > S2. N является необязательным и указывает, следует ли выполнять сравнение с учетом регистра. Если N опускается, строки сравниваются с использованием текущей установки Option Compare.
StrConv(S, N)	Возвращает строку, преобразованную в новую форму в зависимости от числового кода, заданного аргументом N. VBA предоставляет внутренние константы для использования с функцией StrConv; наиболее полезными являются: vbProperCase (преобразует строку так, что каждая буква, начинающая слово, становится заглавной), vbLowerCase (преобразует строку в буквы нижнего регистра) и vbUpperCase (преобразует строку в буквы верхнего регистра).
String(N, S)	Возвращает строку длиной N символов, состоящую из символа, заданного первым символом в S. Например, String(5, "х") возвращает строку "ххххх".
158
Глава 6
Функция(аргумент)	Возвращает/действие
Trim(S)	Возвращает копию строки S после удаления начальных и конечных символов пробела из этой строки.
UCase(S)	Возвращает S со всеми символами нижнего регистра, преобразованными в символы верхнего регистра.
Несколько перечисленных в табл. 6.6 функций преобразования типа данных относятся также к манипулированию строками: Chr, Format, CStr, в частности.
Использование функций для манипулирования строками
Манипулирование строковыми данными является важной частью многих программ, особенно программ, которые взаимодействуют с пользователем. Интерактивные программы должны манипулировать строками по двум причинам: для формулировки сообщений, которые необходимо отображать для пользователя, и из-за того, что входные данные пользователя вводятся в вашу программу (посредством MsgBox) как строковые данные.
Чем лучше вы научитесь манипулировать строками, тем вероятнее, что вы будете способны отображать приемлемые, согласованные сообщения для пользователя вашей программы. Кроме того, чем лучше вы умеете манипулировать строками, тем вероятнее, что вы сможете успешно анализировать строки, вводимые пользователем вашей программы.
VBA имеет различные функции в качестве средств, помогающих манипулировать строковыми данными. В этом и следующем разделах описывается, как использовать наиболее важные строковые функции и некоторые из функций преобразования данных для выполнения как простых, так и сложных операций над строковыми данными в программах.
»
Удаление ненужных символов
Иногда строки в программе содержат ненужные символы пробелов в конце или в начале строки. Эти начальные и конечные пробелы появляются по разным причинам.
Один из наиболее распространенных случаев появления начальных или конечных пробелов — когда используется функция InputBox для получения данных ввода от пользователя. InputBox возвращает весь текст, вводимый пользователем, включая любые лишние символы пробела. Если пользователь вводит лишние символы пробела перед или после фактического значения ввода, функция InputBox возвращает эти символы как часть вводимой строки.
Другая распространенная причина начальных и конечных символов — когда используется содержимое строковой переменной фиксированной длины. Строка фиксированной длины всегда имеет одну и ту же длину, и VBA при необходимости дополняет данные, присвоенные этой строковой переменной (обычно конечными пробелами), чтобы заполнить объявленную длину строки. В результате всякий раз, когда используется строка фиксированной длины, возникает вероятность того, что она будет содержать конечные пробелы.
Посторонние начальные или конечные пробелы в строке могут вызвать различные проблемы: некоторые — только «косметические», другие — более серьезные. Когда строки транслируются для вывода на экран, лишние пробелы могут привести к большим промежуткам в тексте, при этом отображается неприемлемый и трудночитаемый текст. В других случаях посторонние начальные и конечные пробелы могут повлиять на сравнения строк, на сообщаемую длину строки и на некоторые другие факторы. Это может привести к тому, что строковое значение не будет использо
Использование функций Visual Basic
159
ваться в каком-либо другом выражении или процедура выдаст ошибочный результат. В любом из этих случаев может возникнуть серьезная проблема.
В VBA имеются три функции, специально предназначенные для удаления нежелательных начальных и конечных пробелов из строки. Первая функция — RTrim — удаляет символы пробела из правой части строки (конечные пробелы). Вторая функция — LTrim — удаляет символы пробела из левой части строки (начальные пробелы). Третья функция — Trim — удаляет как начальные, так и конечные пробелы из строки.
Эти функции на самом деле не изменяют строку; вы передаете строку, из которой должны быть вырезаны пробелы, как аргумент функции, и функция возвращает копию строки с удаленными лишними пробелами. Процедура в листинге 6.3 демонстрирует использование функций удаления пробелов из строки.
	Листинг 6.3. Демонстрация функций RTrim, LTrim и Trim
1 2 3 4 5 6 7 8 9	Sub TrimDemo() Dim ExSpace As String ExSpace = "	mad dog	" msg = "{" & ExSpace & "}" MsgBox ”{" & ExSpace & "}”, , "До изменения" MsgBox "{" & RTrim(ExSpace) &	, "Без правых пробелов" MsgBox "{" i LTrim(ExSpace) i	, "Без левых пробелов" MsgBox "{" & Trim(ExSpace) s	, "Без пробелов" End Sub
В строке 3 переменной ExSpace (объявленной в строке 2) присваивается строка " mad dog " (с начальными и конечными пробелами). В строке 4 используется функция MsgBox для отображения еще неизмененной строки ExSpace. Строковое выражение для аргумента MsgBox конкатенирует пару фигурных скобок вокруг строки ExSpace, чтобы показать, имеются ли начальные или конечные пробелы в строке. Строки 5-7 листинга 6.3 — каждая используют одну из трех функций для удаления начальных и конечных пробелов из строки ExSpace; каждая строка использует MsgBox для отображения результата функции удаления пробелов. Результат работы кода представлен на рис. 6.4.
Рис. 6.4
Диалоговые окна как результат выполнения кода листинга 6 3
{ mad dog}
Без правых пробелов
Без левых пробелов
OK
(mad dog }
Без пробелов
{mad dog}

Следует использовать функцию Trim для удаления начальных и конечных пробелбв из строк перед их сравнением; этим предотвращается влияние начальных и конечных пробелов на сравнение строк, что обычно не является существенным для пользователя, но имеет значение для VBA.
160
Глава 6
Определение длины строки
Часто бывает необходимо знать длину строки (количество символов находится в строке), особенно при форматировании сообщений для пользователя или при форматировании строковых данных, вводимых процедурой в рабочий лист Excel или документ Word. VBA имеет функцию Len, позволяющую получать длину строки. Следующий оператор показывает общий синтаксис для этой функции:
СИНТАКСИС
Len(VString}
VString — любое допустимое строковое выражение VBA. Следующий оператор показывает использование функции в операторе присваивания:
StrLen = Len ("VBA")	' возвращает 3
Как и ранее, строки фиксированной длины представляют особый случай. Поскольку строка фиксированной длины имеет всегда одну и ту же длину, функция Len всегда возвращает объявленную длину строки. Например, при объявлении FirstName в качестве строковой переменной, имеющей длину 20 символов, функция Len всегда возвращает 20 как длину строки в FirstName; даже если в переменной сохранено имя Bob, имеющее длину только 3 символа, все остальные символы из 20 являются символами пробела.
Обычно целью использования функции Len является определение того, сколько символов имеется в строке, исключая начальные или конечные пробелы. Вернемся к примеру с FirstName; если необходимо узнать фактическую длину имени, сохраненного в переменной, используйте оператор, подобный следующему:
NameLen = Len(Trim(FirstName))
В этом операторе функция Trim удаляет любые начальные или конечные пробелы из строки в переменной, а функция Len сообщает длину результирующей строки. Если FirstName содержит "Москва", то переменная NameLen будет иметь результатом значение 6.
Сравнение и поиск строк
В главе 5 было описано, как сравнивать строки, используя операторы сравнения, и объяснялось действие установок Option Compare Binary и Option Compare Text.
VBA имеет также две функции для сравнения строк. Первая функция — StrComp просто сравнивает две разные строки. При некоторых обстоятельствах лучше использовать StrComp вместо операторов сравнения (=, <, >) для сравнения строк, потому что StrComp позволяет указывать, следует ли выполнять бинарное или текстовое сравнение (независимо от установки Option Compare модульного уровня) для этого определенного сравнения.
Например, если необходимо, чтобы большинство строковых сравнений игнорировали регистр (верхний или нижний) символов при сравнении строк, добавьте оператор Option Compare Text к этому модулю. После этого можно выполнить конкретное сравнение строк, являющееся чувствительным к регистру: используйте VBA-функцию StrComp и задавайте сравнение с учетом регистра.
Использование функции StrComp
Общим синтаксисом для функции StrComp является выражение:
СИНТАКСИС
StrComp (Stnngl, String2 [, Compare])
Stringl и String2 — любые два строковых выражения, которые необходимо сравнить. Необязательный аргумент Compare может быть любой из следующих предопределенных констант:
Использование функций Visual Basic
161
	vbBinaryCompare — для сравнения двух строк с помощью бинарного (с учетом регистра) сравнения;
	vbTextCompare — для сравнения двух строк с помощью текстового (без учета регистра) сравнения;
	vbDatabaseCompare — имеет значение только в Microsoft Access; в этом случае строковое сравнение использует любой метод сравнения, установленный для текущей базы данных. При использовании константы vbDatabaseCompare в каком либо другом программном продукте VBA, а не в Access VBA, отображается сообщение об ошибке времени исполнения, констатирующее наличие недопустимого аргумента процедуры.
Если аргумент Compare опускается, StrComp использует текущую установку Option Compare. При выполнении StrComp сравниваются две строки с использованием заданного метода сравнения и возвращается одно из следующих значений:
	-1, если Stringl меньше String2
	0, если Stringl и String2 равны друг другу
	1, если Stringl больше String2
Процедура в листинге 6.4 демонстрирует функцию StrComp.
Листинг 6.4. Демонстрация функции StrComp
1	Sub Demo_STRComp()
2	Const Умолчание = " STRComp"
3	Dim СтрокаВвода As String
'	4 СтрокаВВода = InputBox(Prompt:="Введите некоторый текст:", _
— 5	Title:="Сравнение строк",
6	.	Default:= Умолчание)
7	MsgBox StrComp(СтрокаВвода, Умолчание, vbTextCompare)
8	End Sub
В строке 2 объявляется константа для использования в качестве текста по умолчанию в последующем операторе InputBox. В строке 3 объявляется строковая переменная СтрокаВвода для сохранения результата функции InputBox. Строки 4-6 являются одним оператором, вызывающим функцию InputBox для получения строки от пользователя. Вызов функции InputBox использует именованные аргументы и задает заголовок диалогового окна и предлагаемое значение по умолчанию. Результат функции InputBox присваивается переменной СтрокаВвода. Строка 7 содержит вызов функции StrComp; оператор использует MsgBox для вывода возвращаемого значения функции StrComp непосредственно на экран. В результате код определяет, принял ли пользователь текст по умолчанию или ввел отличную от этого текста строку.
Использование функции InStr
Другая VBA-функция сравнения строк, InStr, дает возможность определить, содержит ли одна строка другую строку. Эта функция полезна в ряде случаев. Например, используйте InStr, если необходимо определить, содержит ли введенная пользователем строка определенное слово. Другой пример: используйте InStr, если необходимо определить, содержит ли строка символы, не позволяющие преобразовать ее в число.
6 Программирование на VBA 2002
162
Глава 6
Синтаксис функции InStr:
СИНТАКСИС
InStr([Start, ] Stringl, String2 [, Compare])
Stringl и String2 — любые допустимые строковые выражения. InStr проверяет, содержится ли Stringl в String2. Необязательный аргумент Start является любым численным выражением; этот аргумент (если используется) указывает положение символа в Stringl, с которого должна начинаться проверка. Необязательный аргумент Compare определяет, должна ли InStr использовать двоичное или текстовое сравнение. Допустимыми значениями для аргумента Compare функции InStr являются те же предопределенные константы, которые используются функцией StrComp: vbBinaryCompare, vbTextCompare и vbDatabaseCompare.
Функция InStr возвращает число, обозначающее положение символа в Stringl, где было обнаружено String2; если InStr не находит String2 в Stringl, то она возвращает 0. Если Stringl (или String2) равно Null, то InStr возвращает Null.
Листинг 6.5 демонстрирует использование InStr.
Листинг 6.5. Демонстрация функции InStr
1	Sub Demo_InStr()
2	Const Умолчание = "InStr"
3	Dim СтрокаВвода As String
4	СтрокаВвода = InputBox(Prompt:“"Введите некоторый текст:",
5	Title: ^''Сравнение строк", __
б	Default:= Умолчание)
7	MsgBox InStr(1, СтрокаВвода, Умолчание, vbTextCompare)
8	End Sub
В строке 7 проверяется, содержится ли в строке СтрокаВвода строка, обозначенная константой Умолчание. Используется текстовое сравнение, указано начальное положение для поиска. InStr начинает поиск строки Умолчание с первого символа строки СтрокаВвода.
Разбиение строки на меньшие части
Во многих процедурах бывает необходимо разбить строку на составляющие части. Например, может понадобиться проанализировать вводимую пользователем строку, чтобы определить, содержит ли она более одного слова и, если содержит, разделить ее на отдельные слова. Примеры такой обработки строк встречаются в последующих главах.
функция Left
VBA имеет три функции для выделения подстрок из больших строк. (Под строка — это любая строка, которая является или может быть частью большей строки). Первая из них — это функция Left, возвращающая копию определенной части строки. Далее следует синтаксис функции Left:
СИНТАКСИС
Left(String, Length)
Здесь String — любое допустимое строковое выражение, a Length — любое численное выражение. Функция Left возвращает копию String, начиная
Использование функций Visual Basic
163
с первого символа и включая количество символов, заданных с помощью Length. Если Length является числом, большим, чем фактическая длина String, то Left возвращает все строковое выражение String.
В следующем операторе Left копирует первые 16 символов строки OldStr и возвращает эти символы кар строку; этот оператор присваивает результат функции Left переменной NewStr. Если OldStr содержит строку "В пустыне чахлой и скупой", то NewStr будет содержать "В пустыне чахлой" (после выполнения этого оператора).
NewStr = Left(OldStr, 16)
Функция Right
Другая VBA-функция подстроки — это функция Right. Далее следует синтаксис Right:
СИНТАКСИС	•
Right(String, Length)
Здесь String представляет любое допустимое строковое выражение, a Length — любое численное выражение. Функция Right возвращает копию String, начиная с последнего символа в строке и включая справа налево количество символов, указанное с помощью Length. Если Length является числом, большим, чем фактическая длина String, то Right возвращает все строковое выражение String. Функция Right всегда копирует символы от конца строки, действуя в направлении к началу строки. >
В следующем операторе функция Right возвращает последние восемь символов строки OldStr. Если переменная OldStr содержит строку "В пустыне чахлой и скупой", этот оператор сохраняет строку "и скупой" в переменной NewStr.
NewStr = Right(OldStr, 8)
В бизнес-приложениях функция Right может быть полезна, например, при выделении из некоторого ключевого поля номера накладной. Для того чтобы создать уникальный номер накладной, которая создается на складе с кодом, например, "1011" за определенную дату, можно сформировать номер как строку вида: '101101022001002'
Здесь первые четыре символа обозначают код склада, следующие восем символов содержат дату, а последние три — номер накладной, начиная с первой в текущий день. Если код склада всегда содержит четыре символа, то для быстрого (с смысле краткости кода) выделения любого значения из всей строки можно использовать функцию Mid (см. далее). Если же код склада может содержать различное количество символов, то удобнее пользоваться функцией Right.
Функция Mid
Можно извлечь подстроку из середины строки, а не из правой или левой ее части. Такая ситуация может возникнуть при извлечении отдельных слов из строки текста. Для извлечения подстроки из середины другой строки VBA имеет функцию Mid. Функция Mid имеет следующий общий синтаксис:
СИНТАКСИС
Mj,d (String, Start [, Length])
Здесь String — любое строковое выражение, тогда как Start и Length — это любые численные выражения. Функция Mid возвращает копию String, начи
164
Глава 6
ная с положения символа в String, задаваемого с помощью аргумента Start.
> Необязательный аргумент Length определяет количество копируемых в Mid символов из String. Если Start содержит большее число, чем фактическая длина String, то Mid возвращает пустую строку.
Следующий оператор показывает пример функции Mid:
NewStr = MidfOldStr, 10, 5)
Если переменная OldStr содержит строку "Беспечный сын природы”, то этот оператор сохраняет строку ” сын " в переменной NewStr.
Использование символов, которые нельзя ввести с клавиатуры
Иногда необходимо включить в строку какой-либо символ, для которого нет соответствующей клавиши на клавиатуре, например, букву греческого языка, символ для йены или символ авторского права.
Может потребоваться также включить какой-либо символ, который уже имеет особое значение для VBA, такой как символ кавычек ("). Вы не можете включать символы, подобные кавычкам, непосредственно в строку, потому что VBA всегда «подразумевает», что этот символ начинает или заканчивает строку. Следующий оператор, например, приводит к ошибке времени исполнения или ошибке синтаксиса:
MsgBox "This "cannot" work"
Хотя этот оператор может предназначаться для вывода на экран строки, VBA не может выполнить его. Поскольку кавычки (") указывают VBA на то, что литеральная строка либо начинается, либо заканчивается, VBA разбивает вышеприведенный аргумент MsgBox на три части: строку "This ", имя переменной cannot и еще одну строку " work".
Чтобы включить в строку символы, которые невозможно ввести с клавиатуры, или которые имеют особое значение для VBA, используйте VBA-функцию Chr. Функция Chr имеет следующий синтаксис:
СИНТАКСИС
Chr(Charcode)
Здесь Charcode — любое численное выражение, являющееся допустимым кодом для набора символов, используемого компьютером. Аргумент Charcode должен быть числом от 0 до 255. Как вы помните из обсуждения двоичного и текстового сравнения строк, компьютер сохраняет буквы во внутренней памяти как числа и использует схему, в которой каждый символ имеет собственный уникальный номер. Функция Chr принимает код отдельного символа в качестве аргумента и возвращает строку, содержащую соответствующий этому коду символ.
Чтобы просмотреть список кодов, которые распознает VBA, и соответствующих им символов, откройте справочную систему VBA и найдите раздел Character sets. Например, при поиске кода символа кавычек (") обнаруживаем, что кавычки имеют код 34. Используя функцию Chr для предоставления кавычек, следующий оператор отображает диалоговое окно, приведенное на рис. 6.5:
MsgBox Chr(34) & "Кто здесь?" & Chr(34) & " - " & Chr(34) & "Я странник!" & Chr(34) & " - был ответ"
Можно также управлять форматированием отображаемых сообщений, добавляя специальные символы к строкам. Один из символов, которые можно получить с помощью функции Chr — это символ возврата каретки (код символа 13). Это — символ, генерируемый компьютером всякий раз при нажатии клавиши Enter на
Использование функций Visual Basic
165
клавиатуре и указывающий на начало новой строки при использовании его в тексте. Как показано на рис. 6.6, следующий оператор использует Chr для добавления символа возврата каретки в конкатенированную строку так, чтобы полученное диалоговое окно содержало несколько строк.
Рис. 6.5
Пример использования функции Chr
Microsoft Word
'Кто здесь’" - "Я странник!" - был ответ
Диалоговое окно, показанное на рис. 6.6, может быть получено с помощью следующего (одного!) оператора:
MsgBox "Выхожу один я на дорогу;" & Chr(13) & _
"Сквозь туман кремнистый путь блестит;" & Chr (13) & _
"Ночь тиха. Пустыня внемлет богу," & Chr (13) & _
"И звезда с звездою говорит." & Chr (13) & Chr (13) & _
"	М.Ю. Лермонтов" & Chr (13)
Рис. 6.6
Использование функции Chr с константой 13 в качестве параметра окрывает возможности форматирования текста в окне функции MsgBox
Microsoft Word
Выхожу один я на дорогу.
Сквозь туман кремнистый путь блестит, Ночь тиха Пустыня внемлет богу, И звезда с звездою говорит
МЮ Лермонтов
Поскольку символы, используемые для начала новой строки, являются очень важными при форматировании сообщений и других строковых данных, которыми манипулируют VBA-процедуры, VBA имеет несколько предопределенных констант для этих символов, чтобы не было необходимости использовать функцию Chr:
	vbCr — символ возврата каретки (код символа 13). Эта константа является эквивалентом выражения: Chr(13). Включение vbCr в строку приводит к тому, что VBA и большинство приложений Windows начинают новую строку при выводе строки на экран. В некоторых случаях, например, при пересылке строки на принтер, символ возврата каретки просто приводит к перемещению курсора в начало текущей строки без перехода к следующей строке.
	vbLf — символ смещения на одну строку (код символа 10). Эта константа эквивалентна выражению: Chr(10). Включение vbLf в строку приводит к тому, что VBA и большинство приложений Windows начинают новую строку при отображении строки. В некоторых случаях, например, при пересылке строки на принтер, символ смещения на одну строку просто приводит к перемещению курсора к следующей строке без возврата к левому краю области печати.
	vbCrLf — символ возврата каретки/смещения на одну строку; эквивалентен выражению: Chr(13) & Chr(10). Помещение этого символа в строку приводит к тому, что VBA начинает новую строку при отображении строки. Например, при пересылке текста на принтер или для текстовых файлов DOS-формата, необходимо использовать vbCrLf для перемещения курсора к новой строке и к левому краю области печати.
	vbNewLine представляет символ(ы), используемый при создании новой строки для программной платформы, в которой выполняется ваша процедура
166
Глава 6
VBA. Применяйте константу vbNewLine в процедурах, которые должны использоваться либо в Windows, либо в Macintosh-версиях MS приложений.
	vbTab — символ табуляции (код символа 9). Этот символ создается при нажатии на клавишу Tab на клавиатуре. Константа vbTab эквивалентна выражению: Chr(9). Можно включать символы табуляции в строки для выравнивания данных в столбцах.
С учетом вышесказанного последний оператор можно переписать в виде:
MsgBox "Выхожу один я на дорогу;" & vbCr &
"Сквозь туман кремнистый путь блестит," & vbCr & _
"Ночь тиха. Пустыня внемлет богу," & vbCr & "И звезда с звездою говорит." & vbCr & vbCr & vbTab & vbTab & "М.Ю. Лермонтов" 4 vbCr	’
Форматирование значений данных
Хотя VBA может автоматически преобразовывать любой тип данных в строку для отображения с помощью функции MsgBox или для вставки в рабочий лист Excel (документ Word или соответствующий объект другого приложения), формат данных, который выбирает VBA, может не совпадать с желаемым.
При преобразовании числа в строку VBA не добавляет в строку разделитель тысяч, символы доллара или другое числовое форматирование. Кроме того, если число очень большое или очень малое, VBA создает строку, представляющую это число в экспоненциальном формате. Например, VBA преобразует число 3145.25 в строку "3145.25". Если это число представляет сумму в долларах, может оказаться предпочтительнее преобразовать его в строку, содержащую символ доллара и разделитель тысяч: "$3,145.25".
Аналогично, при преобразовании дат VBA всегда использует короткий формат даты и времени, используемый операционной системой компьютера, и всегда отображает и дату, и время. Вы можете использовать другой формат даты или времени или отображать только дату или только время.
Для получения почти любого формата дат при преобразовании чисел или дат в строки можно использовать функцию Format; можно даже использовать функцию Format для форматирования строковых данных в соответствии с определенным шаблоном. Можно также создавать пользовательские экранные форматы, если вам необходимо, чтобы данные появлялись в каком-либо особом формате.
VBA-функция Format идентична функции Format в Excel и использует те же символы-заполнители форматирования данных, что Excel и Access.
Синтаксис оператора Format следующий (приведен из справочной системы VBA):
г СИНТАКСИС
Format[Expression[, Format[, Firstdayofweek[, Firstweekofyear]]])
Здесь аргументы означают:
i Expression	любое допустимое выражение (обязательный);
I Format	допустимое выражение именованного или определенного пользователем формата (необязательный);
Firstdayofweek	константа, которая определяет первый день недели (необязательный);
Firstweekofyear	константа, которая определяет первую неделю года (необязательный).
Использование функций Visual Basic
167
Для аргументов Firstdayofweek и Firstweekofyear в VBA имеются именованные константы, о которых можно узнать из справочной системы VBA в разделе Date Constants.
Чтобы использовать функцию Format, можно либо задать предопределенный формат (называемый именованным форматом (named format)), либо создать образ определенного формата, используя комбинации особой группы символов, называемых символами заполнителями (placeholders). Используйте образ, который создается с помощью символов-заполнителей, если ни один из именованных форматов не отвечает вашим запросам. Примером этих методов использования функции Format могут быть следующие операторы MsgBox (каждый отображает одно и то же диалоговое окно, показанное на рис. 6.7); первый оператор использует именованный формат, второй — образ с символами-заполнителями:
MsgBox Format(#2/27/1976#, "Long Date")
MsgBox Format(#2/27/1976#, "dd mmmm yyyy")
Рис. 6.7
Использование функции Format для изменения строкового формата значения даты
27 February 1976
Friday February 27, 1976
Microsoft Word
OK
Внимательный читатель все же заметит, что в русской версии Window 98 сообщения в окнах немного отличаются.
Табл. 6.7 содержит доступные именованные форматы и объясняет их действие.
Таблица 6.7. Именованные форматы для использования с функцией Format
Именованный формат	Действие
General Date	Форматирует информацию о дате и времени в последовательное число даты, используя установки формата даты и времени для вашего компьютера. То же, что VBA-преобразование по умолчанию последовательных дат в строки.
Long Date	Форматирует в последовательной дате только часть, содержащую дату, используя установки компьютера для Long-формата даты.
Medium Date	Форматирует в последовательной дате только часть, содержащую дату, используя установки компьютера для Medium-формата даты.
Short Date	Форматирует в последовательной дате только часть, содержащую дату, используя установки компьютера для Short-формата даты.
Long Time	Форматирует в последовательной дате только часть, содержащую время, используя установки компьютера для Long-форма-та времени.
Medium Time	Форматирует в последовательной дате только часть, содержащую время, используя установки компьютера для Medium-формата времени.
Short Time	Форматирует в последовательной дате только часть, содержащую время, используя установки компьютера для Short-формата времени.
168
1
Глава 6
Именованный формат	Действие
General Number	Форматирует число в строку без каких-либо особых символов. Действие такое же, как VBA-преобразование по умолчанию чисел в строки.
Currency	Форматирует число с символом денежной единицы, разделителем тысяч и только двумя десятичными разрядами. Символ денежной единицы и десятичный разделитель определяются локальными установками Windows.
Fixed	Форматирует число так, чтобы всегда была, по крайней мере, одна цифра перед десятичным разделителем и, по крайней мере, две цифры после него.
Standard	Форматирует число с разделителем тысяч так, чтобы была, по крайней мере, одна цифра перед десятичным разделителем и, по крайней мере, две цифры после него.
Percent	Форматирует число как процентное отношение, умножая его на 100 и добавляя символ процента. Например, 0.21 возвращается как 21%.
Scientific	Форматирует число в обычный экспоненциальный формат.
Yes/No	Использование этого формата приводит к тому, что функция Format возвращает строку "Да" ("Yes"), если форматируемое число ненулевое, и возвращает строку "Нет" ("No") для любого нулевого значения. Этот именованный формат наиболее часто используется со значениями типа Boolean.
True/False	Использование этого формата приводит к тому, что функция Format возвращает строку "Истина" ("True"), если форматируемое число ненулевое, и строку "Ложь" ("False") для любого нулевого значения. Этот именованный формат наиболее полезен со значениями типа Boolean.
On/Off	Использование этого формата приводит к тому, что функция Format возвращает строку "Вкл" ("On"), если форматируемое число ненулевое, и строку "Выкл" ("Off”) для любого нулевого значения. Наиболее часто используется со значениями Boolean.
Форматы long, medium и short date и time можно изменять посредством Панели управления (Windows Control Panel). Можно также изменять символы, используемые для разделителя тысяч и десятичного разделителя (на Панели управления).
Если вам необходимо создавать пользовательские форматы для чисел, дат или времени, нужно создать строку, содержащую символы-заполнители, для задания образа форматирования, который должна будет использовать функция Format при преобразовании значений в строку. В табл. 6.8 приведены пользовательские символы-заполнители, применяемые для создания образов форматов с применением функции Format. Кроме того, в табл. 6.8 используется как пример численное значение 1234,5. Полужирным шрифтом выделены символы-заполнители, которые вводятся из окружающего текста.
Использование функций Visual Basic
169
Таблица 6.8. Символы-заполнители для создания пользовательских форматов
Символ-заполнитель	Действие
0	Цифровой символ, отображает цифру, если таковая находится в этой позиций, или 0, если — нет. Можно использовать символ 0 для отображения начальных нулей для целых чисел и конечных нулей в десятичных дробях; 00000.000 отображает 00124,500.
#	Цифровой символ, отображает цифру, если таковая находится в этой позиции, иначе — не отображает ничего. Символ-заполнитель # эквивалентен 0, кроме того, что начальные и конечные нули не отображаются; #####.### отображает 1234,5.
$	Отображает знак доллара; $###,###.00 отображает $1 234,50.
	Десятичный символ-заполнитель, отображает десятичную точку в обозначенной позиции в строке символов-заполнителей 0; #.##.## отображает 1234,5
%	Символ процента, умножает значение на 100 и добавляет знак процента в позицию, указанную символами-заполнителями 0; #0.00% отображает число 0.12345 как 12,35% (12,345 округляется до 12,35).
, (запятая)	Разделитель тысяч, добавляет запятые как разделители тысяч в строках символов-заполнителей 0 и #. ###,###,###.00 отображает 1 234,50.
Е—, е—	Отображает значения в экспоненциальном формате со знаком порядка только для отрицательных значений; #.####Е—00 отображает 1,2345Е03; 0,12345 отображается как 1,2345Е-01.
Е+, е+	Отображает значения в экспоненциальном формате со знаком порядка для положительных и отрицательных значений; #.####Е+00 отображает 1,2345Е+03.
/	Отделяет день, месяц и год для форматирования значений дат. mm/dd/yy отображает 06/06/97. Символы "/" можно заменять на символы дефиса для отображения как 06-06-97.
ш	Указывает, как отображать месяцы в датах; m отображает 2, mm — 02, mmm — фев, mmmm — Февраль.
d	Указывает, как отображать дни в датах; d отображает 1, dd отображает 01, ddd — Пт, dddd — пятница.
У	Отображает день года как число от 1 до 366.
УУ	Указывает, как отображать годы в датах; уу отображает 99, УУУУ — 1999.
q	Отображает квартал года как число от 1 до 4.
W	Отображает день недели как число (1 — это воскресенье).
WW	Отображает неделю года как число от 1 до 54.
: (двоеточие)	Отделяет часы, минуты и секунды в значениях формата времени; hh:mm:ss отображает 02:02:02.
h	Указывает, как отображать часы; для значения времени 02:01:38 h отображает 2, hh отображает 02.
170
Глава 6
Символ-заполнитель	Действие
п	Минутный символ-заполнитель для времени; для значения времени 02:01:08 п отображает 1, а пп отображает 01.
S	Секундный символ-заполнитель для времени; для значения времени 02:01:08 s отображает 8, и ss отображает 08.
АМ/РМ	Отображает время в 12-часовом формате времени с добавленными AM и PM; h:nn АМ/РМ отображает 4:00 РМ. Альтернативные форматы включают am/pm, А/P и а/р.
@	Символьный заполнитель, отображает пробел, если не имеется соответствующего символа в форматируемой строке. @@@@ отображает строку Hi с двумя начальными пробелами, (порядок заполнения по умолчанию — справа налево).
<	Отображает все символы в верхнем регистре.
>	Отображает все символы в нижнем регистре.
При использовании функции Format для форматирования строк и чисел можно создавать дополнительные секции в образе формата, чтобы изменять формат отображения в соответствии с форматируемым значением. Секции в образе формата разделяются точкой с запятой (;). Например, следующий образ содержит две секции и форматирует отрицательные числа иначе, чем положительные:
$###,###Л#0.00;$(###,###,##0.00)
Вышеприведенный образ форматирует число 1234567,89 как $1 234 567.89 и форматирует —1234567,89 как $(1 234 567.89).
Можно для форматирования строки иметь две секции в образе формата. Если образ формата содержит только одну секцию, этот образ применим ко всем форматируемым строкам. Если образ формата содержит две секции, первая секция применима к строковым данным, а вторая — к значениям Null и строкам нулевой длины (то есть к строкам, которые не содержат символов, представленных с помощью ""). Рассмотрим следующий оператор, отображающий результат функции Format, используемый с образом из двух частей для строк.
MsgBox Format(strData, " (@@@) - @@@ - @@@@; не номер телефона”)
Приведенный выше оператор отображает (510) - 555 - 1212 в результирующем окне сообщения, если переменная strData содержит "5105551212". Если переменная strData содержит строку нулевой длины (""), то предыдущий оператор отображает в окне сообщения строку «не номер телефона».
Для форматирования числовых значений можно иметь до четырех различных секций в образе формата. Первая секция используется для положительных чисел, вторая — для отрицательных чисел, третья — для нулевых значений, а четвертая — для значений Null. Следующий образ формата содержит четыре секции:
$###,###,##0.00; $(###,###,##0.00); 0.00; "Null value"
Приведенный выше образ формата форматирует отрицательные числа с круглыми скобками, указывает, что нулевые значения должны быть показаны как 0.00, и возвращает текстовое сообщение, если форматируемое значение равно. Null. Этот образ формата форматирует число 1234567,89 как строку "$1 234 567.89". Число —1234567,89 форматируется в строку "$(1 234 567.89)". Значение 0 форматируется в строку "0.00", тогда как значение Null форматируется в строку "Null value".
Кроме общей функции форматирования, вы можете использовать функции специального форматирования, приведенные в таблице 6,9 и в Приложении Г.
Использование функций Visual Basic
171
Таблица 6.9. Функции специального форматирования
Функция	Назначение
FormatCurrency(E [, N [, I [,U [, G]]]])	Возвращает выражение, отформатированное как денежное (валютное) выражение с использованием значения, заданного на вкладке Денежная единица окна Свойства: Язык и стандарты, доступного из Панели управления.
FormatDateTime(D [,N])	Возвращает выражение, отформатированное, как дата или время.
FormatNumber(E [,N [, I [, U [, G]]]])	Возвращает выражение, отформатированное, как число.
FormatPercent(E [, N [, I [, U [, G]]]])	Возвращает выражение, отформатированное, как процентное отношение (умноженное на 100) с конечным знаком процента ( %).
Функция FormatCurrency возвращает выражение, отформатированное как денежное (валютное) выражение с использованием значения, заданного на вкладке Денежная единица окна Свойства: Язык и стандарты, доступного из Панели управления.
Синтаксис функции FormatCurrency следующий (приведен из справочной системы VBA):
СИНТАКСИС
FormatCurrency(Expression[, NumDigitsAfterDecimal [, IncludeLeadingDigit [, UseParensForNegativeNumbers [, GroupDigits]]]])
Здесь аргументы означают:
Expression	Выражение для фоматирования (обязательный).
NumDigitsAfterDecimal	Численное значение, определяющее количество отображаемых знаков справа от десятичной точки. Значение по умолчанию для этого аргумента равно -1, что означает использование региональных настроек (необязательный).
IncludeLeadingDigit	Константа трех состояний, определяющая, следует ли отображать ведущий ноль для дробных чисел (необязательный).
UseParensFor- NegativeNumbers	Константа трех состояний, определяющая, следует ли помещать отрицательные значения внутри круглых скобок (необязательный).
GroupDigits	Константа трех состояний, определяющая, группировать ли цифры с помощью ограничителей, заданных региональными настройками (необязательный).
Агументы IncludeLeadingDigit, UseParensForNegativeNumbers и GroupDigits могут принимать только значения констант: vbTrue, vbFalse и vbUseDefault (True, False и Использовать региональные настройки компьютера).
В качестве примера приведем код небольшой программы и результат ее работы (рис. 6.8) в виде последовательно выдаваемых на экран диалоговых окон.
172
Глава б
Листинг 6.6. Демонстрация функции Formatcurrency
1	Sub MyMacroO
2	'Пример использования функции FormatCurrency
3	Dim MyDoublel As Double,	MyDouble2 As Double
4	MyDoublel = -22323.123
5	MyDouble2 = 0.000123
6	*
7	MsgBox	Formatcurrency(MyDoublel,	7)
8
9	MsgBox	Formatcurrency(MyDouble2,	7,	vbTrue)
10	MsgBox	Formatcurrency(MyDouble2,	7,	vbFalse)
11
12	MsgBox	Formatcurrency(MyDoublel,	7,	vbTrue,	vbTrue)
13	MsgBox	Formatcurrency(MyDoublel,	7,	vbTrue,	vbFalse)
14	MsgBox	Formatcurrency(MyDoublel,	7,	vbTrue,	vbTrue, vbTrue)
15
ЯИДВИ1
Рис. 6.8
Пример использования функции Formatcurrency
$0 0001230
ок
16 End Sub
Синтаксис функции FormatDateTime следующий (взят из справочной системы VBA):
СИНТАКСИС
FormatDateTime(Date[,NamedFormat])
Здесь аргументы означают:
Date	Дата для фоматирования (обязательный).
NamedFormat	Чиленное значение, указывающее, необходимый формат. Если опущен, используется vbGeneralDate (необязательный).
Аргумент NamedFormat может принимать следующие значения:
Константа	Значение	Описание
vbGeneralDate	0	Отображать дату и/или время. Если в аргументе Date имеется часть даты, дата отображается в коротком формате. Если в аргументе Date имеется часть времени, она отображается в длинном формате.
Использование функций Visual Basic
173
Константа	Значение	Описание
vbLongDate	1	Отображать дату с использованием длинного формата, установленного на компьютере в региональных настройках.	|
vbShortDate	2 *	Отображать дату с использованием короткого 1 формата, установленного на компьютере в региональных настройках.	|
vbLongTime	3	Отображать время с использованием временного формата, установленного на компьютере	: в региональных настройках.
vbShortTime	4	Отображать время с использованием формата 24-hour (hh:mm).
В качестве примера приведем код небольшой программы и результат ее работы (рис. 6.9) в виде последовательно выдаваемых на экран диалоговых окон.
Листинг 6.7. Демонстрация функции FormatDateTime
1	Sub MyMacroO
2	' Пример использования функции FormatDateTime
3	Dim MyDate As Date
4	MyDate = Now()
5
6	MsgBox	FormatDateTime(MyDate,	vbGeneralDate)
7	MsgBox	FormatDateTime(MyDate,	vbLongDate)
8	MsgBox	FormatDateTime(MyDate,	vbShortDate)
9	MsgBox	FormatDateTime(MyDate,	vbLongTime)
10	MsgBox	FormatDateTime(MyDate,	vbShortTime)
11
12	End Sub
Microsoft Word		Microsoft Word |X(		Microsoft Word <X|		Microsoft Word JX1		Microsoft Word
3/1/2003 6:05:46 PM		Saturday, March 01, 2003 ILj*ZJ		3/1/2003 |f bk |		6-05.46 PM |r ok |		18.05 If. "<%. 1
								
Рис. 6.9. Пример использования функции FormatDateTime
Синтаксис функции FormatNumber следующий (приведен из справочной системы VBA):
СИНТАКСИС
FormatNumber(Expression[,NumDigitsAfterDecimal [, IncludeLeadingDigit [,UseParensForNegativeNumbers [, GroupDigi ts] ] ] ])'
Здесь аргументы означают то же, что и в функции FormatCurrency.
В качестве примера приведем код небольшой программы и результат ее работы (рис. 6.10) в виде последовательно выдаваемых на экран диалоговых окон.
174
Глава 6
Листинг 6.8. Демонстрация функции FormatNumber
1	Sub MyMacrot)
2	' Пример использования функции FormatNumber
3	Dim MyDouble As Double
4	MyDouble = 112233.4455
5
6	MsgBox	FormatNumber(MyDouble)
7	MsgBox	FormatNumber(MyDouble,	vbFalse)
8	MsgBox	FormatNumber(MyDouble,	vbTrue)
9	MsgBox	FormatNumber(MyDouble,	, vbFalse)
10	MsgBox	FormatNumber(MyDouble,	, vblrue)
11	MsgBox	FormatNumber(MyDouble,	, , vblalse)
12	End Sub
Рис. 6.10
Пример использования
функции FormatNumber
Microsoft Word SI Microsoft Word *1 Microsoft Word
112,233 45
112,233 45
112,233 45
OK
OK
Синтаксис функции FormatPercent следующий (приведен из справочной системы VBA):
• СИНТАКСИС • V- ’	•
FormatPercent(Expression[,NumDigitsAfterDecimal [, IncludeLeadingDigit [,UseParensForNegativeNumbers [, GroupDigits]]]])
Здесь аргументы означают то же, что и в функции FormatCurrency.
В этой главе приведены не все функции, которые имеются в VBA. В VBA есть функции, которые позволяют «общаться» с другими приложениями, получать информацию об ошибках времени исполнения, получать информацию о массивах и манипулировать объектами различных host-приложений в Word и Excel. Некоторые из них описываются в других главах.
Использование функций host-приложений
Кроме функций, встроенных в Visual Basic for Applications, из кода VBA доступны некоторые функции host-приложения VBA. (Помните, что host-приложение — это приложение, в котором разрабатываются процедуры VBA такие, как Word, Excel, PowerPoint, Outlook, или FrontPage).
Специфические функции host-приложения, доступные для VBA, зависят от определенного host-приложения, в котором выполняется работа.
В Excel, например, имеются различные функции, выполняющие математические, логические, финансовые и статистические операции над данными в рабочих листах. Многие (хотя и не все) из этих функции Excel доступны из кода VBA.
Использование функций Visual Basic
175
Функции host-приложения, доступные для VBA, не являются частью VBA, они являются частью host-приложения. Функции рабочих листов Excel, например, не являются частью языка программирования VBA; они являются частью host-приложения Excel. Не каждое host-приложение VBA содержит функции, которые можно использовать в VBA. Функции, доступные для VBA в одном host-приложении, могут не быть доступными в другом. Если вы намереваетесь писать процедуры VBA, которые могут выполняться любым host-приложением, не используйте функции из host-приложения, потому что они могут не быть доступными во всех приложениях. Например, если необходимо написать процедуру для использования в Word, Excel, Access или Microsoft Project, не используйте функций Excel в операторах VBA.
Чтобы использовать функцию, принадлежащую какому-либо host-приложению, обращайтесь к функции посредством программного объекта (Application). Объект Application VBA представляет host-приложение и все его ресурсы. (Объекты более подробно описываются далее.)
Помимо нескольких функций, преобразующих различные измерения набора текста в дюймы и наоборот, Word не имеет функций приложений, доступных в VBA. По этой причине в данной главе основное внимание при объяснении использования функций host-приложений уделяется использованию функций host-приложений в Excel.
Более вероятно, что вы будете использовать функции host-приложения в Excel, поскольку Excel разработан специально для манипулирования числовыми данными в формате рабочих листов. В результате Excel содержит много функций для использования в формулах рабочих листов. Функции рабочих листов Excel применяются для выполнения таких задач, как нахождение суммы целого столбца цифр, для выполнения финансовых вычислений (например, нахождение текущей величины займа) и для выполнения статистического анализа данных.
Хотя многие математические функции Excel дублируют математические функции VBA, Excel содержит намного больше специализированных статистических и финансовых функций, чем VBA. При программировании Excel-операций в Excel VBA может понадобиться использовать многие из функций рабочих листов, являющихся частью Excel.
В качестве примера следующий оператор использует Excel-функцию Мах, возвращающую самое большое число в ее списке аргументов:
MsgBox Application.Мах(9, 1, 3, 2)	' Отображает 9
В этом операторе обратите внимание на то, что за словом Application следует точка (.) и затем — имя функции Мах без пробелов. Эта точка, называемая точкой-разделителем (dot separator), указывает на то, что оператор ссылается на функцию Мах, которая является частью объекта Application. При использовании функций host-приложения в операторах VBA необходимо включать ключевое слово Application и точку-разделитель перед именем каждой функции. Например, чтобы использовать какие-либо функции рабочих листов Excel в операторах VBA, необходимо включать ключевое слово Application и точку-разделитель (.) перед именем каждой функции Excel.
Результат функции Excel нельзя игнорировать. Необходимо всегда включать круглые скобки в вызов функции Excel и всегда каким-либо образом использовать результат функции: как значение в выражении, аргумент для другой функции или процедуры или в операторе присваивания.
Если вы опытный пользователь рабочих листов Excel, вы могли уже заметить, что Excel имеет много функций, имеющих те же имена, что и некоторые функции, перечисленные в табл. 6.3-6.6. Эта ситуация может также наблюдаться и в других host-приложениях: host-приложение имеет функции, имена которых дублируют имена функций, имеющихся в VBA,
176
Глава 6
Поскольку необходимо всегда указывать ключевое слово Application, когда используется функция host-приложения, то не бывает неясно для VBA или пользователя, на какую функцию (VBA или приложения) ссылается оператор. Следующий фрагмент кода, например, показывает два оператора в Excel VBA:
Rslt = Log(AnyNum)
Rslt = Application.Log(AnyNum)
Первый оператор вызывает VBA-функцию Log; второй'— вызывает Excel-функцию LOG. Чтобы использовать VBA-версию функции, просто пишите имя функции; чтобы использовать версию функции host-приложения, включайте ключевое слово Application.
Функции host-приложений, имеющие те же имена, что и функции VBA, не обязательно выполняют те же самые задачи и выдают те же самые результаты. Например, Excel-функция LOG отличается от VBA-функции Log, и эти функции возвращают разные ответы: Excel-функция LN — это функция, совпадающая с действием VBA-функции Log. Внимательно изучите действие и результат функции host-приложения перед тем, как использовать ее вместо функции VBA, в противном случае процедуры могут выдавать ошибочные результаты.
Не каждая функция host-приложения доступна VBA. Например, некоторые функции Excel, дублирующие функции VBA, недоступны, потому что в этом нет смысла. Конкретнее, Excel-функции Date, Year, Month, Day, Hour, Minute и Second дублируют VBA-функции Date, Year, Month, Day, Hour, Minute и Second как по своему действию, так и по назначению. Никакая из этих функций Excel недоступна для VBA. Иногда некоторые функции host-приложений недоступны для VBA независимо от того, дублируют они функции VBA или — нет.
Если вы не уверены, доступна ли определенная функция host-приложения для VBA, используйте Object Browser, чтобы проверить, включает ли список Members (Компонент) эту функцию, при выбранном Application в списке Classes (Классы) и при выбранном host-приложении в списке Project/Library (Проект/ Библиотека). Если нужной функции нет в списке, то она недоступна для VBA.
Чтобы узнать, какие функции имеются в Excel (или любом другом приложение), и узнать, каково назначение и как использовать эти функции, обращайтесь к справочной системе и ищите раздел для слова functions.
В заключение отметим очень полезное дополнительное свойство функции InputBox приложения Excel, которого нет в VBA. Дело в том, что InputBox в Excel имеет необязательный параметр Туре, задающий тип вводимого значения. Это можно использовать в качестве дополнительного контроля вводимой информации.
Параметр Туре может принимать следующие значения:
Значение	Что означает
0	Формула
1	Число
2	Текст (строка)
4	Логическое значение (True или False)
8	Ссылка на ячейку, как объект диапазона
16	Значение ошибки, такое как #N/A
64	Массив значений
Вы можете использовать в качестве аргумента Туре сумму доступных значений. Например, для ввода как текстовых, так и числовых значений можно задавать значение 1+2.
Глава 7
Создание и использование функций и функций-процедур
Из шестой главы вы узнали, что такое функция и как использовать встроенные функции VBA и host-приложений VBA, таких как Excel. Из этой главы вы узнаете, как создавать собственные пользовательские функции, как работать с ними в host-приложениях VBA. В частности, вы узнаете, как сделать так, чтобы ваши собственные функции были доступны рабочим листам Excel.
Функции-процедуры и определенные пользователем функции
Перед тем как начать писать собственные функции, вам необходимо ознакомиться с терминологией и понятиями, используемыми при обсуждении создания функций в VBA.
Функция-процедура (или функция) — это особый вид процедуры VBA, возвращающей результат. Пользовательские функции-процедуры, как и встроенные функции VBA, могут иметь необязательные и именованные аргументы. Функции можно использовать для обеспечения значениями выражений (присваивания) или в качестве аргументов других функций и процедур. Создание новой функции состоит из написания программных операторов, которые определяют:
1)	аргументы, используемые функцией;
2)	действия, выполняемые функцией;
3)	значение, возвращаемое функцией.
Для того чтобы можно было использовать ваши'функции в Excel, необходимо выполнять некоторые дополнительные правила (ограничения).
Word не имеет встроенных функций, которые использовались бы подобно Excel-функциям рабочих листов. Word дает возможность вставлять в документ в виде полей информацию различных типов данных, таких как текущая дата и время, имя документа, оглавление и так далее. Word не содержит функций для выполнения статистических вычислений или других аналитических задач, для чего и предназначен Excel. Следовательно, функции, создаваемые с помощью VBA, имеют различное применение в Excel и Word; В Excel можно использовать функции VBA для расширения коллекции встроенных функций рабочих листов. Другие host-приложения VBA, такие как Access, также позволяют применять создаваемые вами VBA-функции для расширения и улучшения встроенной коллекции функций.
С «точки зрения» Excel используемые им функции-процедуры VBA, являются определенными пользователем функциями (user-defined functions). Этот термин позволяет отличать функции, написанные пользователем, от встроенных функций Excel. Хотя все определенные пользователем функции являются также функциями-процедурами, не все функции-процедуры отвечают требованиям определенной пользователем функции.
Функция-процедура — это наиболее общий термин для создаваемых пользователем функций; термин «определенная пользователем функция» описывает определенный тип функции-процедуры, который может использовать Excel. Нельзя
178
Глава 7
использовать функцию-процедуру, которая не отвечает требованиям определенной пользователем функции в формулах рабочих листов Excel; можно использовать такие функции только в операторах ваших собственных процедур. Далее в этой главе будет использоваться термин «функция» вместо «функция-процедура», когда будет понятно, о чем идет речь.
Создание функций-процедур
> Для записи функции-процедуры нельзя использовать макрорекордер, хотя можно редактировать записанный рекордером макрос и превращать его в функцию-процедуру.
Написание функции-процедуры
Функции-процедуры очень похожи на процедуры VBA, которые вы уже умеете записывать. Основное различие между функцией-процедурой и другими процедурами, помимо того, что функции возвращают значение, а процедуры — нет, состоит в том, что вместо ключевых слов Sub и End Sub, с которыми вы уже знакомы, в функции-процедуре используются ключевые слова Function и End Function.
Функция-процедура имеет следующий синтаксис:
СИНТАКСИС
Function Name([Arglist]) [As Type]
' VBA Statements
[Name - expression]
End Function
Каждая функция-процедура начинается ключевым словом Function, за которым следует имя функции, Name представляет имя, выбранное для этой функции. При написании имен функций необходимо соблюдать те же правила, что и при написании имен других идентификаторов в VBA: они должны начинаться с буквы, не могут содержать пробелов или каких-либо символов арифметических, логических операторов или операторов отношения и не могут дублировать ключевые слова VBA.
После имени функции следует список ее аргументов, который заключается в круглые скобки. Здесь Arglist представляет список аргументов функции и является необязательным.
Туре — любой тип возвращаемого значения функции. Если только не определяется иначе, результат, который возвращает функция-процедура, имеет тип Variant. Как вы узнали ранее, значения, сохраняемые или обрабатываемые как тип Variant, занимают больше памяти, чем любой другой тип данных, и на их обработку уходит больше времени.
Следует задавать тип данных результата функции по тем же причинам, по каким задается тип переменных и констант: для ускорения выполнения кода, более эффективного использования памяти, получения более легкого и понятного кода и для нахождения ошибок программирования (при этом необходимо хорошо знать правила преобразования типов в VBA).
Необязательный элемент синтаксиса Name = expression представляет присваивание функции (function assignment), которое указывает VBA, какое значение должна возвращать функция. Хотя эта часть функции является необязательной, следует всегда включать оператор присваивания в функции-процедуры. Наконец, объявление функции заканчивается ключевыми словами End Function.
Создание и использование функций и функций-процедур
179
Даже если функция не имеет аргументов, как VBA-функции Now, Date и Time, в объявлении функции необходимо использовать круглые скобки. Например, можно написать функцию-процедуру, возвращающую имя файла, содержащего текущую рабочую книгу, так, чтобы можно было вставлять имя файла в ячейку рабочего листа. Такой функции не нужны аргументы, ей не требуется никакая внешняя информация для выполнения работы, и она будет иметь подобное объявление:	•
Function ThisBookName()
Обычно функция предназначается для выполнения некоторого вычисления или другого манипулирования определенными данными и для возвращения результата этого манипулирования. Как вы уже знаете, информация встроенным функциям VBA передается заданием значений в списке аргументов функции. При объявлении функции-процедуры необходимо указывать имя каждого аргумента, передаваемого функции; имена аргументов в списке следует отделять друг от друга запятой и писать в соответствии с правилами, применяемыми к любому идентификатору VBA.
Имена, предоставляемые пользователем в списке аргументов, подобны переменным: они ссылаются на значение, предоставляемое в то время, когда вызывается функция, независимо от того, вызывается ли функция оператором VBA или host-приложением.
Имена аргументов имеют ту же область действия, что и переменные, объявляемые локально в функции-процедуре, то есть недоступны вне функции-процедуры, в списке аргументов которой они объявляются.
Вернемся к описанию синтаксиса и к строке, содержащей оператор Name = expression. Эта строка представляет присваивание функции; Name — имя функции, a expression — любое выражение, создающее значение, которое должна возвращать функция. Присваивание функции указывает VBA, какое значение будет возвращать функция. Заметьте, что присваивание функции использует имя функции-процедуры и присваивает ему значение, как если бы это была переменная. Функции-процедуры могут не иметь совсем или иметь один или несколько различных операторов присваивания функции.
Первый пример функции, который вы изучите, помогает манипулировать строками. Как вы помните из предыдущей главы, функция Len возвращает длину строки, включая любые начальные или конечные пробелы. Если необходимо определить длину строки, исключая начальные и конечные пробелы, можно использовать вложенные (nested) вызовы функции (один вызов функции внутри другого), подобные следующему:
StrLen = Len(Trim(AnyStr))
Этот тип операции хорошо подходит для функции-процедуры. Использовать один вызов пользовательской функции-процедуры проще и легче, чем повторять запись вложенного вызова функции. Листинг 7.1 показывает как раз такую простую функцию-процедуру LenTrim, которая возвращает длину строки, исключая начальные и конечные пробелы.
Листинг 7.1. Простая функция-процедура LenTrim
1	Function LenTrim(tStr)	' Определение функции
2	LenTrim = Len(Trim(tStr))	' Возвращаемое значение
3	End Function
В строке 1 содержится объявление функции LenTrim, начинающееся с обязательного ключевого слова Function. После имени функции открываются круглые скобки, что указывает VBA на начало списка аргументов. Далее следует имя аргу
180
Глава 7
мента (tStr). Имя аргумента сообщает VBA, что функции-процедуре при ее вызове должен передаваться один аргумент.
Как вы уже, наверное, успели заметить, при нажатии на клавишу Enter после ввода ключевого слова Function, имени функции и списка аргументов Редактор VB автоматически вставляет ключевые слова End Function, как и в случае, когда вы вводите ключевое слово Sub для создания процедуры. Если этого не происходит, возможно, при написании строки-заголовка была допущена ошибка синтаксиса.
Строка 2 функции LenTrim — это строка, которая выполняет всю (пока небольшую) работу функции и также содержит аргумент функции для LenTrim. При вычислении выражения Len(Trim(tStr)) VBA принимает строку, полученную посредством аргумента tStr, и передает ее VBA-функции Trim для удаления начальных или конечных пробелов. Результат функции Trim, в свою очередь, используется как аргумент функции Len. Затем VBA присваивает результат функции Len имени функции LenTrim. LenTrim возвращает длину строки аргумента, исключая начальные или конечные пробелы.
Наконец, в строке 3 функция заканчивается ключевыми словами End Function. После выполнения этой строки VBA возвращается к оператору процедуры, вызвавшему функцию LenTrim, и вставляет результат функции LenTrim в этот оператор в том месте, где появляется имя функции.
Для вызова функции LenTrim используйте оператор, подобный следующему, который отображает результат LenTrim для строки ” Excel 2000
MsgBox LenTrim (" Excel 2000	")
В этом операторе строка аргумента имеет четыре начальных и четыре конечных пробела, и длина строки (как указывает VBA-функция Len) равна 18 символам. Функция LenTrim сообщает длину строки без начальных и конечных пробелов; вышеуказанный оператор отображает число 10.
Создание определенных пользователем функций для Excel
Функции-процедуры с некоторыми ограничениями на их действия называются определенными пользователем функциями (или сокращенно UDF-user-defined functions), и только их может использовать Excel в формуле ячейки рабочего листа.
Все ограничения определенных пользователем функций происходят из одного базового ограничения: UDF не может никаким образом изменять среду Excel. Это означает, что определенная пользователем функция не может выбирать, вставлять, удалять или форматировать никакие данные в рабочем листе, таблице или другом листе. UDF также не может добавлять, удалять или переименовывать листы или рабочие книги, не может изменять экранное представление и так далее. Например, нельзя использовать функцию-процедуру как определенную пользователем функцию в Excel, если она выделяет ячейки или изменяет каким-то образом текущий рабочий лист.
Кроме того, UDF не может устанавливать свойства объекта или использовать методы объекта; в большинстве случаев установка свойств объекта или использование его методов приводят к изменениям в среде Excel (объекты, методы и свойства описываются в главе 10). Определенная пользователем функция может осуществлять выборку значений свойств объекта и выполнять любые методы объекта, которые не изменяют среду Excel.
Обычно определенная пользователем функция должна только выполнять вычисления или манипулирование на основе данных, полученных из ее списка аргументов или выбранных из Excel. Функцию LenTrim, показанную в листинге 7.1, можно использовать как определенную пользователем функцию, поскольку она отвечает всем требованиям UDF.
Следует помнить о том, что ни VBA, ни Excel не отображают сообщение об ошибке, если в качестве UDF используется функция, в которой нарушены правила
Создание и использование функций и функций-процедур
181
для определенных пользователем функций. Такая функция просто не может возвращать результат. Например, при попытке вставить значение в рабочий лист Excel, используя функцию-процедуру, нарушающую правила для определенных пользователем функций, ячейка с такой функцией отображает Excel-сообщение об ошибке #VALUE!, обозначающее, что функция или формула для этой ячейки не может возвращать допустимый результат.
VBA запрещает присваивание несовместимого типа результату функции в любой функции-процедуре, которая имеет объявленный тип данных для ее результата. Если, например, вы ошибочно написали оператор присваивания функции так, что присваивается, допустим, тип Integer результату функции с объявленным типом String, то VBA отображает ошибку несовпадения типа.
В случае присваивания типа данных, который не является тем же, что объявленный возвращаемый тип для функции-процедуры, но является совместимым, то VBA преобразует значение типа, определенного для функции при возврате результата функции. Например, если присваивается тип Double функции, результат которой был объявлен как Long, то VBA не выдает никакой ошибки, а просто преобразует Double в тип Long (при возвращении результата функции).
Объявление типа функции имеет еще один результат: если функция-процедура заканчивается без выполнения оператора присваивания функции, VBA возвращает строку нулевой длины для функций типа String и 0 — для функций-процедур, возвращающих численный тип. Нетипизированная функция-процедура, которая заканчивается без выполнения оператора присваивания функции, возвращает результат типа Variant, содержащий специальное значение Empty.
Листинг 7.2 показывает функцию LenTrim, модифицированную так, что она всегда возвращает значение типа Long.
Листинг 7.2. Задание типа функции LenTrim
1	Function LenTrim(tstr) As Long
2	' возвращает длину tStr без ведущих и хвостовых пробелов
3	LenTrim = Len(Trim(tstr))
4	End Function
Следует выбирать тип результата функций-процедур, требующий наименьшего объема памяти, но вмещающий полный диапазон возможных значений, которые может возвращать функция. Для функций общего назначения численных или математических наиболее характерным типом для результата функции является Double.
Объявление типов данных для аргументов функции
Если только не было определено иначе, VBA передает все аргументы в функцию-процедуру как типы Variant. Можно объявлять определенные типы данных для каждого аргумента в списке аргументов.
Аргументы с определенными типами используются по тем же знакомым причинам, по каким используются типизированные переменные или результаты функции. Определение типов аргументов для функции-процедуры также помогает пользователю при вызове функции вводить аргументы правильного типа в правильном порядке.
Для объявления определенных типов аргументов функции-процедуры, используйте ключевое слово As, за которым следует имя нужного типа данных после имени аргумента в списке аргументов. Листинг 7.3 показывает функцию LenTrim, модифицированную так, чтобы она принимала только данные типа String в аргументе tStr.
182
Глава 7
Листинг 7.3. Определение типа данных аргумента функции LenTrim
1	Function LenTrim(tstr As String) As Long
2	' возвращает длину tstr без ведущих и хвостовых пробелов
3	LenTrim = Len(Trim(tstr))
4	End Function
За исключением объявления функции-процедуры (в строке 1), листинг 7 3 идентичен листингу 7.2. После того как тип аргумента объявлен, VBA при вызове функции LenTrim допускает в качестве аргумента появление только значений типа String. Вызов LenTrim с каким-либо другим типом (даже Variant) в качестве аргумента вызывает ошибку несовпадения типа (конкретнее, несовпадение типа аргумента — argument type mismatch).
Использование функций-процедур в VBA
Используйте собственные функции-процедуры в операторах VBA так же, как любые встроенные функции VBA; все правила и условия по использованию встроенных функций применимы к пользовательским функциям-процедурам.
Помните, что при вызове функции необходимо включать список аргументов в круглых скобках, если только вы не собираетесь игнорировать результат функции. Как и в случае со встроенными функциями VBA, можно игнорировать результат вашей собственной функции, хотя это редко бывает необходимо.
Если нужно использовать именованные аргументы в ваших собственных функциях-процедурах, просто используйте имена из списка аргументов в объявлении функции-процедуры. Например, чтобы использовать именованный аргумент в вызове функции LenTrim (листинг 7.3), применяйте оператор, подобный следующему (AnyStr и MyStnng — строковые переменные):
AnyStr = SLen(tstr:=MyString)
Если вам трудно запомнить все именованные аргументы для одной из своих функций, убедитесь, что свойство Auto Quick Info (краткие сведения) включено. Если это так, Редактор VB отображает всплывающее окно с перечнем именованных аргументов вашей функции, как для встроенных функций VBA. На рис. 7.1 показано Code Window, в котором зафиксирован процесс ввода кода для вызова функции LenTrim из листинга 7.1; обратите внимание на всплывающее окно, ото-
Рис. 7.1
Свойство Auto Quick Info позволяет отображать всплывающее окно, показывающее список аргументов вашей собственной функции, как и для встроенных функций VBA
'Л Micr»s»ff Vjtu«l - Norrn»| - [ModuleJ (Cede)] .
fife Edit View Insert Format Cebug Run Xool^ £dd Ins Window Help
I (General)
pTest-LenTfhn
Function LenTrim(tstr As String) As Long
Ч"- ИЦ! i д ihv rib i T f /
LenTrim = Len(Trim(tstr)) Function
End
Йй-М
а* '>
ц
Sub
End
Test_LenTrim {)
Dim Inputstring As String
Inputstring = InputBox{ Введите строку с пробелами') msgbox lentrimf
Sub LenTnm(tSfrArSfr/n^As Long
Создание и использование функций и функций-процедур
183
бражающее имя функции, ее именованные аргументы и возвращаемый тип этой функции.
Свойство Auto Quick Info можно включать и отключать, выбирая Tools | Options (Сервис | Параметры) для отображения диалогового окна Parameters (Параметры). Щелкните на вкладке Editor (Редактор) для отображения опций Редактора VB и затем установите или отмените установку флажка Auto Quick Info (краткие сведения).
Использование инструмента Object Browser для нахождения функций-процедур
Если вы не можете вспомнить, в каком модуле сохранили некоторую функцию, можно использовать Object Browser для определения того, какие из ваших функций-процедур доступны в данный момент, и для быстрого отображения исходного VBA-кода вашей функции.
Чтобы использовать Object Browser, запустите его, как вы уже научились это делать: выберите команду View | Object Browser (Вид | Просмотр объектов) или щелкните кнопку Object Browser на панели Редактора VB для отображения окна Object Browser.
Вы уже знаете, как использовать Object Browser для отображения доступных функций VBA или функций host-приложений. Раскрывающийся список Project/Library (Проект/Библиотека) отображает все открытые в данный момент файлы приложения, как и всегда присутствующую опцию VBA. Для отображения пользовательских функций (и других процедур) в определенном проекте VBA (документе Word, рабочей книге Excel или каком-либо другом документе host-приложения) выполняйте следующие шаги:
1.	Выберите наименование проекта в раскрывающемся списке Project/Library. На рис. 7.2 показано окно Object Browser с выбранным в Project/Library-списке элементом Project (в Excel подобный элемент называется VBAProject). Окно Project Explorer указывает имя файла, в котором сохранен проект (в круглых скобках после имени проекта).
Рис. 7.2
Используйте Object Browser для нахождения VBA-функций
'Л Microsoft Visual Basic - ChapterOT - [Object Browser]	Е~~|В|Я	
Elfe Edt Ytew Insert Format £>et>ug Bun Tools &dd-lns Window Help - ® X В A • H %i« - ► II  X «ff	®	Г	
|proj.ct	_d_d	dll	
1	j»J« Search Results	
1 Library	| Class	1 Member	1	
	
Classes ° IS'obais*	 ^iMpduhl		] SI ThlsDocument	Members of'Module V
	E LenTrim	^1
	* T»st_L*nTrim I
Public Function LenTrlm(fSfr As String) As Long	* Member of Ptniert Mi-dule1 Возвращает длину строки без ведущих и хвостовых пробелов	v	
После того как был выбран проект в окне Project/Library, список Classes (Классы) содержит перечень всех модулей и других объектов в выделенном проекте.
2.	Выберите модуль в списке Classes. После этого список Members of<class> (Компонент) содержит перечень всех процедур и функций, объявленных в выбранном модуле.
3.	Выберите функцию или процедуру, исходный код которой необходимо просмотреть, в списке Members of<class> (Компонент).
184
Глава 7
4.	Щелкните на кнопке Show (показать) для отображения исходного кода функции или процедуры. Редактор VB открывает соответствующий модуль и помещает курсор на первую строку после объявления функции или процедуры.
Можно также копировать текст из окна Object Browser для своих функций и процедур в буфер Windows (Clipboard) так же, как и в случае со встроенными функциями VBA.
Помните, что кнопка Show в окне Object Browser включается, только если исходный код для выбранной функции или другой процедуры доступен.
Не пытайтесь использовать диалоговое окно Macros (открываемое с помощью команды Tools | Macros (Сервис | Макрос)) для выполнения функции-процедуры. VBA «ожидает», что функция-процедура предназначена для того, чтобы возвращать значение, поэтому нет смысла только в выполнении функции. По этой причине VBA не перечисляет функции-процедуры в списке Macro Name (Имя макроса) в диалоговом окне Macros. Это демонстрируется на рис. 7.3, где в списке макросов имеется только программа Test_LenTrim.
Рис. 7.3
VBA не перечисляет функции-процедуры в списке Имя окна Макрос
Имя
Макрос
ActDocuml
AutoExec MAIN
AutoExit MAIN
MyMacro
RunFIneReader MAIN
j ВьГ.ОПНИТо ~j
Орюдка
Изменить

ВыделитьТекст
Замены НумерацияЗтрок
Создать
Удалить
Срган'Ватор
Макросы из | Активных шаблонов
Отмена
Описание
| Макрос создан 01 03 2003 Владимир
Ввод описания функции-процедуры с помощью инструмента Object Browser
Вернемся к рис. 7.2. В списке Members of<class> (Компонент) выбрана функция LenTrim из листинга 7.3. Заметьте, как и в случае со встроенными функциями VBA и функциями host-приложения, имя функции и ее аргументы отображаются в нижней части окна Object Browser (под списками Classes и Members). Однако в отличие от встроенных функций VBA, никакого описания назначения функции не появляется. Для добавления описания к каждой из ваших функций или процедур можно использовать Object Browser. Описание, вводимое для функции с помощью окна Object Browser, появляется не только в окне Object Browser, но и в Function Wizard (мастере функций) Excel. Обеспечение функции-процедуры описанием помогает другим пользователям использовать вашу функцию в формуле ячейки рабочего листа.
Чтобы ввести описание для функции-процедуры, выполните следующие шаги: 1. Выберите функцию-процедуру в окне Object Browser, как было описано ранее. 2. Щелкните правой кнопкой мыши на функции, к которой необходимо добавить описание, и выберите Properties (Свойства) во всплывающем меню. Редактор VB отображает диалоговое окно Member Options (Параметры компонента), показанное на рис. 7.4.
Создание и использование функций и функций-процедур
185
3. Введите описание для функции (или процедуры) в текстовое окно Description (Описание). На рис. 7.4 показано описание функции LenTrim, уже введенное в текстовое окно Description.
4. Щелкните на ОК. Вы вновь оказываетесь в окне Object Browser.
Рис. 7.4
Вводите полезные описания для функций и процедур в диалоговое окно Member Options
Member Options
Name LenTrim	I	I
Cescrptton.	Cancel ।
I Возвращает длину строки без	———	
ведущих и хвостовых пробелов	
Help File	Help Context ID	
l°	Help j
Использование функций пользователя / в рабочих листах Excel
Чтобы использовать свои функции (определенные пользователем) в Excel, вводите имя функции и ее аргументы как формулу в ячейку рабочего листа так же, как вы вводите любую встроенную функцию Excel.
Если вы не можете запомнить имя определенной пользователем функции или ее аргументы, можно найти эту функцию в списке Function name для категории User-Defined, указанной в списке Function category диалогового окна Paste Function. [Отобразить диалоговое окно Paste Function (Мастер функций) Excel можно, щелкая на кнопке Paste Function (Вставка функции) на панели инструментов или выбирая в меню Insert | Function (Вставка | Функция).]
Вставляйте функции VBA из диалогового окна Paste Function, как любые встроенные функции Excel. При необходимости в этом же окне вставляйте и значения для аргументов функции.
Если при использовании определенной пользователем функции (UDF) в ячейке рабочего листа отображаемым результатом является значение ошибки #VALUE!, внимательно проверьте код в вашей функции-процедуре, чтобы убедиться, что он не нарушает каких-либо правил для определенных пользователем функций. Ни Excel, ни VBA не препятствуют использованию в ячейке рабочего листа функции-процедуры, которая нарушает UDF-правила. Однако поскольку функция-процедура нарушает UDF-правила, VBA не выполняет эту функцию, а возвращает ячейке значение ошибки #VALUE!.
При написании функции-процедуры помните, что особым назначением функции является возвращение какого-либо значения. Пишите простые и значимые функции. Обычно функция должна содержать программный код, необходимый только для выполнения некоторых вычислений или манипулирования данными; функция никогда не должна выполнять действия, не относящиеся непосредственно к созданию ее возвращаемого значения.
Пишите функцию всякий раз, когда вам необходимо использовать одну и ту же математическую формулу более двух-трех раз. Как показывают примеры в этой главе, функции-процедуры полезны также при манипулировании и другими данными, а не только числами.
Даже если выражение для какого-либо вычисления может быть совсем простым, все же следует писать функцию-процедуру, если вы используете это выражение часто. Таким образом вы устраняете вероятность ошибки при вводе выражения и даете этому выражению значащее имя.
Хотя можно игнорировать результаты функций-процедур, следует все же так писать функции-процедуры, чтобы игнорирование их результатов не имело смыс
186
Глава 7
ла. Другими словами, функции не должны выполнять действия, кроме абсолютно необходимых для выдачи нужных возвращаемых результатов.
Не считайте VBA-функцию MsgBox примером для написания функций. Функция MsgBox выполняет уникальную задачу в VBA; в результате она делает намного большую работу с большим количеством опций, чем обычно выполняют функции. И, наоборот, считайте VBA-функции StrComp, Mid, функции преобразования данных CStr и CDbl и так далее примером того, как должна действовать функция-процедура. Каждая функция выполняет одну задачу и возвращает один результат без изменения исходных данных, содержащихся в переданных ей аргументах.
Не пытайтесь использовать передаваемые по ссылке аргументы для создания функции, возвращающей более одного результата, используя возвращаемое значение функции и один или больше модифицированных аргументов для получения результатов. Функция никогда не должна изменять исходные данные в передаваемых ей аргументах. В главе 9 будет показано, что существуют обоснованные условия, при которых следует модифицировать значения в аргументах, передаваемых по ссылке; при этих условиях необходимо использовать процедуру, а не функцию. Следите за тем, чтобы ваши функции не изменяли передаваемые по ссылке аргументы; используйте ключевое слово ByVai для передачи аргументов по значению. (Подробнее об этом читайте также в главе 9.)
Многие ваши программы должны использоваться не только в программах или рабочих листах, для которых вы первоначально написали функцию-процедуру. Функция LenTrim, которая обсуждалась в этой главе, например, является функцией общего назначения и может быть полезной в целом ряде различных выражений в разных процедурах.
Поскольку функция-процедура в документе открытого проекта доступна для любого открытого в данный момент документа в одном и том же приложении, можно собрать универсальные функции в один проект. Объединяя функции-процедуры общего назначения в одном проекте, можно создать библиотеку (library) функций. Например, можно поместить все ваши универсальные Excel-функ-ции-процедуры в файл рабочей книги с именем MyFunctions.xls. Другой пример: можно поместить все ваши универсальные Word-функции в документ шаблона с именем MyFunctions.dot и т.д.
Следите за тем, чтобы создаваемая вами функция содержала присваивание функции. То есть чтобы функция возвращала результат, отличный от пустого значения по умолчанию типа Variant, строки нулевой длины типа String или нулевого численного значения. Следите за тем, чтобы программный код функции отвечал всем правилам для определенных пользователем функций, описанных в начале этой главы, если вы предполагаете использовать функцию как UDF в Excel.
Создание функций для Excel
При написании функций-процедур для использования в качестве UDF в рабочих листах Excel необходимо знать несколько фактов, помимо общих требований для определенных пользователем функций:
	Определенные пользователем функции, которые будут использоваться в Excel, не должны иметь имена, похожие на записи ссылок на ячейку типа А1 или R1C1.
	Любые строковые (текстовые) данные, возвращаемые из VBA в Excel, не должны иметь более 255 символов в длину. Если UDF возвращает строку, имеющую больше 255 символов в длину, в ячейку рабочего листа, Excel укорачивает строку до максимальной длины 255 символов перед вставкой ее в ячейку.
	При написании UDF, возвращающей значение даты для Excel убедитесь, что задаете тип результата функции как Date. Excel применяет формат Date для результата функции в ячейке рабочего листа только, если результат имеет VBA-тип Date.
Создание и использование функций и функций-процедур
187
Существует еще одно обстоятельство, связанное с тем, в какой момент времени Excel фактически вызывает определенную пользователем функцию для вычисления или повторного вычисления формулы ячейки рабочего листа, частью которой является UDF.
По умолчанию Excel вызывает UDF для повторного вычисления формулы ячейки рабочего листа всякий раз при изменении значений, используемых для аргументов функции, во многом так же, как для любой формулы рабочего листа. Однако можно задать UDF так, чтобы Excel повторно вычислял ее при повторном вычислении любой ячейки в рабочем листе.
Следует помечать UDF как изменяющуюся (volatile) всякий раз, когда значения ее аргументов не получаются из значений других ячеек рабочего листа. Например, предположим, функция с именем Общая_Стоимость вычисляет стоимость услуг поставщика сети Internet с учетом НДС (налог на добавленную стоимость). UDF может иметь два аргумента: один для определения ячейки рабочего листа, содержащей значение стоимости услуг без учета НДС, а другой — для определения ячейки рабочего листа, содержащей процентную ставку НДС. Поскольку аргументы функции Общая_Стоимость определяют координаты ячейки, изменение содержимого ячейки не меняет значение аргументов функции Общая_Стоимость. При редактировании содержимого ячеек общей стоимости или общей прибыли, Excel не вычисляет повторно функцию Общая_Стоимость, поэтому функция Общая_Стоимость может выдать ошибочные результаты. Если пометить эту UDF как изменяющуюся, она будет всегда отображать правильное значение, потому что Excel будет всегда повторно вычислять ее при каждом изменении любой ячейки в рабочем листе.
Определенная пользователем функция, которая перевычисляется при каждом изменении любой ячейки в рабочем листе Excel, называется изменяющейся функцией. Чтобы пометить UDF как изменяющуюся, добавьте следующий оператор к функции сразу за ее объявлением:
Application.Volatile
Этот VBA-оператор помечает UDF как изменяющуюся функцию, и такая функция на самом деле является особым типом процедуры. Эта процедура называется методом (method), принадлежащим Excel. (Методы подробно описываются в главе 10.) Поскольку метод принадлежит Excel, необходимо при использовании метода Volatile задавать объект Application, точно так же, как необходимо задавать объект Application при использовании функции Excel в операторе VBA. Листинг 7.4 показывает изменяющуюся функцию с именем Общая_Стоимость.
Листинг 7.4. Изменяющаяся определенная пользователем функция в Excel
1	Function Общая_Стоимость(Сумма As Currency, _
2	Ставка_НДС As Single) As Currency
3	Application.Volatile
4	Общая_Стоимость = Сумма * (Ставка_НДС / 100#) + Сумма
5	End Function
Функция Общая_Стоимость имеет два обязательных аргумента: Сумма и Ставка_НДС. Один аргумент (Сумма — стоимость услуг без учета НДС) имеет тип Currency, другой (Ставка__НДС процентная ставка НДС) — тип Single, так как представляет обычно число не более 100. Объявление функции заканчивается указанием того, что возвращаемое функцией значение имеет тип Currency, так как возвращает значения, представляющие деньги.
Строка 3 содержит оператор Application.Volatile; как и требуется, он является первым оператором в функции после объявления функции. Оператор Application.Volatile «регистрирует» определенную пользователем функцию с помощью Excel так, что Excel вызывает ее для перевычисления формулы ячейки рабочего
188
Глава 7
листа, в которой появляется функция, каждый раз при перевычислении любой ячейки в рабочем листе.
Однако не следует злоупотреблять методом Application.Volatile. Если все функции рабочего листа будут изменяющимися, это может привести к ненужным перевычислениям, что увеличивает общее время, необходимое.для перевычисления рабочего листа.
В качестве еще одного примера рассмотрим способ представления некоторых данных с использованием функции пользователя. Необходимо решить следующую задачу. У нас имеется таблица с данными о товарах: наименования, цены и т.д. Эта таблица, в частности, может использоваться для формирования так называемых «прайс-листов». Цены на товары меняются так часто, что менеджеры едва успевают менять «ценники» на товары (небольшие листочки с информацией о наименовании и цены товара) (рис. 7.5). Эти «ценники» нам нужно формировать в одном из листов Excel (например, Лист1), поскольку таблицу с товарами из какого-либо источника данных также легко помещать именно в Excel (рис. 7.6).
Рис. 7.5
«Ценник» с информацией о товаре наименование и цена (в руб)
ЧП «Петров П В »
Stellar 7
Цена 32 руб.
Рис. 7.6
Таблица с информацией о товарах (код, наименование, цены в $ и руб )
г	- -V .	-	 ~	... . ..	 		 UJ Microsoft Excel - CENA	. оа		
И] файл Правка &ид Вставка Формат Сервис	Данные	Qkho	
Справка		. fl	X
н	100% -	’’ ArialCyr	- 10 F2	’	f,	» ж JK	Ч » >	»
/\	В	с	D	A
1 *457019133044 (3DL) Stellar 7	4 30	32 00	—
2 [046119185028 (3DO) Alone in the Dark 2	2 00	50 00	
3 66019084733 (3DO) Bazookatone	2 00	52 00	
4 *046119185440 (3DO) Cowboy Casino	2 60	49 00	
5 '098019120214 (3DO) CPU Back	2 60	33 00	
i 6 *006019111551 (3DO) Cyberdillo	2 00	52 00	
7 *417119155215 (3DO) FIFA Soccer'95	2 60	65 00	
8 407119115731 (3DO) Fun n Games	2 70	33 00	
9 437019112950 (3DO) Micro Cosm	3 50	33 00	
10 *26019093837 (3DO) Myst	2 00	65 00	
11 *437019113204 (3DO) Night Trap (2cd)	6 80	65 00	
. 12 *086019143136 (3DO'i Olimnic Soccer	з sn	33 00	
'M < ► H \Лист1/Лист2 X ЛистЗ /	|<| Г 0Т080	NUM	1	►	г
Для решения этой задачи следует к проекту VBAProject( CENA.XLS) добавить модуль и в этом модуле создать две функции, как показано на рис. 7.7.
Далее в другом рабочем листе (например, Лист2) необходимо заполнить, например, три ячейки первой строки заголовком ЧП «Петров П.В.» — наименование торгующей организации (рис. 7.5). В ячейки второй строки следует записать формулы =пе\у_пате(Лист1!В1), =пе\у_пате(Лист1!В2) и =пе\у_пате(Лист1!ВЗ), соответственно. В ячейки третьей строки остается поместить формулы =СЕ-ХА(Лист1!П1), =СЕХА(Лист1!П2) и =СЕХА(Лист1!ПЗ), соответственно (считаем, что цены в рублях записаны в колонке D). Сразу же после выполнения этих операций на этом листе должна появиться информация о товарах в том виде, как это показано на рис. 7.8.
Создание и использование функций и функций-процедур
189
Рис. 7.7
Функции CENA и new_name в модуле проекта для форматирования данных в виде «ценников»
1 >Р1- V». 1 ЛзХ  CENA.XLS - Модуль 1 (Code)
СЗ jOj_________________________.
- Й VBAProject (СЕ1ЧА XLS) «Microsoft Excel Objects S ThisWorkbook
j О Лист! (Лист!) Й) Лист2 (Лист2) ® ЛистЗ (ЛистЗ) Modules
<4$ Модуль!
* VBAProject (PERSONAL .XLS)
|(G«neraO	▼ | jnewjiame ~
Function CENA(А)	"Г3
CENA = "Цена " & А & " руб "	~~
~End Function
Function new_name(name)	‘
3 - Len(RTrim(name))
n3 = InStr (name, ") ") + 2	I
new_name = Mid(name, n3, j - n3 + 1)
End Function
Рис. 7.8
Необходимо заполнить только первые несколько строк с использованием функций CENA и new_name для форматирования данных в виде «ценников»
Осталось совсем немного — выделить ячейки A1-D3, поместить курсор мыши в правый нижний угол ячейки D3 (курсор должен принять вид темного крестика), протащить курсор вниз на число ячеек кратное трем и с удовольствием наблюдать на экране довольно легко получившиеся «ценники» (рис. 7.9). Если данные о товарах изменились, следует только исправить их в листе Лист!.
Рис. 7.9
Задача форматирования данных в виде «ценников» решена
©Microsoft Excel - CENA		С		рта	
IS)*] файл гравка Вид Встдека Формат Сервис Данные Окно У В <* 60%	’ ” AnalCyr	* 10 т ж А ч А1	’г	f„ ЧП «Петров П В »			^правка Ж 5® -J	_ в X	
	А	'	8		с		
1 2 3 Л. в 7 е 9	ЧП .Петро» П В » Stellar? Цена 32 руб.	ЧП «Петро» П В » Alone in the Dark 2 Цена 50 руб.	ЧП «Петро» П В • Bazookatone Цена 52 руб.		
	ЧП «Петро» П В * Cowboy Casino Цена 49 руб.	ЧП «Петро» П В » CPU Back Цена 33 руб.	ЧП «Петро» ПВ» Cyberdillo Цена 52 руб.		
	ЧП «Петро» П 6 • FIFA 5оссеГ95 Цена 65 руб.	ЧП «Петро» П В » Fun n Games Цена 33 руб.	ЧП «Петро» П В • Micro Cosm Цена 33 руб.		
н < ► и\ Лист! \Лист2/ ЛистЗ /	|«	»|[
Готово
Глава 8
Изменение порядка выполнения операторов в VBA
До сих пор вы писали процедуры и функции, которые VBA выполняет только в линейном порядке. Во многом так же VBA выполняет записанный рекордером макрос: VBA начинает выполнение кода с первого оператора после строки объявления процедуры или функции и продолжает выполнять каждый оператор построчно до тех пор, пока не будет достигнут оператор End Sub или End Function, отмечающий конец определения этой процедуры или функции, или до тех пор, пока не возникнет runtime-ошибка (на это, очевидно, полагаться не стоит).
Подобные процедуры и функции, хотя и способны выполнять очень сложные задачи, не могут менять порядок выполнения операторов-инструкций при определенных обстоятельствах. На самом деле очень часто встречаются такие ситуации, когда необходимо, чтобы процедуры или функции выполняли различные действия при разных условиях. Например, если вы пишите процедуру, которая получает имя рабочей книги от пользователя, а затем открывает эту рабочую книгу, может понадобиться, чтобы ваша процедура имела возможность создать рабочую книгу, если книга еще не существует. В подобной ситуации необходимо, чтобы процедура выполняла те или иные операторы, предоставляя пользователю возможность создать рабочую книгу.
Команды, изменяющие порядок выполнения операторов, часто используют оценку конкретных элементов данных для выбора различных предопределенных действий. Например, можно написать процедуру, проверяющую, все ли числа столбца в рабочем листе находятся в диапазоне от 1 до 10. Эта процедура может проверять каждый элемент ввода в столбце отдельно и выполнять некоторый набор операторов, когда встречается элемент ввода вне указанного диапазона.
Изменение порядка выполнения операторов не всегда связано с реакцией на возникающие в процессе работы программы проблемы. Если вам необходимо, чтобы пользователь процедуры делал некоторый выбор по поводу последующего действия процедуры, можно использовать функцию InputBox для получения текстового ввода от пользователя или использовать функцию MsgBox, давая возможность пользователю делать выбор щелчком на командной кнопке в окне сообщения. После получения пользовательского выбора процедура должна выполнить действие, соответствующее этому выбору.
Конечно, процедуры не могут на самом деле «принимать решения» так же, как это делает человек. Однако процедуры «могут выбирать» предопределенные действия на основе простых условий и «принимать» относительно сложные решения, объединяя более простые решения.
При использовании VBA-операторов изменения порядка выполнения операторов определяется условие или набор условий, при которых VBA выполняет ту или иную ветвь (branch) кода процедуры. Поскольку такие операторы влияют на последовательность выполнения программы, их часто называют операторами управления потоком (flow control) или операторами управления программой (program control), но на практике они более известны как операторы условного и безусловного перехода (conditional и unconditional branching).
Оператор условного перехода — это структура, которая выбирает ту или иную ветвь кода процедуры на основе некоторого предопределенного условия или группы условий. Оператор безусловного перехода — это оператор, просто изменяющий по-
Изменение порядка выполнения операторов в VBA
191
следовательность выполнения кода процедуры независимо ни от какого конкретного условия. Условный переход используется гораздо чаще, чем безусловный.
При выполнении оператора условного перехода, такого как If...Then, VBA сначала оценивает указанное условие. Если условие равно True, VBA выполняет заданную группу операторов. Чтобы определить условие для оператора условного перехода, используется логическое выражение. При выполнении оператора безусловного перехода (GoTo) VBA немедленно начинает выполнение операторов, указанных командой перехода.
Критерии, на основе которых VBA «принимает решение» в операторах условного перехода, определяются путем создания логического выражения, описывающего условие, при котором необходимо выполнение или невыполнение определенной серии операторов. Для создания логических выражений в операторах перехода используются различные операторы сравнения и логические операторы VBA (которые были описаны в главе 5).
Простой выбор
Простейшими VBA-операторами изменения порядка выполнения кода являются операторы If...Then и If...Then...Else. Оператор If...Then позволяет VBA выбрать единственную альтернативную ветвь выполнения процедуры. Связанный с ним оператор If...Then...Else дает возможность VBA выбирать из двух альтернативных ветвей кода процедуры на основе оценки того, является ли указанное условие равным True.
Оператор If...Then позволяет выбрать единственную альтернативную ветвь кода в процедуре или функции.
Оператор If...Then имеет две различные формы синтаксиса. Простая форма — это однострочный оператор If...Then:
СИНТАКСИС
If Condition Then Statements
Condition — любое логическое выражение, a Statements — один, несколько или ни одного оператора VBA; все операторы должны помещаться в одной и той же строке. При выполнении подобного оператора VBA сначала оценивает логическое выражение, представленное с помощью Condition-, если это логическое выражение равно True, то выполняется оператор (или операторы) после ключевого слова Then до конца строки. Затем VBA возобновляет выполнение кода с первого оператора после строки, содержащей оператор If...Then.
Если логическое выражение, представленное с помощью Condition, равно False, то выполняется первый оператор в строке после строки, содержащей оператор If...Then, без выполнения альтернативной ветви. Следующий фрагмент процедуры показывает типичный однострочный оператор If...Then
If temperature > 100 Then MsgBox "Слишком горячо!"
Можно включать несколько операторов VBA в одну строку, отделяя каждый из них двоеточием (:), как показано в следующем примере:
Statementl : Statement2 : StatementN
В этой строке Statementl, Statement2 и StatementN каждый представляет один допустимый оператор VBA. Можно включать столько операторов в одну строку, сколько необходимо до максимальной длины строки для модуля. Однако строки со многими операторами трудно читать и понимать. Обычно следует помещать только один оператор в каждую строку.
192
Глава 8
В листинге 8.1 приведен код функции, которая принимает от пользователя новое наименование книги в виде строки и, если строка пустая (не содержит символов, кроме пробелов), выдает сообщение об этом.
Листинг 8.1. Функция GetBookName
1	Function GetBookName() As String
2	Dim ITitle As String, IPrmpt As String, IDflt As String 3
4	ITitle = "Ввод наименования книги"
5	IPrmpt = "Введите наименование новой книги"
6	IDflt = "Книга1"
7
- 8	' использование InputBox для получения имени файла.
9	GetBookName - Trim(InputBox(prompt:=lPrmpt, _
10	Title:=lTitle,
11	Default:=lDfIt))
12
13	' проверить наличие строки ввода
14	If Len(GetBookName) = 0 Then _
15	MsgBox "Наименование не введено!"
16
17	End Function	' GetBookName
Операция получения наименования функции (строка 9) совмещена с удалени-' ем ненужных пробелов посредством функции Trim.
Обратите внимание на строку 15, которая содержит однострочный оператор If...Then (символ перехода на новую строку не является причиной считать оператор неоднострочным: это — только возможность написания более длинного оператора, чем позволяет размер страницы). При выполнении строки 15 VBA сначала оценивает условное выражение Len(GetBookName) = О, которое возвращает значение True, если пользователь ввел строку, состоящую только из пробелов (здесь была использована ранее обсуждавшаяся функция LenTrim). В этом случае выполняется оператор:
MsgBox "Наименование не введено!"
Если выражение Len(GetBookName) = О возвращает False, то VBA не выполняет оператор после ключевого слова Then.
Видимо, сейчас вам уже не трудно будет написать процедуру тестирования функции, поэтому мы не будем на этом останавливаться, а сразу перейдем к «критике» функции. Недостатком этой функции является то, что в случае ввода в диалоговом окне функции InputBox одних пробелов мы только получим об этом сообщение, а функция GetBookName возвратит нам пустую строку. Если мы только тестируем эту функцию, ничего плохого в этом случае не произойдет. А что, если нам нужно создать с полученным наименованием какой-либо объект: книгу, лист, файл? На этот случай необходимо всегда формировать какое-то запасное (по умолчанию) имя. На самом деле в этом и заключается смысл создания оболочки вокруг функции InputBox. Если бы все пользователи были «правильными», можно было бы всегда обходиться функцией InputBox, поскольку «правильные» пользователи никогда не догадались бы в качестве имени новой книги ввести пробелы.
Итак, нам нужно, чтобы функция ввода наименования книги всегда возвращала непустую строку, даже если пользователь решил пошутить и сломать вашу программу. Для этого необходимо, кроме сообщения о том, что шутка оценена, присвоить возвращаемому значению функции имя по умолчанию, например, то, которое было ранее предложено пользователю, но отвергнуто им. Для этого рассмотрим следующую форму оператора If...Then.
Изменение порядка выполнения операторов в VBA
193
Вторая форма синтаксиса оператора If...Then называется блоком (block) оператора If. В блоке оператора If...Then условие и операторы записываются в отдельных строках, как показано в следующей синтаксической форме:
СИНТАКСИС
If Condition Then
Statements	„
End If
Здесь Condition, как и в однострочном операторе If...Then, представляет логическое выражение, определяющее условие, при котором VBA следует выполнить альтернативные операторы. Statements — это один, несколько или ни одного оператора VBA; операторы могут находиться в одной или нескольких строках. Наконец, ключевые слова End If указывают VBA, что достигнут конец альтернативной ветви операторов. Ключевые слова End If должны появляться в отдельной строке, хотя в эту строку можно включать конечный комментарий (см. следующую ниже диаграмму).
Как и в случае с однострочным оператором If...Then, VBA сначала оценивает логическое выражение, представленное с помощью Condition. Если это выражение равно True, VBA выполняет операторы в альтернативной ветви, начиная с первого оператора в строке, после строки, содержащей ключевые слова If...Then. VBA продолжает выполнение операторов в альтернативной ветви до тех пор, пока не достигнет ключевых слов End If. Затем продолжается выполнение операторов, начиная с первого оператора после End If.
Изменим код функции GetBookName, как показано в листинге 8.2.
Листинг 8.2. Функция GetBookNameZ
1	Function GetBookName2() As String
2	Dim llitle As String, IPrmpt As String, lDflt As String 3
4	llitle = "Ввод наименования книги"
5	IPrmpt = "Введите наименование новой книги"
6	lDflt = "Книга1"
7
8	' использование InputBox для получения имени файла.
9	GetBookName2 = Trim(InputBox(prompt:=lPrmpt, _
10	Title:=lTitle, _
11	.	Default:=lDfIt))
12
13	' проверить наличие строки ввода
14	If Len(GetBookName2) = 0 Then
15	MsgBox "Наименование не введено!"
16	GetBookName2 = lDflt ' имя по умолчанию
17	End If
7 Программирование на VBA 2002
194
Глава 8
18
19	End Function	' GetBookName
20	'
21	Sub test_GetBookName2()
22	' Тестирование функции GetBookName2
23	NewBookName = GetBookName2()
24	MsgBox NewBookName
25	End Sub	,
Листинг 8.2 содержит код уже обсужденной функции GetBookName2, которая никогда не возвращает пустую строку, и тестирующей процедуры, использующей MsgBox для отображения результата вызова GetBookName2.
В некоторых случаях при вводе наименования нового файла (книги) удобнее задавать конкретное имя по умолчанию, которое зависит от каких-либо дополнительных условий. Это требует ввода имени по умолчанию в качестве аргумента функции. Но, с другой стороны, хотелось бы оставить возможность использовать функцию ввода без аргументов. Поэтому прежде, чем рассматривать далее более сложные конструкции операторов управления последовательностью выполнения кода, обсудим такую возможность VBA, как необязательные аргументы функции.
Использование необязательных аргументов
Обычно аргументы, которые приводятся в списке аргументов функции-процедуры, должны предоставляться каждый раз, когда вызывается функция; эти аргументы являются обязательными {required). Вы уже знаете о необязательных аргументах функции по работе с VBA-функциями InputBox и MsgBox. Но, что самое замечательное, вы также можете использовать необязательные аргументы для ваших собственных функций-процедур.
При включении необязательных аргументов в список аргументов необходимо перечислять сначала все обязательные аргументы; после первого необязательного аргумента все последующие аргументы в этом списке должны быть также необязательными. Можно даже определять тип данных и значение по умолчанию для необязательных аргументов функции.
Для создания необязательного аргумента вставьте VBA-ключевое слово Optional перед именем этого аргумента в списке аргументов при объявлении функции-процедуры. Листинг 8.3 содержит очередную версию функции GetBookName, которая позволяет указать в качестве необязательного аргумента имя новой книги. С помощью встроенной функции IsMissing в коде определяется факт использования необязательного аргумента при вызове функции GetBookName. Если аргумент не был введен, функция использует свою внутреннюю строковую константу в качестве наименования книги.
Листинг 8.3. Функция GetBookName3
1 Function GetBookName3(Optional IDflt) As String
2 Dim ITitle As String, IPrmpt As String
3
4 ITitle = "Ввод наименования книги"
5 IPrmpt = "Введите наименование новой книги"
6
7	1 11 включен ли IDflt в список аргументов
8 If IsMissing(IDflt) Then IDflt - "Книга1"
9
10	' использование InputBox для получения имени файла.
11 GetBookName3 = Trim(InputBox(prompt:=lPrmpt, __
12	Title:=lTitle,
13	Default:=lDfIt))
Изменение порядка выполнения операторов в VBA
195
14
15	' проверить наличие строки ввода
16	If Len(GetBookName3) = 0 Then
17	MsgBox "Наименование не введено!"
18	GetBookName3 - IDflt 1 имя по умолчанию
19	End If
20
21 End Function	',GetBookName
22
23
24 Sub test_GetBookName3()
25	' Тестирование функции GetBookName2
26
27	' вызов функции без параметра
28	NewBookName = GetBookName3()
29	MsgBox "Наименование новой книги:	" & NewBookName
30
31	' вызов функции с параметром
32 NewBookName = GetBookName3(IDfIt:="Книга20")
33 MsgBox "Наименование новой книги: " & NewBookName
34 End Sub
Продолжим рассмотрение операторов, позволяющих изменять последовательность выполнения кода процедуры или функции.
Выбор ветви с помощью lf...Then...Else
Оператор If...Then дает возможность задавать одну альтернативную ветвь операторов в процедуре. Однако часто бывает необходимо выбрать одну из двух различных ветвей операторов в зависимости от определенного условия. Для этого VBA предоставляет операторы If...Then...Else и If...Then...ElseIf.
Как и If...Then, VBA-оператор If...Then...Else имеет две формы: однострочную и блочную. Синтаксис однострочного оператора If...Then...Else следующий:
СИНТАКСИС
If Condition Then Statements Else ElseStatements
Condition — любое допустимое логическое выражение. Statements — один или несколько операторов VBA. Как и в однострочном операторе If...Then, все операторы и ключевые слова однострочного If...Then...Else должны находиться в одной и той же строке.
При выполнении однострочного оператора If...Then...Else VBA сначала оценивает логическое выражение, представленное с помощью Condition; если это выражение равно True, VBA выполняет операторы (представленные с помощью Statements) между ключевыми словами Then и Else и возобновляет выполнение кода с первого оператора после строки, которая содержит If...Then...Else.
Если логическое выражение, представленное с помощью Condition, равно False, VBA выполняет операторы после ключевого слова Else до конца строки (представленные с помощью ElseStatements) и продолжает выполнение кода с первого оператора после строки, содержащей If...Then...Else.
В следующей строке показан типичный пример однострочного оператора If...Then...Else:
If Вес > 100 Then MsgBox "Тяжело!" Else MsgBox "He так тяжело!"
В этом примере, если значение переменной Вес больше 100, то условное выражение равно True и VBA выполняет оператор MsgBox для отображения сообщения [ "Тяжело!". Если переменная Вес содержит число, равное или меньшее 100, то рас
7*
196
Глава S
сматриваемое условие равно False и VBA выполняет оператор MsgBox после ключевого слова Else для отображения сообщения "Не так тяжело!”.
Как видно из примера однострочного оператора If...Then...Else, однострочную форму не всегда просто читать. Кроме того, поскольку все элементы однострочного оператора If...Then...Else должны находиться в одной и той же строке, размер и количество операторов, которые можно включать в альтернативные ветви выполнения, ограничиваются имеющимся в строке местом.
Блок операторов If...Then...Else легче читать и понимать и, поскольку можно располагать операторы в разных строках внутри блока оператора If...Then...Else, он не имеет ограничения по размеру и числу операторов, которые можно помещать в альтернативные ветви. Блок оператора If...Then...Else имеет следующий синтаксис:
СИНТАКСИС
If Condition Then
Statements	,
Else
ElseStatements
End If
Condition — любое допустимое логическое выражение; Statements и ElseStatements представляют один, несколько или ни одного оператора VBA. При выполнении блока оператора If...Then...Else VBA сначала оценивает логическое выражение, представленное с помощью Condition. Если это выражение равно True, то VBA выполняет все операторы (представленные с помощью Statements) между ключевым словом Then и ключевым словом Else. Затем VBA возобновляет выполнение кода с первого оператора, появляющегося после ключевых слов End If, которые указывают на конец блока оператора If...Then...Else.
Если логическое выражение, представленное с помощью Condition, равно False, VBA выполняет все операторы (представленные с помощью Els'eState-ments) между ключевым словом Else и ключевыми словами End If. Затем VBA продолжает выполнение кода с первого оператора, появляющегося после ключевых слов End If. Как и в блоке оператора If...Then, ключевые слова End If должны помещаться в отдельной строке, хотя в эту строку можно добавлять конечный комментарий (см. следующую наже диаграмму).
Оператор If...Then...Else выбирает одну или другую ветвь, но никогда не выбирает обе ветви одновременно. В следующем примере (листинг 8.4) показан типичный блок оператора If...Then...Else:
Листинг 8.4. функция GetBookName4
1	Function GetBookName4(Optional lDflt) As String
2	Dim llitle As String, IPrmpt As String, IVar As String 3
Изменение порядка выполнения операторов в VBA
197
4	ITitle = "Ввод наименования книги"
5	IPrmpt = "Введите наименование новой книги"
6
7	1 включен ли IDflt в список аргументов
8	If IsMissing(IDflt) Then IDflt = "Книга1"
9
10	' использование InputBox для получения имени файла.
11	IVar = Trim(InpufeBox(prompt:=lPrmpt, _
12	Title:=lTitle,
13	Default:=lDfIt))
14
15	' проверить наличие	строки ввода
16	If Len(lVar) =	0	Then
17	MsgBox "Наименование	не	введено!"
18	GetBookName4 = IDflt	'	имя по умолчанию
19	Else
20	GetBookName4 = IVar
21	End If
22
23	End Function	' GetBookName
Никаких преимуществ у этого кода по сравнению с кодом листинга 8.3 нет, но здесь был использован оператор If...Then...Else и строки 16-21 представляют собой более понятный код. Этот пример содержит тот же оператор, приводимый для однострочного If...Then...Else, но теперь использует форму блока.
Сложный выбор
Вы узнали, как создавать операторы перехода, выбирающие одну или одну из двух альтернативных ветвей кода процедуры. Однако часто бывает необходимо выполнить более сложный выбор в процедурах, выбирая между тремя, четырьмя и более ветвями.
Вложенные операторы lf...Then
При необходимости принятия более сложных решений можно помещать оператор If...Then или If...Then...Else внутрь другого оператора If...Then или If...Then... Else, что называется вложением операторов (nesting). (Вложение означает помещение одного типа структуры управления выполнением кода внутрь другой.) (См. следующую ниже диаграмму.)
198
Глава 8
Хотя можно вкладывать и однострочные формы операторов If...Then и If... Then...Else, такие операторы трудно понимать. При вложении If ...Then и If...Then... Else используйте для ясности блочную форму этих операторов.
Листинг 8.5 показывает простую процедуру для иллюстрации того, как работают вложенные операторы If...Then...Else. Процедура EvalDiscount получает от пользователя количество покупемого клиентом товара (числовое значение), а затем оценивает это число и определяет скидку, на которую может рассчитывать клиент.
Листинг 8.5. Вложенные операторы lf...Then...Else
1	Sub EvalDiscount()
2	' Определение скидки (в %) в зависимости от
3	1 количества продаваемого товара	.	<
4	Dim IStr As String
5	, Dim IntNum
6	IntNum = Application.InputBox( _
7	prompt:=”Введите количество товара", _
8		Title:="Процедура EvalDiscount”, _
9	Type:=l)
10	If Not (TypeName(IntNum) = "Boolean") Then
11
12	If IntNum > 1000 Then
13	IStr = "10"
14	Else
15	If IntNum >	500 Then
16	IStr = "6"	- 
.17	Else
18	IStr = "0"
19	' End If
20	End If	'
21	MsgBox	"Скидка	"	&	IStr	&	"%"
22	Else
23	MsgBox	"Количество	не	указано"
24	End If
25
26	End Sub
Написанная так процедура будет работать только в Excel, так как она использует метод Application.InputBox. Этот метод применен для того, чтобы не дать пользователю во время работы функции InputBox ввести что-либо, кроме числа. VBA отображает сообщение об ошибке, если пользователь вводит не число (рис. 8.1), и ожидает до тех пор, пока пользователь не введет численное значение или не выберет кнопку Cancel. Если пользователь, не вводя данные в окне функции Application.InputBox, щелкнет на кнопке OK, VBA также выдаст сообщение об ошибке (рис. 8.2). 
Рис. 8.1
Сообщение Excel при неправильном вводе в окне функции Application.InputBox (при работе с Office Assistant)
Microsoft Excel
Неверное число
Обратите внимание на степень защищенности программы листинга 8.5 от неправильных действий пользователя. Во-первых, функция Application.InputBox не дает возможности ввести в окно ввода нечисловое значение. Во-вторых, если поль-
Изменение порядка выполнения операторов в VBA
199
Рис. 8.2
Сообщение Excel при щелчке на кнопке ОК без ввода данных в окне функции
Application.lnputBox
(при работе с Office Assistant)
Microsoft Excel
Ошибка в формуле.
•	Для получения дополнительных сведений нажмите кнопку "Справка".
•	Чтобы получить помощь по использованию функции, выберите команду "Функция" (меню "Вставка").
•	Старайтесь не использовать вне формул знак равенства (=) и минус (-) или ставьте перед ними одиночную кавычку (1).
е Справка
;ок'
зователь использует «спасительную» кнопку Cancel, чтобы отказаться от ввода, программа (в строке 10) проверит результат ввода, который при щелчке на кнопке Cancel имеет тип Boolean, и выберет необходимую ветвь оператора If...Then...Else. При щелчке на кнопке Cancel выполнится оператор в строке 23 и на экран будет выдано сообщение о том, что количество товара не указано.
Использование lf...Then...Elself
VBA предоставляет сокращенную версию оператора If...Then...Else, являющуюся сжатым эквивалентом вложенных операторов If...Then...Else, показанных в листинге 8.5. Такой краткой формой является оператор If...Then...ElseIf.
Оператор If...Then...ElseIf имеет следующий синтаксис:
СИНТАКСИС	....
If Conditionl Then
Statements
Elself Condition2
El selfStatements
[Else
ElseStatements]
End I f
Conditionl и Condi.ti.on2 — любые логические выражения; Statements, ElselfS-tatements и ElseStatements — один, несколько или ни одного оператора VBA. При выполнении оператора If...Then...ElseIf VBA сначала оценивает логическое выражение, представленное с помощью Conditionl. Если это выражение равно True, то VBA выполняет все операторы (представленные с помощью Statements) между ключевыми словами Then и Elself. Затем VBA возобновляет выполнение кода с первого оператора после ключевых слов End If, которые указывают на конец оператора If...Then...ElseIf.
Если логическое выражение Conditionl равно False, VBA оценивает логическое выражение, представленное с помощью Condition2. Если выражение Соп-dition2 равно True, VBA выполняет все операторы (представленные с помощью ElselfStatements) между ключевым словом Elself и ключевыми словами End If (или необязательным Else). Затем VBA продолжает выполнение кода с первого оператора, появляющегося после ключевых слов Endlf. Ключевые слова End If должны находиться на отдельной строке.
200
Глава 8
Если логическое выражение Conditions равно False, то VBA пропускает Elself-Statements и продолжает выполнение кода с первого оператора после ключевых слов End If. Можно по желанию включать оператор Else в оператор If...Then...ElseIf. Если логическое выражение Condition! и логическое выражение Conditions равны False и имеется оператор Else, то VBA выполняет операторы, представленные с помощью ElseStatements. После выполнения операторов ElseStatements VBA продолжает выполнение кода с первого оператора после ключевых слов End If (см. следующую наже диаграмму).
В следующем листинге (8.6) показано, как с учетом вышеизложенного можно изменить строки 12-20 листинга 8.5.
Листинг 8.6. Использование lf...Then...Elself
1	Sub EvalDiscount2()
2	' Определение скидки (в %) в зависимости от
3	' количества продаваемого товара
4	Dim IStr As String
5	Dim IntNum
6	IntNum = Application.InputBox(	_
7	prompt: ="Введите количество товара", »_
8	Title:="Процедура EvalDiscount2", _
9	Type:=l)
10	If Not (TypeName(IntNum) = "Boolean") Then
11
12	If IntNum > 1000 Then
13	IStr = "10"
14	Elself IntNum > 500 Then
15	IStr = "5"
Изменение порядка выполнения операторов в VBA
201
16	Else
17	IStr = "О"
18	End If
19	MsgBox	"Скидка	"	&	IStr	&	"%"
20	Else
21	MsgBox	"Количество	не	указано"
22	End If
23
24	End Sub
Этот оператор If...Then...ElseIf действует точно так же, как вложенный оператор If...Then...Else в строках 12-20 листинга 8.5, и с теми же результатами, только эта форма более компактна.
При желании можно включать более одного предложения Elself в оператор If...Then...ElseIf; все предложения Elself следуют перед Else. VBA выполняет операторы в предложении Elself, если только логическое выражение в Elself равно True.
Использование оператора If...Then...ElseIf является вопросом профессионального предпочтения. Многие программисты считают, что их код более понятен и удобен при использовании вложенных операторов If...Then...Else и избегают использования оператора If...Then...ElseIf. Первоначально оператор If...Then...ElseIf был добавлен в BASIC для обеспечения возможностей, которые обеспечиваются оператором Select...Case (описывается в следующем разделе); он остается в VBA для легкой трансляции существующих программ с BASIC на VBA. При выполнении выбора из нескольких вариантов оператор Select...Case превосходит вложенный оператор If...Then...Else или еще более компактный оператор If...Then...ElseIf.
Оператор Select...Case
Примеры использования вложенных операторов If...Then...Else и If...Then... Elself показывают, что эти операторы позволяют выбирать из трех ветвей кода, но что если необходимо выбрать между 5, 8 или 10 различными возможными действиями?
Для выполнения выбора из нескольких возможных ветвей кода можно вкладывать операторы If...Then...Else на много уровней вглубь, но уследить за ходом выполнения ветвей становится прогрессирующе труднее. Альтернативно, можно было бы добавить дополнительные операторы Elself в оператор If...Then...ElseIf с оператором Elself для каждой условной ветви. Оператор If...Then...ElseIf имеет подобную проблему: когда имеется много операторов Elself, оператор If...Then... Elself становится трудно читать и сопровождать.
К «счастью», VBA имеет условный оператор перехода для использования в случаях, когда необходимо выбирать из большого количества различных ветвей кода: оператор Select Case. Он работает во многом так же, как множество независимых операторов If, но он более понятен для того, кто пишет код, и того, кто читает этот код. Ключевые слова Select Case используются со многими операторами Case, где каждый оператор Case проверяет появление другого условия и выполняется только одна из ветвей Case. Ветвь Case может содержать один, несколько или ни одного оператора VBA.
Оператор Select Case имеет следующий синтаксис:
СИНТАКСИС
Select Case TestExpression Case ExpressionListl statements!
Case ExpressionList2 statements2
Case ExpressionListN
202
Глава 8
statementsN
[Case Else
ElseStatements]
End Select
TestExpression — любое численное или строковое выражение. ExpressionListl, ExpressionList2 и ExpressionListN — (каждый) представляют список логических выражений, отделенных запятыми. Statements!, • statements2, statementsN и ElseStatements (каждый) представляют один, несколько или ни одного оператора VBA. В Select Case можно включать столько операторов Case ExpressionList, сколько необходимо (см. следующую наже диаграмму).
При выполнении VBA-оператора Select Case сначала оценивается TestExpression, а затем сравнивается результат этого выражения с каждым выражением, перечисленным в каждом ExpressionList. Если значение, представленное с помощью TestExpression совпадает с выражением в ExpressionList для одного из Case, VBA выполняет операторы для этого предложения Case. Если значение TestExpression совпадает более, чем с одним оператором Case, VBA выполняет только операторы в первом совпадающем предложении Case. Часто TestExpression — это просто имя одной переменной, математическое или численное, а не логическое выражение. Выражения в ExpressionList — это обычно логические выражения.
После завершения выполнения операторов в первом совпадающем операторе Case VBA продолжает выполнение кода с первого оператора после ключевых слов End Select, которые обозначают конец Select Case.
Если значение TestExpression не совпадает ни с каким из Case, а необязательный Case Else присутствует, VBA выполняет операторы, представленные с помощью ElseStatements перед переходом к оператору после Select Case.
Изменение порядка выполнения операторов в VBA
203
В отдельных операторах Case выражение ExpressionList может состоять из одного или более выражений, отделяемых запятой. Список ExpressionList имеет следующий синтаксис:
СИНТАКСИС
expression!, expression2,	expressionN
Выражения в ExpressionList могут быть любыми численными, строковыми или логическими выражениями. Выражение в ExpressionList может также определять диапазон значений при использовании оператора То:
expression! То expression2
Например, для определения диапазона чисел от 10 до 150 в операторе Case ExpressionList используется следующее выражение:
Case 10 То 150
Для выбора ветвей на основе сравнения, является ли TestExpression больше, меньше или равным какому-либо значению, или на основе какого-либо другого реляционного сравнения, используйте следующий синтаксис:
СИНТАКСИС
Is Comparisonoperator expression
В этой строке ComparisonOperator — это любые VBA-операторы отношения, кроме операторов Is и Like; expression — любое выражение VBA.
Для выполнения операторов в ветви Case, когда, например, TestExpression больше 10, используется следующее выражение:
Case Is > 10
Ключевое слово Is здесь — это не то же самое, что оператор Is. В этом операторе Is означает ссылку на TestExpression.
Листинг 8.7 представляет пример оператора Select Case.
Листинг 8.7. Оператор Select Case
1	Sub	EvalDiscount3()
2	' Определение скидки (в %) в зависимости от	
3	’ количества продаваемого товара	
4		Dim IStr As String
5		Dim IntNum
6		IntNum = Application.InputBox(
7		promptВведите количество товара",
8		Title:="Процедура EvalDiscount3",
9		Type:=l)
10		If Not (TypeName(VarWeight) = "Boolean") Then
11		Select Case IntNum
12		Case Is > 1000
13		IStr = "10"
14		Case Is > 500
15		IStr = "5 "
16		Case Else
17		IStr = "0 "
18		End Select
19		MsgBox "Скидка " & IStr & "%"
20		Else
21		MsgBox "Количество не указано"
22		End If
23	End	Sub
204
Глава 3
Обратите внимание на строки 11-18. После рассмотрения двух предыдущих примеров эти строки не могут не вызвать вздох облегчения. Эта конструкция хороша и простотой для понимания, и легкостью при наращивании новых условий. В остальном код этого примера переписан из предыдущих листингов.
Безусловный переход
Оператор безусловного перехода, пожалуй, самый спорный оператор во всех языках программирования. В ранних языках он являлся почти единственным средством организации циклических выполнений блоков кода. Сторонники структурного программирования посвящают много времени критике программ и языков программирования, в которых используется этот оператор. Поэтому не очень увлекайтесь применением этого оператора в своем коде и старайтесь вспоминать о нем только в чрезвычайных ситуациях, когда все другие средства уже испробованы и не помогли.
Оператор безусловного перехода всегда изменяет порядок выполнения операторов в процедуре или функции VBA. При этом VBA не проверяет никаких условий (отсюда термин безусловный (unconditional)), а просто переходит к выполнению кода с другого места.
VBA имеет только один оператор безусловного перехода: GoTo. Существует очень мало причин для использования оператора GoTo; в действительности процедуры, которые используют несколько операторов GoTo, трудны для понимания. Почти в каждом случае, когда вы можете использовать оператор GoTo, можно использовать один из операторов If, оператор Select Case или одну из структур организации циклов, о которых вы узнаете в главе 11, для выполнения той же задачи с большей легкостью и ясностью.
Оператор GoTo остался от ранних версий языка программирования BASIC, которые не имели сложного оператора принятия решений Select Case, описанного в этой главе, или мощных структур организации циклов. Программисты, работавшие с ранними версиями BASIC, использовали GoTo для имитации результатов более сложных операторов VBA.
Следует знать, как оператор GoTo работает в качестве оператора безусловного перехода, главным образом для того, чтобы понимать, как действует обработчик ошибок GoTo, но также потому что вам может встретиться эта команда, используемая другими программистами.
Оператор GoTo имеет следующий синтаксис:
СИНТАКСИС
GoTo line
Выражение line представляет любую допустимую метку или номер строки в той же процедуре или функции, которая содержит оператор GoTo. При выполнении оператора GoTo VBA немедленно переходит к выполнению оператора в строке, определенной с помощью line.
Метка строки (line label) — это особый тип идентификатора, который задает определенную строку по имени. Метки строк имеют следующий синтаксис:
СИНТАКСИС
Name:
Выражение пате — любой допустимый идентификатор VBA. Метка строки может начинаться в любом столбце в строке, если она является первым непустым символом в строке. Номер строки (line number) — в основном, то же самое, что и метка строки, но он является просто номером, а не идентификато
Изменение порядка выполнения операторов в VBA
205
ром. Использование номеров строк в процедурах VBA является крайне нежелательным, следует всегда использовать метку строки вместо них.
В листинге 8.8 показана процедура, демонстрирующая наиболее обоснованное использование оператора GoTo в процедуре VBA: эта процедура использует оператор GoTo для перехода к концу процедуры при выборе пользователем командной кнопки Отмена (Cancel) в окне ввода.
Листинг 8.8. Пример использования оператора GoTo
1	Sub EvalDiscount4()
2	' Определение скидки (в %) в зависимости от
3	' количества продаваемого товара
4	Dim IStr As String
5	Dim IntNum
6	IntNum = Application.InputBox(	_
7	prompt:“"Введите количество товара",	_
8	Title : “''Процедура EvalDiscount4 " , _
9	Type:=l)
10
11	If TypeName(VarWeight) = "Boolean" Then GoTo EndSubCancel
12
13	Select Case IntNum
14	Case	Is >	1000
15	IStr	=	"10"
16	Case	Is >	500
17	IStr	=	"5 "
18	Case	Else
19	IStr	=	"0 "
20	End Select
21
22	MsgBox "Скидка " & IStr & "%"
23	GoTo EndSub
24
25	EndSubCancel:	' обработка отмены ввода в окне InputBox
26	MsgBox "Количество не указано"
27
28	EndSub:	' успешное окончание работы
29
30	End Sub
В строке 11 определяется, были ли введены данные в окне диалога. Если пользователем была выбрана кнопка Отмена, код продолжает выполняться со строки 25, на которую указывает метка EndSubCancel. Если же данные введены успешно, процедура продолжает выполняться со строки 13. В строке 23 снова встречается оператор безусловного перехода для того, чтобы обойти строку 26 и не выдавать сообщения о том, что количество не было введено.
Еще раз отметим, что так процедуры писать не нужно. Это — просто пример оператора GoTo. И лучше пока забыть о существовании этого оператора.
Использование MsgBox для обеспечения возможности выбора
До сих пор вы использовали оператор MsgBox с целью отображения сообщений для пользователя в диалоговых окнах с заголовками. Как уже отмечалось в главе 6, при помощи необязательного аргумента Buttons можно использовать VBA-процедуру MsgBox как функцию для получения выбора от пользователя в от
206
Глава 8
вет на сообщения или вопросы, которые отображает ваша процедура. Для многих простых вариантов выбора использование функции MsgBox для получения ответа от пользователя является гораздо более легким, чем получение текстового ввода с помощью функции InputBox и последующий анализ этого текста для определения того, какой выбор сделал пользователь.
При включении аргумента Buttons с необходимыми круглыми скобками оператор MsgBox работает подобно функции и отображает окнб сообщения, содержащее различные командные кнопки. MsgBox возвращает численный результат, указывающий, какую командную кнопку выбрал пользователь. Число и тип командных кнопок, отображаемых диалоговым окном MsgBox, задается с помощью аргумента Buttons.
В листинге 8.9 показана простая процедура, которая демонстрирует использование аргумента Buttons.
Листинг 8.9. Использование MsgBox и аргумента Buttons для получения пользовательского ввода
1	Sub Demo_MsgBoxFunction()
2	' Процедура демонстрирует MsgBox, используемую как функция
3
4	Const mTitle = "Демонстрация кнопок MsgBox"
5	Dim Resp As Integer
6
7	Resp = MsgBox(prompt:="Выберите кнопку", _
8	Title:=mTitle,
9	Buttons:=vbYesNoCancel + vbQuestion)
10	Select Case Resp
11	Case Is = vbYes
12	MsgBox prompt:="Вы выбрали кнопку 'Да'”, _
13	Title:=mTitle, _	,
14	Buttons:=vblnformation
15	Case Is = vbNo
16	MsgBox prompt:="Вы выбрали кнопку 'Нет'", _
17	Title:=mTitle, _
18	Buttons:=vblnformation
19	Case Is = vbCancel
20	MsgBox prompt:="Вы выбрали кнопку 'Отмена'", _
21	Title:=mTitle, _
22	Buttons:=vbCritical
23	End Select
24	End Sub
Процедура Demo_MsgBoxFunction демонстрирует использование оператора MsgBox как функции, результаты различных аргументов Buttons и оценку значения, которое возвращает функция MsgBox. Диалоговое окно, в котором пользователю необходимо сделать выбор, представлено на рис. 8.3. Результаты работы кода этой процедуры при всех трех (по отдельности, конечно) выборах представлены на рис. 8.4.
Рис. 8.3
Окно кода листинга 8.9 предоставляет пользователю выбор из трех кнопок
Выберите кнопку
Yes
No
Cancel
Изменение порядка выполнения операторов в VBA
207
Рис. 8.4. Такие сообщения можно получить при выборе различных кнопок в диалоговом окне функции MsgBox
Аргумент Buttons для MsgBox позволяет задавать количество и тип кнопок и наличие или отсутствие в окне сообщения одного из значков Windows для обозначения предупредительного сообщения (Warning message), сообщения запроса (Query message), информационного сообщения (Information message) и критического предупредительного сообщения (Critical Warning message). Можно также использовать аргумент Buttons для определения того, какая из отображаемых кнопок (кнопка 1, 2, 3 или 4) является кнопкой по умолчанию в окне сообщения. Каждый раз можно задавать только один тип кнопки, один значок и одну кнопку по умолчанию.
В строке 9 (часть оператора вызова функции MsgBox, начинающегося в строке 7) константа vbYesNoCancel определяет, что диалоговое окно MsgBox должно содержать три командные кнопки: кнопку Yes (Да), кнопку No (Нет) и кнопку Cancel (Отмена). Константа vbQuestion определяет, что окно сообщения должно содержать значок сообщения запроса (Query message) Windows.
Как только пользователь выбирает командную кнопку в окне сообщения, VBA возвращает численное значение, соответствующее выбору пользователя. В строке 7 результат функции MsgBox присваивается переменной Resp. VBA использует различные значения в зависимости от того, какую командную кнопку выбрал пользователь: одно значение для обозначения кнопки Yes, другое — для обозначения кнопки No и еще одно — для кнопки Cancel. Функция MsgBox может также отображать окна с кнопками Abort (Стоп), Retry (Повтор) и Ignore (Пропустить) в различных комбинациях. Поскольку каждая кнопка имеет свое определенное возвращаемое значение, VBA имеет несколько внутренних констант для представления возможных возвращаемых значений функции MsgBox. Полный список значений констант VBA, которые может возвращать MsgBox, приведен в главе 6.
В строке 10 начинается оператор Select Case, который оценивает значение, возвращаемое функцией MsgBox в строке 7 и сохраняемое в переменной Resp. Тестовое выражение для оператора Select Case — это сама переменная Resp, поэтому VBA сравнивает значение в переменной Resp, чтобы проверить, совпадает ли оно с каким-либо условием Case ь операторе Select Case.
Помните, что можно увидеть все доступные внутренние константы, имеющие отношение к MsgBox, в окне Object Browser (Просмотр объектов). Для просмотра внутренних констант аргумента Buttons выберите VBA в списке Project/Library (Проект | Библиотека) в окне Object Browser, а затем выберите VbMsgBoxStyle в списке Classes (Классы); список Members of 'VbMsgBoxStyle' (Компонент) отображает внутренние константы для значений аргумента Buttons. Если вы выберете VbMsg-BoxResult в списке Classes, список Members of 'VbMsgBoxResult' отображает внутренние константы для возвращаемого значения функции MsgBox.
Остается один элемент, который можно задать с помощью аргумента Buttons для MsgBox и который не был включен в листинг 8.9: можно указать, является ли первая, вторая, третья или четвертая командная кнопка в окнах MsgBox кнопкой по умолчанию.
Как вы видели до сих пор, MsgBox обычно делает первую командную кнопку в своем окне кнопкой по умолчанию. Посмотрите на рис. 8.3 и обратите внимание,
208
Глава 8
что кнопка Yes помечена как кнопка по умолчанию. Если после того, как VBA отобразит это диалоговое окно, пользователь нажимает на клавишу Enter, VBA действует так, как если бы пользователь выбрал клавишу Yes.
Вам может понадобиться, чтобы кнопкой по умолчанию была какая-либо другая кнопка, а не первая в списке в окне сообщения. Например, если вы используете MsgBox для запроса от пользователя подтверждения удалить рабочий лист в рабочей книге, может быть предпочтительнее, чтобы командной кнопкой по умолчанию была кнопка No, а не кнопка Yes; поскольку удаленный рабочий лист не может быть восстановлен, имеет смысл помочь пользователю избежать нечаянного подтверждения удаления при простом нажатии на клавишу Enter.
Чтобы изменить командную кнопку по умолчанию, добавьте одну из внутренних констант VBA — vbDefaultButtonl, vbDefaultButton2, vbDefaultButton3 или vbDefaultButton4 — к аргументу Buttons. Следующий фрагмент процедуры показывает оператор MsgBox из строк 7-9 листинга 8.9, модифицированный так, чтобы командной кнопкой по умолчанию в окне сообщения была кнопка No:
Resp = MsgBox(prompt:="Выберите кнопку", _
Title:=mTitle, _
Buttons:=vbYesNoCancel + vbQuestion + _
VbDefaultButton2)
При выполнении этого оператора VBA отображает диалоговое окно, показанное на рис. 8.5. Это окно идентично окну, показанному ранее на рис. 8.3, за исключением того, что добавление значения vbDefaultButton2 к аргументу Buttons делает вторую кнопку (в данном случае — кнопку No) кнопкой по умолчанию.
Рис. 8.5
Сравните это диалоговое окно с окном, показанным на рис. 8 3. Заметьте, что кнопка No является теперь командной кнопкой по умолчанию как результат добавления vbDefaultButtonZ к аргументу Buttons.
Глава 9
Дополнительные свойства процедур и функций
Теперь, когда вы знаете уже достаточно много о процедурах и функциях, а также об управлении выполнением кода на VBA, рассмотрим некоторые дополнительные свойства процедур и функций, использование которых открывает новые возможности для написания хорошего кода.
Раннее окончание процедур, функций и целых программ
Существуют обстоятельства, такие как отмена окна ввода пользователем или отсутствие некоторых ожидаемых данных, при которых нет смысла продолжать выполнение процедуры или функции. Если у вас имеется программа, содержащая процедуры, которые вызывают другие функции и процедуры, вы можете задать условия, при которых вся программа должна прекращать выполнение: например, отсутствует рабочий лист, диапазон, документ и так далее.
VBA имеет операторы Exit и End, которые дают возможность либо завершать процедуру или функцию, либо останавливать всю программу.
Использование оператора Exit
Для того чтобы процедура или функция прекратила выполнение, используется одна из двух доступных форм VBA-оператора Exit, в зависимости от того, необходимо ли завершить функцию или процедуру.
Оператор Exit имеет две синтаксические формы:
СИНТАКСИС
Exit Sub
Exit Function
Exit Sub и Exit Function работают одинаково и имеют один и тот же результат; Exit Sub используется для окончания процедуры, a Exit Function — для окончания функции.
Сначала рассмотрим простой пример — листинг 9.1, который отличается от листинга 8.8 тем, что в нем нет оператора GoTo.
Листинг 9.1. Пример использования оператора Exit Sub 1 2 3 4 5 6 7 8
1 Sub EvalDiscountb()
2 1 Определение скидки (в %) в зависимости от
3 ' количества продаваемого товара
4	Dim IStr As String
5	Dim IntNum
6	IntNum = Application.InputBox(	_
7	prompt:^"Введите количество товара",
8	Title:="Процедура EvalDiscountb",
210
Глава 9
9	Туре:=1)
10
11	If TypeName(VarWeight) = "Boolean" Then
12	MsgBox "Количество не указано"
13	Exit Sub
14	End If	•	.
15	"	'
16 Select Case IntNum	.
17	Case Is > 1000
18	IStr = "10"
19	. Case Is > 500
20	IStr = "5 "
21	Case Else
22	IStr = "0 "
23 End Select
24
25 MsgBox "Количество: " & Str(IntNum) S ". Скидка " S IStr 4 "%"
26
27 End Sub
В строках 11-14 этой процедуры содержится код проверки того, была ли выбрана пользователем в окне ввода кнопка Cancel. Если это — так, программа выдает сообщение о том, что вес не был введен, и прекращает выполнение кода оператором Exit Sub. Для такой небольшой задачи это — самый подходящий код. Видимо, даже сторонники структурного программирования не найдут здесь причин для критики, хотя оператор Exit Sub также нельзя отнести к структурным языковым конструкциям.
В листинге 9.2 приведена процедура MakeSalesRpt_Chart, в которой также для раннего окончания процедуры используются операторы Exit Sub. Причиной раннего окончания процедуры является отказ пользователя от ввода имени рабочего листа (в Excel). Можно только представить последствия выполнения кода без проверки того, ввел ли пользователь имя листа для дальнейшей его обработки!
Листинг 9.2. Использование оператора Exit Sub
1 Sub MakeSalesRpt_Chart()
2 ' Запрашивает имя листа, содержащего исходные данные,
3 ' затем запрашивает диапазон ячеек с данными для диаграммы.
4 1 11 Далее запрашивается имя листа для помещения в него круговой
5 ' диаграммы. Затем процедура создает диаграмму и использует
6 ' метод Chartwizard для получения круговой диаграммы
7
8 Const sTitle = "Отчет о продажах"	,
9
10	Dim	SrcShtName As String	1
11	Dim	SourceRng As String
12	Dim	DestShtName As String
13
14	' получить имя исходного	листа
15 SrcShtName = InputBox(prompt:= _
16	"Введите имя листа,	" &	_
17	"содержащего данные	для	диаграммы",	_
18	Title:=sTitle)
19	' проверить: введено ли имя
20 If Len(Trim(SrcShtName)) = 0 Then
21	MsgBox "Имя с данными не введено - конец работы"
22	Exit Sub
23	End If
24	' выбор листа, на который	указал пользователь
25	Sheets(SrcShtName).Select
26
Дополнительные свойства процедур и функций
211

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
' получить диапазон (с данными)
SourceRng = InputBox(prompt:= _
"Введите диапазон с данными для диаграммы, " & _
"используя R1C1 формат:", _
Title:=sTitle)
' проверка: введен ли диапазон
If Len(Trim(SourceRng)) = 0 Then
MsgBox "Диапазон данных не введен - конец работы"
Exit Sub
End If
' получить имя листа для помещения в него диаграммы DestShtName = InputBox(prompt:= _
"Введите имя листа для диаграммы:", _
Title:=sTitle)
' проверка: не выбрана ли Отмена
If Len(Trim(DestShtName)) = 0 Then
MsgBox "Лист для диаграммы не введен " & _ конец работы"
Exit Sub
End If
' выбор листа и создание диаграммы
Sheets(DestShtName).Select
ActiveSheet.ChartObjects.Add(96, 37.5, 234, 111).Select
' использование метода Chartwizard для создания диаграммы With Sheets(SrcShtName)
ActiveChart.Chartwizard Source:=.Range(SourceRng), _
Gallery:=xlPie, _
Format:=7, _
PlotBy:=xlColumns, _
.	CategoryLabels:=1, _
SeriesLabels:=1, _
HasLegend:=l, _
Title:="0тчет о продажах"
End With
End Sub
Процедура MakeSalesRpt_Chart является отредактированной версией записанного рекордером макроса Excel 2000. Сначала был записан макрос для создания фрагмента диаграммы. Затем этот макрос был скопирован в другой модуль и отредактирован с добавлением объявления различных констант и переменных. В процедуру были добавлены операторы VBA для ввода данных от пользователя и оценки вводимых данных. (Заметьте, что процедура работает только в Excel.)
В переменной SrcShtName сохраняется (строки 15-18) имя рабочего листа, в котором содержатся данные для графического изображения, в SourceRng (строки 28-31) — диапазон данных для диаграммы, в DestShtName (строки 39-41) — имя рабочего листа для помещения в него диаграммы.
После каждого ввода данных результат операции ввода проверяется. Если данные не введены, работа процедуры заканчивается оператором Exit Sub.
Оператор Exit Sub приводит к тому, что VBA немедленно прекращает выполнение кода процедуры. После выполнения операторов Exit Sub VBA прекращает выполнение текущей процедуры и возвращается к выполнению той процедуры или функции, которая вызвала процедуру, содержащую оператор Exit Sub.
Используйте оператор Exit Sub или Exit Function вместо GoTo для раннего окончания процедуры или функции. Оператор Exit Sub более очевидно показывает, что процедура закончит выполнение. И, следовательно, ее легче писать, читать и понимать.
212
Глава 9
Использование оператора End
Вы уже знакомы с ключевыми словами End Sub и End Function, используемыми для сообщения VBA о достижении конца процедуры или функции. Эти ключевые слова-инструкции указывают VBA прекратить выполнение кода текущей процедуры или функции и возобновить выполнение кода процедуры или функции, которая вызвала текущую процедуру или функцию; если текущая процедура не была вызвана другой процедурой, VBA прекращает выполнение всех операторов.
Одним из хороших принципов программирования является принцип модульности. Процедура не должна содержать бесконечно длинный код, части которого выполняют совершенно не связанные между собой задачи. Следует помещать в каждую процедуру небольшой и функционально законченный код, который легко читать и сопровождать. Например, хорошо понимается код со следующей структурой:
Sub ГлавнаяПроцедура()
' Вызов процедуры Процедура!
Call Процедура!
' Вызов процедуры Процедура?
Call Процедура?
' Вызов процедуры Процедура?
Call Процедура?
End Sub
Sub Процедура!() ' Код процедуры End Sub
Sub Процедура? ()
' Код процедуры
End Sub
Sub Процедура?()
' Код процедуры
End Sub
Можно также встретить и следующий код:
Sub ГлавнаяПроцедура()
' Вызов процедуры Процедура!
Call Процедура!
End Sub	*
Sub Процедура!()
' Вызов процедуры Процедура?
Call Процедура?	t
End Sub
Sub Процедура?()
' Вызов процедуры Процедура?
Call Процедура?
End Sub
Sub Процедура?()
' Код процедуры
End Sub
Обратите внимание на то, что в этих фрагментах кода процедуры не возвращают никаких результатов свой работы. Это может быть только в случае, когда эти процедуры по очереди обрабатывают какие-то общие данные, выполняя над ними определенные действия. Результатами этих действий могут быть либо сами преобразованные данные, либо новые (и тоже общие) данные.
Представим такую ситуацию, когда обработка данных одной процедурой зависит от результатов обработки этих данных другой процедурой, выполняемой рань
Дополнительные свойства процедур и функций
213
ше. Вполне возможно, что по каким-то причинам (пользователь неправильно ввел имя листа с данными, вообще отказался от ввода, неправильно введены числовые и другие данные) одна из процедур не подготовила данные для обработки следующей процедурой. В этом случае весь процесс обработки данных следует прекратить и в дальнейшем никаких процедур не вызывать, т.е. просто закончить работу всей программы. При этом даже необязательно возвращаться в вызывающую процедуру, особенно если предусмотреть перед каждым выходом из программы вывод окна с сообщением о том, почему и где было прервано выполнение кода.
Для полного завершения выполнения программы с помощью VBA используйте ключевое слово End одно в отдельной строке:
End
При выполнении этого оператора VBA прекращает все выполнение операторов процедуры и функции. Любые имеющиеся переменные перестают существовать и их значения теряются.
В листинге 9.3 показана функция GetBookName, которая полностью заканчивает любую программу, выполняемую VBA, если пользователь отменяет окно ввода.
Листинг 9.3. Прекращение выполнения программы оператором End
1	Function GetBookName(ByVai IDflt As String, _
2	Optional Prmpt, _
3	Optional ITitle) As String
4	' включен ли параметр Prmpt в список аргументов?
5	If IsMissing(Prmpt) Then Prmpt = "Введите имя книги:"
6
7	' если	IDflt	не	является пустой	строкой,	преобразовать
8	' ее к	верхнему	регистру, иначе	присвоить	IDflt	имя
9	If IDflt О "" Then
10	IDflt = UCase(IDflt)
11	Else
12	IDflt = "NEWFILE.XLS"
13	End If
14
15	' использовать InputBox для получения имени файла
16	GetBookName = InputBox(prompt:“Prmpt, _
17	Title:“ITitle,
18	Default:=lDfIt)
19
20
21	' проверка: не была ли произведена отмена
22	If Len(Trim(GetBookName)) = 0 Then
23	MsgBox prompt:“"Окончание программы", Title:“ITitle
24	End
25	End If
26 End Function
27
28
29 Sub TestGetBook_Name()
30 ' Тестирование функции GetBookName
31
32	MsgBox GetBookName(IDflt_
33	ITitle:“''Тестирование выхода из программы")
34	End Sub
Пишите процедуры или функции, использующие оператор End, для отображения некоторого сообщения пользователю о том, что будет происходить и почему, перед оператором, который фактически содержит оператор End. В противном случае пользователи вашей процедуры могут не понять, почему процедура или программа, которую они используют, внезапно прекратила работу. Если программа
214
Глава 9
перестанет выполняться вследствие какого-либо действия пользователя, такого как отмена окна ввода, без объяснения, пользователь процедуры может никогда не узнать, почему процедура заканчивается; в действительности, пользователи склонны считать, что это происходит из-за ошибки в процедуре.
Не забывайте закрывать рабочие книги или выполнять другую сервисную работу перед выполнением оператора End, чтобы пользователю программы не приходилось, например, доделывать наполовину законченные диаграммы или иметь дело с рабочими книгами, которые имеют несохраненные данные, когда ваша программа прекращает выполнение.
Дополнительные свойства необязательных аргументов
Необязательные аргументы функции могут объявляться с типом (иначе, по умолчанию, они имеют тип Variant). Тип необязательного аргумента объявляется по тем же причинам, что и тип обязательного аргумента: для того, чтобы правильно использовать функции и обнаруживать операторы, которые передают функции неверные значения.
Тип необязательного аргумента объявляется тем же способом, что и тип обязательного аргумента — с помощью ключевого слова As. Следующий фрагмент кода показывает объявление функции с типом необязательного аргумента nChar как Long:
Function UpCase(tStr As String, Optional nChar As Long) As String
Всякий раз при объявлении необязательного аргумента функции VBA резервирует место для этого аргумента. Поскольку необязательные аргументы могут присутствовать или не присутствовать во время вызова функции, можно указать VBA присваивать необязательному аргументу значение по умолчанию. VBA использует значение по умолчанию каждый раз, когда функция вызывается без этого включенного конкретного необязательного аргумента. Значение по умолчанию присваивается необязательному аргументу с помощью знака равенства (=) и предоставления константного значения так же, как при объявлении именнованной константы.
Function GetBookName5(Optional IDflt As String - "Книга1") As String
Листинг 9.4 содержит функцию GetBookName5, полученную из подобной функции листинга 8.4. Здесь необязательный аргумент объявлен с типом и значением по умолчанию.
S Функция IsMissing работает только с необязательными аргументами типа Variant. Для всех других типов необязательных аргументов VBA инициализирует значение J аргумента, как для любой новой переменной (строки имеют нулевую длину и численные типы равны 0), a IsMissing всегда возвращает False. Чтобы обнаружить пропущенный типизированный необязательный аргумент, тестируйте его на равен-ство 0 или строке нулевой длины.
Листинг 9.4. Функция GetBookName5
1	Function GetBookName5(Optional IDflt As String = "Книга1") As String
2	Dim ITitle As String, IPrmpt As String, IVar As String
3
4	ITitle = "Ввод наименования книги"
5	IPrmpt = "Введите наименование новой книги"
6
7	' использование InputBox для получения имени файла.
8	IVar = Trim(InputBox(prompt:=lPrmpt, _
9	Title:=lTitle,
10	Default:=lDfIt))
Дополнительные свойства процедур и функций
215
11
12	' проверить наличие строки ввода
13	If Len(lVar) = 0 Then
14	MsgBox "Наименование не введено!"
15	GetBookName5 = lDflt ' имя по умолчанию
16	Else
17	GetBookName5 = IVar
18	End If
19
20 End Function	' GetBookName
21
22 ' Тестирование функции GetBookName5
23 Sub Test_GetBookName5()
24 MsgBox GetBookName5("Новая_Книга")
25 End Sub
Сравните этот код с кодом листинга 8.4. Не правда ли, этот код более изящен?
Управление передачей аргументов
Теперь, когда вы знаете, как создавать функции-процедуры с типизированными и необязательными аргументами, кажется, что еще можно делать с аргументами, чтобы программы обладали большими возможностями? Оказывается, существуют механизмы, которые VBA использует для фактической передачи (и возвращения) данных-аргументов функции-процедуре, и вы можете управлять этими механизмами.
Передача аргументов по ссылке и по значению
Существует два способа, которыми VBA передает информацию в функцию-процедуру: по ссылке (by reference) и передача аргументов по значению (by value). По умолчанию VBA передает все аргументы по ссылке. При передаче данных функции посредством аргумента по ссылке VBA на самом деле только передает адрес памяти, который ссылается на исходные данные, определенные в списке аргументов функции во время вызова функции. Это означает, что если функция изменяет значения в любом из аргументов, исходные данные, переданные функции посредством этого аргумента, также изменяются.
При передаче аргумента по значению VBA делает копию исходных данных и передает эту копию функции. Если функция изменяет значение в аргументе, передаваемом по значению, изменяется только копия данных; исходные данные не изменяются. Передача по ссылке позволяет с помощью функции изменять исходные данные, передаваемые функции посредством аргумента; передача же по значению не позволяет изменять значение исходных данных.
Поскольку передача по ссылке позволяет функции изменять значение исходных данных ее аргументов, аргументы, передаваемые по ссылке, могут получить нежелательные побочные значения. Листинг 9.5 содержит код функции Sconcat, которая объединяет две строки, передаваемые ей как параметры по ссылке. Перед объединением строк из них удаляются начальные и хвостовые пробелы. При этом операторы удаления пробелов в качестве промежуточных переменных используют сами аргументы, таким образом меняя их значения. Результат работы программы тестирования функции Sconcat приведен на рис. 9.1.
Листинг 9.5. Побочные результаты функции Sconcat
1	Function Sconcat(argl As String, arg2 As String) As String
2	argl = Trim(argl)
3	arg2 = Trim(arg2)
216
Глава 9
4	Sconcat = argl S arg2
5	End Function	i
6
7	Sub Test_Sconcat()
8	Dim al	As String,	a2 As	String	>
9	al = "	Значение	al:	"
10	a2 = "	Значение	a2:	"
11	MsgBox	al S a2, ,	"До	вызова	Sconcat"
12	MsgBox Sconcat(al, a2), , "При вызове Sconcat"
13	:	MsgBox al S a2, , "После вызова Sconcat"
14	: End Sub
Рис. 9.1. Результаты тестирования функции Sconcat из листинга 9 5
Из рис. 9.1 видно, что после вызова функции Sconcat значения переменных al и а2 изменились.
Определение способа передачи аргумента
Понятно, что побочные результаты, вызванные изменением функцией значений в аргументах, передаваемых по ссылке, являются необязательными и в большинстве случаев — нежелательными. Они могут привести к серьезным проблемам в программах. Часто бывает трудно отследить проблемы, вызванные побочными результатами, потому что редко причина какого-либо изменения значения переменной является очевидной. (Побочный результат (side effect) — это общий термин для обозначения любого изменения в значении переменной в среде выполняющейся программы, которое не запрограммировано явно.)
Для предупреждения таких побочных результатов необходимо, чтобы функция работала с копией значения аргумента, а не с исходными данными. Можно было бы, конечно, объявить локальную переменную в функции-процедуре и копировать аргумент в эту локальную переменную. Копирование значений аргумента в локальные переменные функции обычно нежелательно. Дополнительные переменные увеличивают объем памяти, необходимой для функции, и количество выполняемой программистом работы. Дополнительные переменные могут также привести в беспорядок программный код, усложняя его до ошибочного.
Более легкий и предпочтительный способ обеспечить работу функции только с копиями значения аргумента, а не с исходным значением — это указать VBA, что аргумент должен передаваться по значению, а не по ссылке. (Помните, передача по значению дает функции копию значения аргумента; передача по ссылке открывает функции доступ к исходным данным в аргументе.)
Чтобы явно указать, передает VBA аргумент по значению или по ссылке, используйте ключевое слово ByVai или ByRef перед аргументом, для которого необходимо задать метод передачи. Как можно понять по именам ключевых слов, при использовании ByVai VBA передает аргумент по значению, а при ByRef — по ссылке.
Изменим объявление функции Sconcat2 (листинг 9.6) с целью передачи ей аргументов по значению и протестируем получившийся код.
Дополнительные свойства процедур и функций
217
Листинг 9.6. Устранение побочных результатов функции Sconcat в функции Sconcatl
1	Function Sconcat2(ByVai argl As String, ByVai arg2 As String) As String
2	argl = Trim(argl)
3	arg2 = Trim(arg2)
4	Sconcat2 = argl S arg2
5	End Function
6
7	Sub Test_Sconcat2()
8	Dim al	As String,	a2 As	String
9	al = ”	Значение	al:	"
10	a2 = "	Значение	a2:	"
11	MsgBox	al S a2, ,	"До	вызова	Sconcat2"
12	MsgBox Sconcat2(al, a2), , "При вызове Sconcat2"
13	MsgBox al S a2, , "После вызова Sconcat2"
14	End Sub
Обратите внимание на то, что значения переменных al и а2 не изменились после вызова функции Sconcat2.
До вызова Sconcati
Значение а 1: Значение а2:
Рис. 9.2. Результаты тестирования функции Sconcat2 из листинга 9.6
Не следует объявлять аргументы по значению (ByVai), если только функция-процедура не изменяет этот аргумент, потому что передача аргументов по значению может использовать больше памяти и времени для выполнения, чем при передаче аргументов по ссылке — передача аргументов по значению  приводит к тому, что VBA делает копию данных для аргумента.
Объявляйте аргумент с ключевым словом ByVai для передачи его по значению, если у вас имеются сомнения, следует ли передавать этот конкретный аргумент по ссылке или по значению: потери в объеме памяти и скорости при передаче по значению не слишком велики. Кроме того, передача аргумента по значению эффективнее и делает код более понятным, чем создание вашей собственной копии значения аргумента в локальной переменной.
Рекурсия
В конце этой главы, посвященной написанию пользовательских функций-процедур, необходимо объяснить еще одно важное понятие, хотя оно и не является непосредственно частью процесса создания функций-процедур VBA. Более того, этот материал предназначен не для начинающих программистов и может быть пропущен при первом чтении данной книги.
Рекурсивная (recursive) функция или процедура — это функция или процедура, которая вызывает сама себя. Почти во всех случаях, рекурсия является ошибкой программирования и приводит к полному сбою программы. Наиболее общим симптомом возникновения этой проблемы является ошибка из-за нехватки памяти или ошибка из-за нехватки памяти в стеке. Стек (stack) — это временная рабочая область компьютерной памяти. VBA использует стековую память для сохранения внутренних результатов выражений, копий аргументов функций, передаваемых
218
Глава 9
по значению, результатов функций-процедур и в других случаях, когда необходима временная рабочая область.
Примеры рекурсивных функций1
Самый простой пример, который может продемонстрировать рекурсивную функцию, это — пример функции возведения числа в степень. Алгоритм функции fPower основан на том факте, что число, возведенное в степень п, равно этому же числу, умноженному само на себя в степени n—1. Например, 23 равно 2х23-1 или 2х22.
Листинг 9.7 содержит код функции fPower, возвращающей степень числа. В качестве аргументов функция принимает число и степень, в которую нужно возвести это число.
Листинг 9.7. Функция fPower пример рекурсии
1	Function fPower(num As	Double, pwr	As Integer)	As Double
2 3	' рекурсивное возведение в степень If pwr = 0 Then			
4 5	fPower = 1 Else	' окончание рекурсии		
6 7 8 9 10 11 12	fPower = num * End If End Function Sub Test_fPower() MsgBox fPower(2, 3) End Sub	fPower(num,	pwr - 1)	'	рекурсия
Функция fPower имеет два обязательных аргумента: num и pwr, и возвращает результат типа Double. В строке 6 функция вызывает сама себя. Чтобы понять, как работает функция fPower, рассмотрим порядок выполнения кода функции, вызванной процедурой Test_fPower.
В этом случае при первом обращении аргумент num (и всегда) имеет значение 2, a pwr — значение 3. В строке 3 начинается оператор If...Then, который определяет момент прекращения рекурсии. Здесь проверяется, равно ли значение переменной pwr нулю. В этом вызове значение pwr равно 3, поэтому выполнение функции продолжается в строке 6.
В строке 6 выполняется присваивание функции; выражение, присваиваемое результату функции fPower, указывает на то, что результат функции равен значению num, умноженному на результат следующего вызова функции fPower со вторым аргументом, равным pwr—1.
Если подставить литеральные промежуточные значения для этого примера в данное выражение, вызов функции fPower в строке 6 в этом месте будет следующим:
FPower(2,2)
Это — второй вызов функции fPower; значение аргумента pwr теперь равно 2. В строке 3 проверяется, равно ли нулю значение аргумента pwr; если — нет, VBA снова выполняет присваивание функции в строке 6. Выражение в присваивании функции вызывает функцию fPower снова, передавая pwr—1 в качестве второго аргумента.
Если мы опять подставим литеральные промежуточные значения для этого примера в выражение в строке 6, вызовом функции fPower в этом месте будет:
FPower(2,1)
1 К сожалению, автор не имел достаточно времени, чтобы придумать пример рекурсии, который бы относился к области бизнеса и был достаточно простым.
Дополнительные свойства процедур и функций
219
В этом третьем вызове функции fPower значение pwr теперь равно 1. В строке 3 проверяется, не равно ли нулю значение аргумента pwr; если — нет, то присваивание функции в строке 6 выполняется третий раз, приводя в результате к четвертому вызову fPower.
В четвертом вызове функции fPower значение pwr равно О; результатом проверки (в строке 3) на равенство нулю значения аргумента pwr является True, и VBA выполняет строку 4, заканчивая рекурсию. Строка 4 — это еще один оператор присваивания функции, на этот раз присваивающий число 1 как результат функции. (Любое число, возведенное в степень О, равно 1).
В вызовах 1-3 функции fPower функция не возвратила никакого результата; VBA не может полностью вычислить выражение в операторе присваивания функции (строка 6) до тех пор, пока серия рекурсивных вызовов не прекращается в четвертом вызове функции fPower. Теперь, когда функция fPower возвращает результат, рекурсивный процесс прекращается, и каждый отдельный вызов функции fPower возвращает ее результат.
Четвертый вызов fPower возвращает число 1 в выражение в строке 6 третьего вызова функции fPower. Подставим литеральные промежуточные значения из примера, и это выражение будет равно 2x1. Результат, возвращаемый третьим вызовом функции fPower, равен 2.
VBA возвращает это значение 2 выражению присваивания функции во втором вызове функции так, что (подставляем литеральные промежуточные значения) это выражение равно теперь 2x2. Второй вызов функции fPower возвращает 4 выражению присваивания функции первого вызова функции fPower.
Снова подставляются литеральные значения, и выражение из первого вызова функции fPower равно теперь 2x4. Наконец, исходный первый вызов функции fPower возвращает значение 8 — правильный результат возведения 2 в третью степень.
Если вы хотите проследить последовательность передачи аргументов функции fPower, вставьте перед строкой 3 следующий оператор:
MsgBox num & " и " & pwr
При этом в процессе тестирования предыдущего примера вы увидите последовательность окон, отображенную на рис. 9.3.
Рис. 9.3. Окна с промежуточными результатами работы функции fPower
На самом деле, нет необходимости писать функцию fPower: VBA оператор возведения в степень (") имеет такой же результат. Функция fPower была выбрана для иллюстрации рекурсии, потому что она предоставляет самый простой пример работы рекурсии.
Рассмотрим пример функции нахождения наибольшего общего делителя двух целых чисел с помощью классического алгоритма Евклида, который заключается в следующем:
1) имеются два целых числа а и Ь;
2) если остаток от деления а на b равен нулю, то b — уже наибольший общий делитель, иначе выполнить: (аО = b), (al= a Mod b), а = аО, b = al и вернуться к началу пункта 2.
220
Глава 9
Листинг 9.8. Функция GCD пример рекурсии
1	Function GCD(a As Integer, b As Integer) As Integer
2	If (a Mod b) = 0 Then
3	GCD = b
4	Else
5	GCD = GCD(b, (a Mod b))
6	End If	•
7	End Function
8
9	Sub Test_GCD()
10	Dim d As Integer
11	MsgBox GCD(a:=342, b:=612)
12	End Sub
Структура кода этой рекурсивной функции очень похожа на структуру предыдущего примера, поэтому, видимо, нет надобности анализировать ее так же подробно. В результате тестирования функции GCD при помощи процедуры Test_GCD будет получен результат 18, который и является наибольшим общим делителем исходных чисел.
Как избежать случайной рекурсии и других проблем
Теперь, когда вы знаете о том, как работает рекурсивная функция-процедура, вы готовы к рассмотрению недостатков рекурсивных программ.
Одним из наиболее очевидных недостатков рекурсивных функций и процедур является то, что их часто трудно понимать. Другой недостаток заключается в том, что они используют большой объем памяти; каждый раз, когда рекурсивная функция вызывает сама себя, VBA передает все ее аргументы снова и для результата функции резервируется область памяти. Объем памяти, используемый серией вызовов рекурсивной функции, может быть значительным в зависимости от размера аргументов (в байтах) и размера возвращаемого функцией значения (в байтах).
Почти всякую задачу, которую можно выполнить с помощью рекурсивной функции, можно также выполнить с помощью структуры цикла без дополнительных потерь памяти; структуру цикла часто легче понять, чем функцию, выполняющую работу посредством рекурсии. (Структуры цикла описываются в главе 11.)
Нечаянная рекурсия — это довольно распространенная ошибка программирования, особенно для начинающих программистов. Когда вы начинаете разрабатывать свои функции, легко ошибиться при написании оператора присваивания функции и нечаянно создать оператор, который вызывает функцию рекурсивно, вместо присваивания результата функции. Поскольку вы указываете VBA, какое значение должно быть возвращено как результат функции с помощью присваивания функции, легко также забыть, что имя функции не является переменной, и попытаться работать с именем функции как с именем переменной; такие попытки обычно приводят к случайным рекурсивным вызовам.
Если вы случайно создали рекурсивную функцию-процедуру, маловероятно, что рекурсия когда-либо закончится. Рекурсивные функции должны разрабатываться очень тщательно, чтобы обязательно было какое-либо условие, прекращающее рекурсивные вызовы. Если функция не тестирует какое-либо условие, чтобы явно завершать рекурсию (как делает функция fPower), вызовы рекурсивной функции продолжаются до тех пор, пока у VBA не заканчивается память (с возникновением ошибки времени исполнения).
Обычно при выполнении функции, которая содержит нечаянный рекурсивный вызов, компьютер как бы прерывает работу на несколько секунд перед тем, как VBA отображает ошибку времени исполнения из-за нехватки памяти.
Глава 10
Объекты и коллекции, введение
Эта глава посвящена одной из самых интересных тем в программировании. Материал, представленный здесь, может восприниматься по-разному в зависимости от уровня подготовленности читателя. Общепризнанным считается мнение о том, что объектно-ориентированное программирование легче воспринимается теми, кто не слишком много времени занимался традиционным (модульным) программированием. Поскольку эта книга в основном предназначена для тех, кто вообще никогда не программировал (для этого так подробно и разбираются многочисленные примеры), то имеется надежда, что и этот материал будет понятен и заинтересует читателя. По крайней мере, именно после прочтения этой главы можно начинать «по-настоящему» программировать в VBA.
VBA является идеальным инструментом для изучения основ объектно-ориентированного программирования, так как имеет встроенные объекты (рабочие книги и листы, ячейки, документы и выделенные фрагменты текста), их свойства и методы. Эти объекты — не выдумка, они реальны, их необходимость ощутима. Поэтому для иллюстрации объектов, свойств и методов не нужно обращаться к объектам, не имеющим никакого отношения к программированию, например, автомобилям с их свойствами (цвет, размер, скорость) и методами (изменение скорости, подача сигнала и т.д.). На примере объектов, свойств и методов, с которыми работает VBA, можно создавать свои собственные, полезные вам объекты. Можно к свойствам и методам встроенных объектов VBA добавлять новые, связанные с вашими задачами.
Объекты
В середине 80-х годов была разработана новая концепция в компьютерном программировании, известная как объектно-ориентированное программирование (object-oriented programming, OOP). Популярность объектно-ориентированного программирования с годами возрастает; новый Рабочий стол (desktop) в Windows 95, Windows NT 4.0 и Active Desktop в Windows 98/2000/XP, фактически воплощают многие объектно-ориентированные принципы. Центральная идея объектно-ориентированного программирования заключается в том, что программное приложение (как и реальный мир вокруг нас) должно состоять из особых объектов, каждый из которых имеет собственные специфические качества и поведение.
Объектно-ориентированное приложение организует данные и выполняемые операторы программного кода в связанные объекты, что облегчает разработку, организацию и работу со сложными структурами данных и действиями, выполняемыми над этими данными (или с ними). Каждый объект в программном приложении содержит данные и операторы, связанные вместе и образующие единый элемент. Большинство приложений содержат много различных типов объектов.
В Excel 2000/2002 объектами являются рабочие книги, листы, диапазоны данных, таблицы, графические объекты, диалоговые окна и само приложение Excel. В Word 2000/2002 объектами являются документы, диапазоны текста, таблицы, графические объекты, диалоговые окна и само приложение Word.
222
Глава 10
То, что вы узнаете из этой главы, поможет вашей работе с VBA не только в Word и Excel. Все host-приложения VBA, такие как Access 2000/2002 и Microsoft Project, имеют объекты, доступные для VBA таким же образом, как объекты Word и Excel. Объекты в других host-приложениях VBA существуют по тем же причинам, что и объекты в Word и Excel. Конкретные объекты в host-приложении VBA варьируют в зависимости от приложения. Объекты в Access, например, — все имеют отношение к базам данных и манипулированию базами данных, тогда как объекты в Excel связаны с понятиями рабочих листов, книг и так далее.
Свойства объекта
Как и объекты реального мира, объекты VBA имеют различные присущие им качества или свойства (properties). Объекты в Word и Excel имеют свойства, определяющие их вид и поведение: текст в документе Word может отображаться или не отображаться полужирным шрифтом или курсивом, рабочий лист Excel может быть видимым или нет, строки в рабочем листе или таблице имеют свойство высоты, столбцы имеют свойство ширины и так далее.
Свойства регулируют вид и поведение объекта. Чтобы изменить вид и поведение объекта, необходимо изменить его свойства. В Excel можно изменить поведение рабочего листа, изменяя свойство вычисления с автоматического на ручное, или можно изменить вид рабочего листа, задав новый цвет для текста или графики в листе. В Word можно изменить поведение документа, изменяя свойство, которое регулирует показ орфографических ошибок во время набора текста; можно изменить вид документа, задав новые значения для свойств разметки страницы.
Чтобы узнать о текущем виде и поведении объекта, необходимо узнать о его свойствах. Вы можете определить диск, папку и имя рабочей книги Excel или документа Word, рассмотрев свойство FullName этой рабочей книги или документа.
Некоторые свойства объекта можно изменять, некоторые — нет. Например, в рабочей книге Excel можно изменить имя автора книги, изменяя свойство Author, но нельзя изменить свойство Name рабочей книги. (Свойство Name рабочей книги содержит имя файла на диске и не может быть изменено без создания нового дискового файла или переименования файла рабочей книги вне Excel).
Некоторые объекты имеют свойства с одними и теми же или подобными именами: объекты Application, Workbook и Worksheet в Excel — все имеют свойство Name. Каждый объект рабочего листа сохраняет данные для своих свойств внутри самого рабочего листа вместе с пользовательскими данными. [Пользовательские данные (user data) — это любые данные, сохраняемые объектом, которые поступают непосредственно от пользователя подобно данным, содержащимся в ячейках рабочего листа.]
Методы объекта
Объекты реального мира почти всегда имеют тот тип присущего им поведения или действия, который они могут выполнить. Объекты VBA также имеют поведение и возможности, называемые методами (methods). Объект рабочей книги Excel, например, имеет встроенную способность добавлять к себе новый рабочий лист — метод добавления рабочих листов (называемый Add). Другой пример: документ Word имеет встроенную способность проверять орфографию текста в документе — метод проверки орфографии (называемый, как вы могли догадаться, CheckSpelling).
Методы изменяют значения свойств объектов; методы выполняют также действия с данными (или над данными), сохраняемыми объектом. Методы во многом похожи на процедуры VBA, с которыми вы уже знакомы, но связаны с объектом; к методам объекта можно обратиться, только используя объект. Это может казаться сложным, но на деле все проще. Для вызова метода объекта (функции обработ
Объекты и коллекции, введение
223
ки данных объекта) указывается не только наименование метода, но и объект (имя), которому принадлежит метод.
Одной из причин того, что объектно-ориентированное программирование стало популярной техникой проектирования, является то, что оно позволяет разработчикам программного обеспечения создавать более эффективные программы с совместно используемым кодом. Вместо сохранения отдельной копии кода для каждого метода каждого объекта VBA-объекты одного и того же типа совместно используют код своих методов.
Несмотря на то, что объекты одного и того же типа совместно используют код для своих методов, метод считается частью объекта; когда вы вызываете определенный метод для конкретного объекта, метод воздействует только на объект, посредством которого вы обращаетесь к этому методу.
После того как объект создан (если это — не встроенный объект), нет необходимости беспокоиться о том, как работают его методы и как объект сохраняет или манипулирует данными. Все, что нужно знать, — как указать объект и как указать метод, который необходимо использовать (или определенное свойство, которое нужно выбрать и изменить). Встроенный код для объекта VBA выполняет остальную работу автоматически.
Классы объекта
Программные объекты группируются в иерархические классы или коллекции объектов, как объекты реального мира вокруг нас. Все объекты в одном и том же классе имеют одни и те же (или подобные) свойства и методы. Каждый класс объектов может содержать один или несколько подклассов. Объекты, принадлежащие к определенному классу объектов, называются членами (members) этого класса.
MS Word, Excel, Access, PowerPoint, Outlook и т.д. принадлежат к общему классу объектов — host-приложений VBA. При запуске Word 97/2000/2002 на вашем компьютере вы создаете экземпляр Word 97/2000/2002. При наличии достаточных ресурсов памяти в компьютере вы можете запустить Word более одного раза; каждый раз при запуске Word будет создаваться еще один экземпляр Word. Каждый раз при создании или открытии документа в Word создается экземпляр объекта Document. Аналогично, каждая копия Excel 97/2000/ 2002, выполняемая на компьютере, является экземпляром приложения Excel, а каждая рабочая книга, открытая в данный момент, является экземпляром объекта Workbook.
VBA дает возможность пользователю создавать собственные классы объектов, добавлением модуля класса в проект. Ваш модуль класса должен содержать все определения свойств и методов для объекта. После описания нового класса вы можете создавать его экземпляры (объекты этого типа).
Использование объектов
Операторы программ VBA, использующие объекты, обычно выполняют одно или несколько из следующих действий:
	определяют текущее состояние или статус объекта путем выборки значения, сохраняемого в определенном свойстве;
	изменяют состояние или статус объекта установкой значения, сохраненного в определенном свойстве;
	используют один из методов объекта, обеспечивая выполнение объектом одной из его встроенных задач.
Например, можно определить имя активного в данный момент рабочего листа в Excel, выполняя выборку строки, сохраняемой в свойстве Name рабочего листа. (Свойство Name рабочего листа содержит имя рабочего листа, как показано на ярлычке листа.) Чтобы изменить имя рабочего листа, необходимо присвоить новую
224
Глава 10
строку свойству Name этого рабочего листа. Для добавления рабочего листа в рабочую книгу используется метод Add рабочей книги.
Прежде чем применять свойства и методы некоторого объекта, их следует сначала определить.
В операторах VBA используйте следующий общий синтаксис для определения свойства или метода объекта:
СИНТАКСИС
Object.identifier
Object — любая допустимая ссылка на объект. Объектные ссылки создаются заданием переменной для ссылки на объект или использованием методов или свойств объектов, возвращающих объектную ссылку. Identifier — любое допустимое имя свойства или метода; VBA отображает сообщение о runtime-ошибке при попытке использовать свойства или методы, которые не являются в действительности частью указанного объекта.
Если вы запустите в среде VBA Word процедуру листинга 10.1, то получите нечто подобное тому, что вы видите на рис. 10.1, т.е. в диалоговом окне функции MsgBox будет отображено наименование активного документа, хотя сама процедура может принадлежать другому документу (открытому, но не активному).
Листинг 10.1. Активный документ
1	Sub ActDocum()
2	MsgBox "Активный документ: ” & ActiveDocument.Name
3	End Sub
Рис. 10.1
Результат выполнения кода листинга 10 1
Обратите внимание на то, что точка (.) отделяет объектную ссылку от имени свойства или метода. В некотором смысле эта точка-разделитель также соединяет объектную ссылку с идентификатором свойства или метода. Поскольку вы обращаетесь к свойству или методу посредством объекта, необходимо определять объектную ссылку и идентификатор свойства или метода вместе. Точка-разделитель указывает VBA, где заканчивается объектная ссылка и где начинается идентификатор свойства или метода. В то же самое время точка-разделитель соединяет объектную ссылку и имя свойства или метода для образования единого идентификатора в операторе VBA.
В табл. 10.1 приведены несколько из наиболее важных объектов (с точки зрения программиста VBA) в Excel 2000/2002. В таблице показано имя объекта и краткое описание этого объекта. (Имейте в виду, что Excel содержит намного больше объектов, чем перечислено в табл. 10.1.)
Таблица 10.1. Общие объекты Excel 2000/2002
Объект	Описание
Application	Само приложение Excel (host-приложение)
Chart	Диаграмма в рабочей книге
Объекты и коллекции,введение
225
Объект	Описание
Font	Этот объект содержит атрибуты шрифта и стиля для текста, отображаемого в рабочем листе
Name	Заданное имя для диапазона ячеек рабочего листа
Range	Диапазон ячеек (одна или более) или именованный диапазон в рабочем ливте
Window	Любое окно в Excel; окна используются для отображения рабочих листов, диаграмм и т.д.
Workbook	Открытая рабочая книга
Worksheet	Рабочая таблица в книге
В табл. 10.2 перечислены наиболее важные объекты в Word 2000/2002. В таблице приводится имя объекта и краткое описание этого объекта. (Имейте в виду, что Word содержит намного больше объектов, чем перечислено в табл. 10.2.)
Таблица 10.2. Общие объекты Word 2000/2002
Объект	Описание
Application	Само приложение Word (host-приложение)
Bookmark	Отдельная закладка в документе
Document	Открытый документ
Font	Содержит атрибуты шрифта и стиля для текста, отображаемого в объекте
Paragraph	Отдельный параграф в документе
Range	Непрерывная область в документе
Style	Встроенный или определенный пользователем форматирующий стиль в документе
Table	Отдельная таблица в документе
TableOfContents	Отдельная таблица содержания документа
Template	Шаблон документа
Window	Любое окно в Windows
Из таблиц 10.1 и 10.2 видно, что Excel 2000/2002 и Windows 2000/2002 имеют похожие объекты.
Использование свойств объектов
Свойства объектов можно использовать только двумя способами: получать значение свойства или устанавливать его. Как уже было упомянуто в начале этой главы, не все свойства объекта изменяемы. Свойства объектов, которые нельзя изменять, называют свойствами, доступными только на чтение (read-only); свойства, которые можно устанавливать, называют свойствами, доступными на чте-ние/запись (read-write).
Свойства обычно содержат численные, строковые, значения типа Boolean, хотя некоторые свойства могут возвращать значения типа Object или другие типы данных.
8 Программирование на VBA 2002
226
Глава 10
Обращение к свойству объекта имеет следующий синтаксис:
СИНТАКСИС
Object.Property
Object — допустимая объектная ссылка VBA, тогда как Property представляет любое допустимое имя свойства для объекта, на который выполняется ссылка.
Свойства используются в выражениях так же, как любое другое значение переменной или константы. Можно присваивать значение свойства переменной, использовать свойства объектов в выражениях как аргументы к функциям и процедурам или как аргументы для методов какого-либо объекта.
Чтобы присвоить некоторой переменной значение свойства объекта, используйте следующий синтаксис:
СИНТАКСИС
Variable = Object.Property
Variable — любая допустимая переменная, имеющая совместимый со свойством объекта тип; Object — любая допустимая ссылка на объект, a Property — любое допустимое имя свойства для объекта, на который выполняется ссылка.
В следующем примере строка, сохраняемая в свойстве Name рабочего листа Excel, на которую ссылается объектная переменная aSheet, присваивается переменной AnyStr:
AnyStr = aSheet.Name
Можно также использовать свойство объекта непосредственно в каком-либо выражении или в качестве аргумента функции или процедуры. Следующие строки представляют обоснованное использование свойства объекта (в каждой строке InstSheet является объектной переменной, заданной для ссылки на рабочий лист Excel):
MsgBox InstSheet.Name
AnyStr = "Эта ячейка имеет имя: " & InstSheet.Name
MsgBox LCase(InstSheet.Name)
Почти каждый объект в VBA имеет свойство, которое содержит его имя. Следующий оператор использует MsgBox для отображения свойства FullName в объекте рабочей книги Excel; свойство FullName содержит имя диска, путь к папке и имя файла рабочей книги:
MsgBox InstBook. FullName
В приведенном выше примере InstBook — это переменная, заданная для ссылки на объект открытой рабочей книги. Если InstBook ссылается на рабочую книгу с именем Sales.xls в папке Му Documents, то окно сообщения, вызываемое приведенным выше оператором, отображает строку "C:\My Documents\SALES.XLS".
Чтобы задать свойство объекта, просто присвойте свойству новое значение, используя следующий синтаксис:
СИНТАКСИС
Object.Property = Expression
Object — любая допустимая объектная ссылка, Property — любое свойство объекта, на который выполняется ссылка, a Expression — любое выражение VBA, которое вычисляется до типа, совместимого со свойством.
Объекты и коллекции,введение
227
Следующая строка, например, изменяет имя рабочего листа, на который ссылается объектная переменная InstSheet, присваивая значение свойству Name листа:
InstSheet.Name = "Первый квартал"
Следующий пример изменяет текст, отображаемый в строке состояния в нижнем левом углу окна приложения, присваивая строку свойству StatusBar объекта Application (объект Application — это host-приложение VBA, в данном случае — Excel):
Application.StatusBar = "Генерировать отчет за третий квартал"
Используйте свойство Application.StatusBar в своих процедурах для отображения сообщений о действиях, которые выполняет процедура, особенно если некоторые из этих действий занимают много времени (например, сортировка длинного списка). Добавляя сообщение в строку состояния, вы даете знать пользователю, что процедура все еще работает. Используйте оператор, подобный следующему:
Application.StatusBar = "Сообщение о текущих действиях"
Не забывайте возвращать управление строке состояния при работе в Excel. В Excel необходимо устанавливать свойство Application. StatusBar в False, когда процедура выполнена, иначе Excel продолжает отображать заданное вами сообщение строки состояния. Используйте оператор, подобный следующему, для удаления сообщения из строки состояния и возврата управления строке состояния:
Application.StatusBar = False
В табл. 10.3 перечислены некоторые из наиболее употребительных или полезных свойств объектов в Excel 2000/2002 версии Visual Basic for Applications. В таблице представлено имя свойства, тип и значение, а также объекты, которые имеют это свойство.
Таблица 10.3. Наиболее употребительные свойства объектов в Excel 2000/2002
Свойство	Тип/Что означает	Где найти
ActiveCell	Object: активная ячейка в рабочем листе	Application, Window
ActiveChart	Object: активная диаграмма	Application, Window, Workbook
ActiveSheet	Object: активный лист	Application, Window, Workbook
Address	Возвращает координаты ячейки указанного объекта	Range
Cells	Диапазон объекта Range	Application, Range, Worksheet
Charts	Коллекция диаграмм	Application, Workbook
Count	Integer: число объектов в коллекции	Все объекты коллекции
Formula	String: формула для ячейки рабочего листа	Диапазон
Index	Integer: число объектов в коллекции	Worksheet
Name	String: имя объекта	Application, Workbook и в других объектах
Path	String: драйвер и каталог, в котором сохранен объект	Addin, Application, Workbook
8*
228
Глава 10
Свойство	Тип/Что означает	Где найти
Saved	Boolean: сохранялась ли рабочая книга после последних изменений	Workbook
Selection	Object: текущий выделенный фрагмент	Application, Window
Sheets	Коллекция листов рабочей книги	Application, Workbook
StatusBar	String: сообщение в статусной строке	Application
ThisWorkBo ok	Object: рабочая книга, из которой выполняется текущая процедура	Application
Type	Integer: число, указывающее тип объекта	Window, Worksheet, Chart
Visible	Boolean: отображается или нет объект на экране	Application, Worksheet, Range и в других объектах
Value	(варьируется): действительное значение, отображаемое в ячейке	Range
Workbooks	Коллекция рабочих книг	Application
Worksheets	Коллекция рабочих листов	Application, Workbook
Некоторые свойства из таблицы 10.3 использованы в коде листинга 10.2. Чтобы посмотреть, как работает этот код, запустите Excel 2000/2002, выберите, например, лист с именем Sheet2 и переименуйте его в Лист для тестов. Введите в ячейку, например, С6, следующий текст Содержимое активной ячейки. В этот момент среда Excel готова к запуску кода листинга 10.2 и выглядит, как показано на рис. 10.2. Войдите в Редактор VBA и введите код листинга 10.2.
Рис. 10.2
Среда Excel подготовлена для запуска кода листинга 10
LJ Microsoft Excel * Книга1
В1) Файл Правка Вид Вставка Формат Сервис Данные Окно Справка - в х £r U " Times New Roman -12 - ж к н иг 4- afc tjs Й?	> • А - ”
С6	-г fi, Содержимое активной ячейки
~CTp0Ka<tK]pMynj р	G'	—-
1
2
3
4	—
5
6	j	|Содерж1|мое активной ячепкп
7	“
8
и < ► н\Лист1/Лист2 /ЛистЗ /	]<|	|	>|Г~
Готово	NUM
Листинг 10.2. Активный лист, ячейка
1 Sub TestObjectOl()
2	' имя активного листа
3	MsgBox ActrveSheet.Name
4
5	' адрес активной ячейки
6	MsgBox ActiveCell.Address
7
Объекты и коллекции, введение
229
8	' содержимое активной ячейки
9	MsgBox ActiveCell.Formula
10
11 End Sub
Процедура при помощи функции MsgBox по очереди отобразит окна, представленные на рис. 10.3.
Рис. 10.3
Результат выполнения кода листинга 10.2
Microsoft Excel [Xj		Microsoft Excel |Ц£|		Microsoft Excel
Лист1				Содержимое активной ячейки
Г '"ок		:ок' ;		Г” ок i
				
Как видите, даже небольшие знания об объектах дают некоторые дополнительные возможности для работы со средой Excel. Но все еще впереди.
В табл. 10.4 приведены некоторые из наиболее употребительных или полезных свойств объектов в Word 2000 версии VBA. В таблице представлено имя свойства, тип, значение и объекты, которые имеют это свойство.
Таблица 10.4. Употребительные и полезные свойства объектов Word 2000/2002
Свойство	Тип/Значение	Имеется в объектах
ActiveDocument	Object: активный документ	Application
ActivePrinter	String: имя активного принтера	Application
Active W indow	Object: активное окно	Application, Document
Count	Long: число объектов в коллекции	Во всех объектах коллекций
Name	String: имя объекта	Application, Bookmark, Dictionary, Document и в других
Path	String: драйвер и путь к папке, в которой сохранен объект	Addin, Application, Dictionary, Document и в других
Range	Object: часть документа, содержащаяся в указанном объекте	Bookmark, Paragraph, Selection, Table и в других
Saved	Boolean: был ли сохранен текст после последнего изменения	Document, template
Selection	Object: текущий выделенный фрагмент	Application, Pane, Window
StatusBar	String; сообщение строки состояния	Application
Visible	Boolean: отображается объект на экране или нет	Application, Border
Перед подробным изучением свойств и методов встроенных объектов приведем некоторые примеры использования свойств и методов из таблицы.
230
Глава 10
Запустите Word 2000/2002. Откройте два документа. В одном из них в Редакторе VBA создайте новый модуль и введите код листинга 10.3.
Листинг 10.3. Активный документ
1	Sub ActDocum()
2
3	MsgBox ActiveDocument Name, , _
4	"Наименование активного документа"
5
6	MsgBox ActiveDocument Path, , _
7	"Путь сохранения документа"
8
9	ActiveDocument Close ' закрыть активный документ
20
11	MsgBox ActiveDocument Name, , _
12	"Наименование активного документа"
13	End Sub
В строках 3-4 записан оператор, который выдает на экран имя активного документа (рис. 10.4 а) с помощью процедуры MsgBox. Следующий оператор (в строках 6-7) выдает окно, в котором указывается путь к месту хранения файла на диске (рис. 10.4 Ь). Не менее, чем два предыдущих, интересен оператор в строке 9. Этот оператор закрывает активный документ! Заметьте, это делается не при помощи привычного меню, а из кода VBA. Более того, предварительно пользователю (что необязательно и может быть отключено) задается вопрос, не следует ли сохранить последние изменения в документе (рис. 10.4 с). Последнее окно (рис. 10.4 d) функции MsgBox связано с оператором в строках 11-12; здесь сообщается об имени (ставшего активным) другого документа. Если запустить код листинга 10.3 из текущего активного документа, то он не выполнится до конца, так как закрытие документа прервет выполнение кода: редактор VBA закроется вместе с документом.
b)
Рис. 10.4
Результат работы кода листинга 10 3
Объекты и коллекции,введение
231
Использование методов объекта
Методы объекта используются в операторах VBA так, как использовались бы любые встроенные процедуры VBA.
Метод объекта имеет следующий синтаксис:
СИНТАКСИС
Object.Method
Для методов объектов, имеющих обязательные и необязательные аргументы, используйте такой синтаксис:
Object.Method Argument!, Arguments, Arguments...
В обеих строках синтаксиса Object представляет любую допустимую объектную ссылку VBA, a Method — имя любого метода, принадлежащего объекту, на который выполняется ссылка. Во второй строке синтаксиса Argument!, Аг-gument2 и так далее представляют аргументы в списке аргументов метода. Как в случае с аргументами для вызова процедуры VBA, необходимо перечислять аргументы метода в определенном порядке, отделяя каждый аргумент в списке запятой и включая отмечающие запятые (place holding commas) для пропущенных необязательных аргументов. Метод может иметь один или несколько аргументов в своем списке или не иметь их совсем; аргументы метода могут быть обязательными или необязательными.
Пример: рабочие книги Excel имеют метод Activate, который делает рабочую книгу активной и активизирует первый лист в книге. Если задать переменную InstBook для ссылки на объект рабочей книги, то приведенный ниже оператор активизирует эту рабочую книгу (в последующих разделах этой главы описывается, как задать переменную для ссылки на объект):
InstBook.Activate
Хотя метод Activate не имеет аргументов, многие методы объектов имеют один или более аргументов. В следующем примере вызывается метод SaveAs объекта рабочей книги Excel; используется один обязательный аргумент и один из нескольких необязательных аргументов.
ActiveWorkbook.SaveAs Filename:="D\VBA2000\NEWFILE.xls", _
FileFormat:=xlNormal
Word-объекты Document также имеют методы Activate и SaveAs с похожими аргументами. Первый оператор, приведенный ниже, активизирует документ, на который ссылается переменная InstDoc, а второй — использует метод SaveAs документа для сохранения активного документа под другим именем:
InstDoc.Activate ActiveDocument.SaveAs Filename:="E:\VBA2000\Chapl0.doc"
Многие объекты имеют методы, которые возвращают значения так же, как это делает функция. Чтобы использовать значение, возвращаемое методом, необходимо поместить список аргументов метода в круглые скобки и включить вызов метода в оператор присваивания или другое выражение, точно так же, как при использовании функции. Можно также игнорировать результат, возвращаемый методом. Чтобы игнорировать результат метода (если он имеет результат), вызовите метод без круглых скобок вокруг списка аргументов, как если бы метод не Возвращал результата.
Пример: Excel-метод Address (который принадлежит объекту Range) возвращает адрес диапазона ячеек в рабочем листе как строку. В следующем примере показан оператор VBA, который использует метод Address (myRange — это объектная переменная, которая ссылается на диапазон ячеек в рабочем листе):
MsgBox myRange.Address
232
Глава 10
Если переменная myRange ссылается на первую ячейку в рабочем листе, то оператор MsgBox в приведенной выше строке примера отображает строку $А$1.
Хотя в этом примере метод Address вызывается без каких-либо аргументов, он, на самом деле, имеет несколько необязательных аргументов. Эти необязательные аргументы определяют стиль адреса ячеек рабочего листа, возвращаемого методом, а также, являются ли координаты ячеек абсолютными или относительными. В следующем примере показан вызов метода Address с, его третьим необязательным аргументом (который определяет стиль возвращаемых координат ячеек):
MsgBox myRange.Address(, , xlRlCl)
В этом операторе необходимо в список аргументов метода включать отмечающие запятые для пропущенных необязательных аргументов, как для любой другой процедуры или функции. Поскольку аргумент ссылочного стиля является третьим аргументом, ему предшествуют две отмечающие запятые в списке аргументов. xlRlCl — это внутренняя константа Excel, указывающая на то, что координаты ячеек рабочего листа используют стиль записи R1C1; если объектная переменная myRange ссылается на ячейку во второй строке и третьем столбце, то отображается строка R2C3 (вторая строка, третья колонка).
Методы имеют также именованные аргументы, как и другие процедуры и функции VBA. Можно переписать последний пример, используя именованные аргументы, следующим образом:
MsgBox myRange.Address(Referencestyle:=X1R1C1)
Используйте именованные аргументы, чтобы было легче читать код VBA. В каждом из следующих примеров показан оператор, вызывающий метод SaveAs объекта рабочей книги Excel (этот метод не возвращает результат) для сохранения рабочей книги под другим именем (объектная переменная InstBook ссылается на рабочую книгу):
InstBook.SaveAs "NEWNAME.XLS", xlNormal, , , , True
InstBook.SaveAs FileName:="NEWNAME.XLS" , _
FileFormat:=xlNormal, _
GreateBackup:=True
Оба оператора используют только три из шести необязательных аргументов для метода SaveAs. Первый оператор использует стандартный список аргументов, второй — именованные аргументы. Намного легче понять назначение и действие второго обращения к методу SaveAs, чем первого.
Между методом объекта и любой другой процедурой VBA (встроенной или пользовательской) имеется одно существенное отличие — метод принадлежит определенному объекту и метод можно использовать, обращаясь к нему только посредством этого объекта. Часто можно распознать вызов методов в коде VBA по тому факту, что метод связан со ссылкой на объект с помощью точки-разделителя, как показано в примерах этого раздела.
В табл. 10.5 приведены некоторые из наиболее употребительных или полезных методов в Excel 2002 версии VBA. В таблице представлено имя, краткое описание метода и объекты, имеющие этот метод.
Таблица 10.5. Общеупотребительные и полезные методы объектов Excel 2000/2002
Метод	Назначение	Имеется в объектах
Activate	Активизирует объект	Window, Workbook, Worksheet, Range и в других объектах
Calculate	Выполняет вычисления в открытой рабочей книге, рабочем листе или диапазоне	Application, Range, Worksheet
Объекты и коллекции, введение
233
Метод	Назначение	Имеется в объектах
Clear	Удаляет данные, сохраненные в указанном объекте	Range
Close	Закрывает указанный объект	Window, Workbook, Workbooks
Justify	Выравнивает тек<;т, сохраненный в указанном объекте	Range
Run	Выполняет указанную процедуру или функцию	Application, Range
Save	Сохраняет файл рабочей книги	Application, Workbook
SaveAs	Сохраняет указанный объект в другом файле	Workbook, Worksheet
Select	Выбирает указанный объект	Range, Sheets, Worksheets
SendKeys	Пересылает нажатия клавиши в диалоговые окна в host-приложении	Application
Volatile	Регистрирует функцию как изменяющуюся (см. гл. 6)	Application
Вернитесь к листу с именем Лист для тестов в рабочей книге Excel, занесите какую-либо информацию в ячейки листа и выделите какую-нибудь ячейку, например, как показано на рис. 10.5. Выполните код листинга 10.4.
Листинг 10.4. Метод Clear для ячейки и диапазона
1	Sub TestMethodsOl()
2	1 тестирование метода Clear
3
4	' содержимое активной ячейки
5	' до применения метода Clear
6	MsgBox ActiveCell.Formula, , "До метода Clear"
7
8	’ выполнения Clear
9	ActiveCell.Clear
10
11	' содержимое активной ячейки
12	' после применения метода Clear
13	MsgBox ActiveCell.Formula, ,	"После метода Clear"
14
15	' Очистить диапазон ячеек:
16	Range("C6:D7").Clear
17
18	End Sub
Сначала в результате выполнения кода этого листинга (строка 6) на экран выдается в диалоговом окне содержимое активной ячейки С4. Метод ActiveCell.Clear очищает эту ячейку, а оператор в строке 13 выдает на экран пустое сообщение. Наконец, оператор в строке 16 очищает диапазон ячеек C6:D7. Рабочий лист имеет вид, представленный на рис. 10.6. Обратите внимание на то, как задается диапазон ячеек для выполнения метода Clear.
В табл. 10.6 приведены некоторые из наиболее употребительных или полезных методов в Word 2000/2002 версии VBA. В таблице приведено имя метода, краткое описание метода и объекты, имеющие этот метод.
234
Глава 10
Рис. 10.5
Содержимое листа до выполнения кода листинга 10.4
Рис. 10.6
Содержимое листа после выполнения кода листинга 10.4
Таблица 10.6. Наиболее употребительные и полезные методы объектов Word 2000/2002
Метод	Назначение	Имеется в этих объектах
Activate	Активизирует объект	Window, Document, Pane и в других объектах
CheckSpelling	Проверяет орфографию указанного документа или диапазона	Document, Range
Close	Закрывает указанный объект	Window, Document
Delete	Удаляет указанный объект или удаляет символы и слова	Bookmark, Range и в других объектах
GoTo	Перемещает курсор в начальное положение элемента, такого как страница, закладка или поле; возвращает объект Range	Document, Range, Selection
Printout	Печатает указанный объект	Application, Document, Envelope, Window
Объекты и коллекции,введение
235
Метод	Назначение	Имеется в этих объектах
Run	Выполняет указанную процедуру или функцию	Application
Save	Сохраняет указанный объект	Document, Template
SaveAs	Сохраняет документ в другом файле	Document
Select	Выбирает указанный объект	Bookmark, Document, Field и в других объектах
Рассмотрим подробнее метод SaveAs, который уже использовался в примерах этой главы.
Для метода SaveAs необходимы дополнительные параметры, так как нет смысла сохранять документ под тем же именем методом, отличным от Save (на самом деле, Save тоже имеет необязательные параметры). Чтобы получить список параметров метода, можно воспользоваться системой Auto Quick Info. Как только вы наберете строку
ActiveDocument.SaveAs(
система подсказки выдаст на экран список всех параметров метода SaveAs, как это обычно делается для обычных функций (рис. 10.7).
Рис. 10.7
Система Auto Quick
Info для методов работает так же, как и для функций
MsgBox ActiveDocument.Name
"Наименование активного документа"
MsgBox ActiveDocument.Path, , _ "Путь сохранения документа"
ActiveDocument .Close ’ j п;рытъ г.кигангй
MsgBox ActiveDocument.Name, , _
"Наименование активного документа" End Sub
Sub SaveDocumO
End
ActiveDocument.SaveAs (|	I
Sub SaveAs([Fi7eNa/ne], [Fi/eFormaf], [LockCommenfs], [Password], [AddFoRecentFi/es], [WnfePassword], [ReadOnfy Recommended], [EmbedTrueTypeFonts], [SaveNativePictureFormaf], [Sai/eFormsDafa], | [Sai/eAsAOCQ-effer], [Encoding], [InsertLineBreaks], [AllowSubstifutions], ......[LineEnding], [AddBiDiMarks])
Согласно выданному системой Auto Quick Info всплывающему окну метод SaveAs имеет довольно много аргументов, хотя все они — необязательные. Если интуитивно вам непонятно назначение параметров какой-либо функции в окне Auto Quick Info, обратитесь за помощью к справочной системе. Для этого либо выделите, например, строку ActiveDocument.SaveAs и нажмите клавишу F1, либо в окне Microsoft Visual Basic Help откройте вкладку Contents, выберите последовательно разделы: Microsoft Word Visual Basic Reference, Methods, S, SaveAs Method. В результирующем окне вы получите исчерпывающую информацию о синтаксисе метода SaveAs:
236
Глава 10
СИНТАКСИС
expression.SaveAs(FileName, FileFormat, LockComments, Password, AddToRecentFiles, WritePassword, ReadOnlyRecommended, EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter}
Все параметры метода, кроме expression, — необязательные и описываются в справочной системе следующим образом:
expression — выражение, возвращающее объект Document.
FileName — аргумент типа Variant. Является новым именем сохраняемого документа. По умолчанию это — текущие папка и имя файла. Если документ еще ни разу не сохранялся, используется имя по умолчанию (например, Docl.doc). Если документ с именем FileName уже существует, он будет перезаписан без сообщения об этом пользователю.
FileFormat — аргумент типа Variant. Формат, в котором сохраняется документ. Может быть одной из следующих WdSaveFormat-констант: wdFormat-Document, wdFormatDOSText, wdFormatDOSTextLineBreaks, wdFormatEn-codedText, wdFormatHTML, wdFormatRTF, wdFormatTemplate, wdFormat-Text, wdFormatTextLineBreaks или wdFormatUnicodeText.
LockComments — аргумент типа Variant. Чтобы блокировать документ для комментариев, должен иметь значение True.
Password — аргумент типа Variant. Строка пароля для открытия документа. AddToRecentFiles — аргумент типа Variant. True — для добавления имени файла к списку недавно используемых документов в меню File.
WritePassword — аргумент типа Variant. Строка пароля для сохранения изменений в документе.
ReadOnlyRecommended — аргумент типа Variant. True — для того, чтобы Word устанавливал статус «только на чтение» при открытии документа.
EmbedTrueTypeFonts — аргумент типа Variant. True — для сохранения TrueType-шрифтов вместе с документом.
SaveNativePictureFormat — аргумент типа Variant. Если в документ импортировались графические изображения других платформ (например, Macintosh), True — для сохранения только Windows-версии импортированных изображений. SaveFormsData — аргумент типа Variant. True — для сохранения данных, введенных пользователем в форму как записи.
SaveAsAOCELetter — аргумент типа Variant. Если документ имеет прикрепленный файл электронной почты, True — для сохранения документа как АОСЕ-письма (файл электронной почты сохраняется).
В справочной системе очень подробно приведено описание каждого метода, и следует почаще прибегать к ее услугам. Впрочем, Редактор VBA постоянно предлагает эту помощь в процессе вашей работы с ним.
Объявление объектных переменных
Возможно, вы помните из главы, посвященной типам данных, что в дополнение к типам Byte, Integer, Long, Single, Double и String VBA также имеет тип Object. Переменные или выражения типа Object ссылаются на объект VBA или на объект, принадлежащий host-приложению, такой как Excel-объекты Workbook, Worksheet и Range или Word-объекты Document, Range, Paragraph.
Как и в случае с другими типами VBA, можно объявлять переменные в модулях, процедурах и функциях с определенным типом Object, что показано в следующем операторе:
Dim myObject As Object
Объекты и коллекции, введение
237
Можно задавать переменную myObject, создаваемую предшествующим оператором Dim, чтобы она содержала ссылку на любой объект VBA или объект host-приложения. Если вы собираетесь использовать переменную типа Object для некоторых специфических типов объектов, можно также объявлять объектную переменную для этого специфического типа объекта:
Dim InstBook As Workbook
Объектную переменную InstBook, создаваемую этим оператором Dim, можно использовать только для сохранения ссылок на объекты Workbook; при попытке присвоить переменной InstBook ссылку на объект Range или Worksheet VBA отображает сообщение об ошибке несовпадения типов. Аналогично, следующее предложение объявляет объектную переменную, которая может сохранять только объекты Document:
Dim InstDoc As Document
Можно использовать VBA-функцию IsObject для определения того, образует ли переменная или выражение допустимую объектную ссылку. Функция IsObject имеет следующий синтаксис:
СИНТАКСИС
IsObject(Object)
Object представляет переменную или выражение, которое необходимо протестировать; IsObject возвращает значение True, если Object является допустимой объектной ссылкой, и False — иначе.
Для определения объектного типа переменной, можно также использовать VBA-функцию TypeName (в предыдущих главах эта функция уже применялась).
Объект в выражениях
Объектное выражение (object expression) — это любое выражение VBA, которое определяет отдельный объект. Все объектные выражения должны вычисляться до единственной объектной ссылки (ссылки на объект); объектные выражения используются с единственной целью — создание ссылок на специфические объекты в ваших программах VBA.
Объектное выражение может состоять из объектных переменных, объектных ссылок или объектного метода или свойства, которое возвращает объект. Все последующие примеры являются правильными объектными выражениями (использующими объекты Excel):
Application	Имя объекта: ссылается на объект приложения
Application. ActiveSheet	Объектное свойство, которое возвращает ссылку на объект: активный лист
Application. W orkbooks	Объектный метод, который возвращает коллекцию объектов: все открытые рабочие книги
ABook	Объектная переменная: инициализированная в операторе Set, ссылается на объект
Нельзя использовать переменные типа Object или объектные выражения в арифметических, логических или операциях сравнения. Объектная ссылка, созданная с помощью объектного выражения или сохраненная в объектной переменной, в действительности, является только адресом, указывающим место в памяти компьютера, где сохранен объект, на который выполняется ссылка. Поскольку
238
Глава 10
объектная ссылка — это адрес памяти, арифметические, логические операторы и операторы сравнения не имеют смысла.
Перед использованием объектной переменной для ссылки на объект необходимо задать эту переменную, чтобы она содержала ссылку на нужный объект. Присваивание объектной ссылки объектной переменной отличается от присваиваний других переменных; чтобы присвоить объектную ссылку объектной переменной, используйте оператор Set.	•
Оператор Set имеет следующий синтаксис:
СИНТАКСИС
Set Var = Object
Var — это любая объектная переменная или переменная типа Variant. Object — любая допустимая объектная ссылка; это может быть другая объектная переменная или объектное выражение. Если Var — переменная, объявленная с каким-либо определенным типом (например, Range или Workbook), этот тип должен быть совместим с объектом, на который ссылается Object.
В следующем фрагменте программы типы переменной и объектов используются правильно (для объектов Excel):
Dim InstSheet As Worksheet
Set InstSheet = Application.ActiveSheet
Следующий фрагмент программы VBA имеет в результате ошибку несовпадения типов потому, что свойство ActiveSheet возвращает объект Worksheet, а не Workbook:
Dim InstBook As Workbook
Set InstBook = Application.ActiveSheet
Чтобы задать отдельный объект в выражении или объектную переменную для ссылки на этот объект, используйте методы и свойства, возвращающие объекты, такие как свойства Active Workbook и ActiveSheet объекта Application или метод Cells объекта Worksheet (в Excel). Аналогичные принципы применимы в Word: используйте свойство ActiveDocument объекта Application для получения ссылки на текущий документ и так далее.
Хотя стандартные операторы сравнения (<, <=, >, >=, о, =) не являются значимыми при использовании с объектами, VBA предоставляет один оператор сравнения, предназначенный исключительно для использования с объектными выражениями и переменными — оператор (операцию) Is.
Оператор Is имеет следующий синтаксис:
СИНТАКСИС
Objectl Is Object2
Object 1 и Object2 — любые допустимые объектные ссылки. Используйте оператор Is для определения того, обозначают ли две объектные ссылки один и тот же объект. Результат операции сравнения Is равен True, если объектные ссылки являются одними и теми же, иначе — False.
В листинге 10.5 показана VBA-процедура для Excel, выполняющая резервную копию активной рабочей книги. Можно использовать подобную процедуру, если необходимо предоставить пользователю легкий способ сохранять копию активной рабочей книги под другим именем без изменения имени файла активной рабочей книги в памяти, как это делается с помощью команды File | Save As (Файл | Сохранить как...).
Объекты и коллекции, введение
239
Листинг 10.5. Процедура создания резервной копии активной рабочей книги
1	Sub SaveActiveBook()
2	' Создает копию активной рабочей книги под новым именем,
3	1 используя метод SaveCopyAs. Новое имя имеет добавку "_Ьр"
4
5	Dim FName As String	1 имя файла-копии
6	Dim OldComment As String ' комментарии
7
8	' сохранить комментарии исходного файла
9	OldComment = ActiveWorkbook.Comments
10
11	' добавить новые комментарии к backup-файлу
12	ActiveWorkbook.Comments = "Резервная копия файла " & _
13	ActiveWorkbook.Name & _
14	", выполненная процедурой SaveActiveBook"
15
16	1 Сформировать новое имя файла из исходного
17	FName = Left(ActiveWorkbook.Name, _
18	InStr(ActiveWorkbook.Name, ".") - 1) & "_bp.xls"
19
20	' добавление к имени файла пути
21	FName = ActiveWorkbook.Path & s FName
22
23	ActiveWorkbook.SaveCopyAs Filename:=FName
24	ActiveWorkbook.Comments = OldComment ' восстановить комментарии 25 End Sub
В этой процедуре используются два объекта Excel, их свойства и методы. Объектная ссылка ActiveWorkbook является свойством Excel-объекта Application, которое возвращает объектную ссылку на активную в данный момент рабочую книгу. (В следующем разделе вы узнаете, что обычно можно опускать объектную ссылку для свойств и методов объекта Application.)
В строке 9 копируется строка свойства Comments объекта ActiveWorkbook в переменную OldComment. Затем в строках 12-14 задается новое значение для свойства Comments объекта ActiveWorkbook (это свойство изменяется и для исходной рабочей книги). Свойство Comments этого объекта содержит текст комментария, обычно вводимого вами в диалоговое Properties (Окно свойств), которое Excel отображает при сохранении рабочей книги в первый раз или при использовании команды File | Properties (Файл | Свойства). На рис. 10.8 приведено окно Properties для файла, который был получен в результате резервного копирования. Обратите внимание на поле Comments. В этом поле должен находиться текст, который можно получить, если перед строкой 16 вставить оператор:
MsgBox ActiveWorkBook.Comments
В строках 17-19 формируется имя нового файла из имени текущего. Этот оператор использует функции Left и InStr, помогая создать новое имя файла для резервной копии активной рабочей книги. Функция InStr возвращает положение разделителя имени файла (.) в свойстве Name объекта ActiveWorkbook. (Свойство Name рабочей книги содержит имя файла рабочей книги). Результат функции InStr определяет, сколько символов функция Left копирует из свойства Name объекта ActiveWorkbook. Поскольку функция InStr возвращает позицию разделителя имени файла (.), Left возвращает имя файла, не включая разделитель и расширение XLS. К полученному имени добавляется строка "_bp.xls".
В строке 21 к пути, получаемому при помощи метода ActiveWorkbook.Path, добавляется имя нового файла.
Строка 23 использует метод ActiveWorkbook.SaveCopyAs для сохранения активной рабочей книги с новым именем файла на текущем диске и каталоге; имя файла активной рабочей книги в памяти остается тем же.
240
Глава 10
Рис. 10.8
Убедитесь в правильности комментариев при резервном копировании активной рабочей книги
Наконец, в строке 24 восстанавливается оригинальное содержимое свойства ActiveWorkbook.Comments; файл активной рабочей книги теперь находится точно в таком же состоянии, в каком он был перед тем, как начинается выполнение этой процедуры.
Ссылка на объекты с помощью With...End With
Как видно из листинга 10.5, процедуры могут ссылаться на один и тот же объект часто с помощью нескольких операторов в одной строке. Каждый оператор в листинге 10.5 в строках с 9 по 23 использует свойство или метод объекта, на который ссылается Active Workbook. VBA предоставляет особую структуру — структуру With...End With, позволяющую ссылаться на свойства или методы, которые принадлежат одному и тому же объекту, без задания всей объектной ссылки каждый раз.
Структура With...End With имеет следующий синтаксис:
СИНТАКСИС
With Object
' операторы, использующие свойства и методы Object
End With
Object — это любая допустимая объектная ссылка.
В листинге 10.6 показана процедура SaveActiveBook2, на этот раз со структурой With...End With.
Листинг 10.6. Добавление к процедуре SaveActiveBook структуры With...End With 1 2 3
1 Sub SaveActiveBook?()
2	1 Создает копию активной рабочей книги под новым именем,
3	' используя метод SaveCopyAs. Новое имя имеет добавку "_Ьр2"
Объекты и коллекции, введение
241
4
5	Dim FName As String 'имя файла-копии
6	Dim OldComment As String	'комментарии
7
8	With ActiveWorkbook
9	' сохранить комментарии исходного файла
10	OldComment = .Comments
11
12	' добавить новые комментарии к backup-файлу
13	.Comments = "резервная копия файла " s .Name S _
14	", выполненная процедурой SaveActiveBook2"
15
16	' Сформировать новое имя файла из исходного
17	FName = Leftf.Name, InStr(.Name, ".") - 1) & "_bp2.xls"
18
19	FName = .Path & "\" S FName
20
21	.SaveCopyAs Filename:=FName
22	.Comments = OldComment 'восстановить комментарии
23	End With
24	End Sub
Эта версия процедуры работает точно так же, как показанная в листинге 10.5. Здесь используется структура With...End With. Строка 8 начинается с ключевого слова With, за которым следует объектная ссылка ActiveWorkbook, начиная таким образом всю структуру With...End With.
В строке 10 содержимое свойства ActiveWorkbook.Comments присваивается строковой переменной OldComment. Заметим, что на этот раз только точка-разделитель (.) включается в начало свойства Comments. Поскольку этот оператор находится внутри структуры With ActiveWorkbook, VBA «знает», что объектной ссылкой для свойства .Comments является ActiveWorkbook.
Все сказанное относится ко всем остальным операторам, использующим свойства объекта ActiveWorkbook.
Наконец, строка 23 завершает структуру With...End With ключевыми словами End With.
Не забывайте сохранять любые данные, которые хотите изменить только на некоторое время. Процедура SaveActiveBook2, например, изменяет свойство Comments активной рабочей книги. SaveActiveBook2 использует переменную для сохранения оригинального комментария перед выполнением изменений, а затем восстанавливает оригинальный комментарий.
Не следует получать данные ввода от пользователя, если они вам действительно не нужны. Процедура SaveActiveBook2 могла бы быть записана с оператором InputBox для получения имени файла вместо генерации этого имени автоматически. Автоматическое генерирование обеспечивает то, что резервные файлы, создаваемые этой процедурой, легко идентифицируются и пользователю не приходится выполнять ввод имени файла. Генерирование нового имени файла в процедуре устраняет также потенциальные проблемы, связанные с вводом неверного имени файла пользователем.
Очевидно, что набор кода листинга 10.6 требует меньших усилий, чем набор кода листинга 10.5; такой код к тому же легче читать и понимать. Упрощайте свой код, используя структуру With...End With всякий раз, когда у вас несколько программных операторов используют свойства или методы одной объектной ссылки.
Работа с коллекциями объектов и контейнерами объектов
Коллекция (collection) объектов — это группа связанных объектов, таких как все рабочие листы в рабочей книге или все символы в параграфе. Объект в коллекции называется элементом (element) этой коллекции.
242
Глава 10
Сама коллекция является объектом; коллекции имеют собственные свойства и методы. Каждая коллекция, например, имеет свойство Count, которое возвращает число элементов в коллекции. Если в активной рабочей книге имеется 16 рабочих листов, то следующее выражение вычисляется до числа 16:
Application.ActiveWorkbook.Worksheets Count
В этом выражении Worksheets — коллекция всех рабочих листов в рабочей книге, ActiveWorkbook — свойство Excel-объекта Application, возвращающее активную рабочую книгу, a Count — свойство коллекции Worksheets, возвращающее общее число рабочих листов в коллекции.
Это простое выражение помогает проиллюстрировать то, что одни объекты содержат другие объекты. Контейнер (container) — это любой объект, содержащий один или несколько других объектов. В данном примере Application содержит объект, на который ссылается ActiveWorkbook, содержащий в свою очередь, коллекцию объектов Worksheets. Все контейнерные объектные ссылки соединяются вместе с помощью точки-разделителя (.) для образования одного объектного выражения.
Многие объекты содержат другие объекты различных типов: рабочая книга содержит объекты Module, Chart и Worksheets; рабочий лист может содержать объекты DrawingObjects, ChartObjects или OLEObjects. На рис. 10.9 в окне справочной системы показана диаграмма объектов Excel 2000/2002 — коллекция
Рис. 10.9
Excel-коллекция Application в справочной системе VBA
[Application
^Workbooks (Workbook)
Microsoft Excel Objects
“[Addins (Addin)
•[ Worksheets (Worksheet)	}
-[Charts (Chart)	[^
-[Answer
~j AutoCorrect
-|DocumentProperties (DocumentProperty)l -[Assistant
-jVBProject	|
-[CustomViews (CustomView)	|
-[CommandBars (CommandBar)	[
jHTMLProject	[
-[ptvotCaches (PivotCache)	|
-[Styles (Style)	|
-[Borders (Border) “{Font Hlnterror -[Windows (Window)	|
Црапез (Pane)	~
-[Names (Name)	|
-[RoutingShp	I
-[PublishObjects (PubllshObject) |
-[SmartTagOptions	|
-[WebOpbons	|
-[AutoRecover
-[CellFormat	|
•jCOMAddlns (COMAddln)	|
-[Debug	|
-[Dialogs (Dialog)	|
-[commandBars (CommandBar) ]
-jErrorCheckingOptions
~[LanguageSettings
-[Names (Name)
“[Windows (Window)
Црапе! (Pane) ~
~~|WorksheetFunction
-[RecentFiles (RecentFile)
-[SmartTaqRecognizers ^-jSmartTagRecognizer
Legend
О Object and collection
D Object only
)► Click arrow to expand chart
“[Speech
-jSpellingOptlons
-[FileSearch
~~|V8E
-[ODBCErrors (ODBCError)
-[OLEDBErrors (OLEDBError)
-[DefaultWehOptions
-[UsedObjects
-[Watches
l~jWatch
[iRtdServer
[iRTDUpdateEvent	~

J
Объекты и коллекции, введение
243
Application, из которой видно, что одни объекты этой коллекции содержат другие. На рис. 10.10 показана диаграмма объектов коллекции Application.Worksheets. Подобную иерархию имеет и коллекция Application.Charts. На рис. 10.11 (также в окне справочной системы) показана диаграмма объектов Word 2000/2002 — коллекция Application, а на рис. 10.12 — коллекция Documents.
Иерархия объектов и контейнеров, показанная на рис. 10.9-10.12, называется объектной моделью (object model).
Как вы уже могли заметить, стрелки на диаграмме рядом с некоторой коллекцией (например, Worksheets рис. 10.9) указывают на то, что данная коллекция имеет в справочной системе подобную диаграмму (рис. 10.10), которую также можно вывести на экран. Коллекции, содержащие не только объекты, но и коллекции, окрашены желтым цветом, а содержащие только объекты — синим.
Рис. 10.10
Excel-коллекция
Application.Worksheets в справочной системе VBA
Справка .Microsoft Visual Basic
Contents; Мастер ответов Укй-jjH
Microsoft Excel Objects (Worksheet)
I-Г®
1 Введите кгкчееые слова
jObject model
Очистить [ Нацти |
2 Или выберите ключевые слова [add m ^automate automate automation chart COM component
3 Выберите раздел (найдено 6)
Mcrosoft Excel Objects
Microsoft Excel Objects (ChartGroups
Microsoft Excel Objects (Charts)
Microsoft Excel Objects (Shapes)
Understanding Automation
[Worksheets (Worksheet)
•{Names (Name)
4'Ranqe
•{Areas	~
•{Borders (Border) ~
•{Errors
ЧЁггоГ
•{Font ~
4intenoF
•{Characters LjFont	'
ilMame
-iStyle ___ _
•{Borders (Border)
•{Font
M Interior
-(FormatConditions (FormatCondition)l
•{HypaUrfe (Hyperlink) I
-(Validation	~ I
•{Comment	1
{Comments (Comment) I
•fQjstomProperBes П
^CustoinProperty I •iHPaqeBreaks (HPaqeBreakTI •{VPaqeBreaks (VPageBreak)! •{Hyperlinks (Hyperlink)" "1 •{Scenarios (Scenario) I -jQLEObiects (OLEObiectFI -{Outline	, ,
jPageSetup	I
^Graphic	~~I
•{QueryTabies (QueryTable)l
^Parameters (Parameter) ! •{PivotTables (PivotTable)!
HCalculatedFields	I
~{CalculatedMembers~~ I Ц C akutafedMernber
-jCubeFields	I
^CubeField	~
Объект Application и в Excel, и в Word называется внешним контейнером и содержит все другие объекты и коллекции. Например, Excel-объект Application (рис. 10.9) содержит коллекции Workbooks, Addins и другие; Workbooks — это коллекция всех открытых рабочих книг, a Addins — коллекция всех инсталлированных приложений-надстроек (Add-ins). Excel-коллекция Workbooks, в свою очередь, содержит коллекции Worksheets, Charts и т.д. Коллекция Worksheets содержит отдельные листы (рис. 10.10). На рис. 10.11 можно видеть, что объект Word Application содержит коллекции Documents — документы, Addins — надстройки, Dialogs — диалоги, Dictionaries — словари и много других коллекций. Некоторые коллекции Word Application сами содержат коллекции, например, коллекция Documents — это коллекция всех открытых документов (рис. 10.12).
Рис. 10.9-10.12 дают представление о том, как определять сложные объектные ссылки. Чтобы указать VBA, на какой объект необходима ссылка, может понадобиться определить контейнер объекта. Для ссылки на определенный лист рабочей книги Excel, например, может быть необходимо включить ссылку на рабочую книгу, которая содержит этот рабочий лист:
Workbook("Sales.xls").Worksheets("Отчет")
244
Глава 10
Microsoft Word Objects
Рис. 10.11
Word-коллекция
Application
в справочной системе VBA
•jEmailOption»	|
]
Z]
zzj
-iFtfeConverters	|
^FJeConverter	]
•jFHeDlalog	|
-fFHeSearch	~~]
-jForrtNamei	|
HHangutHanjaConversionDictionartes] ^Dictionary	|
-jKeyBlndingt	|
LfreyBmtfafig	I
"[KeysBoundTo	|
ЦкеуВшЛпд	~~""П
-jLanguages	|
i~|l.M>guage	~~	"	|
4Dktionary	j
•jLanguageSettings	j
-jLfotGallerte»	|
LjlbtbJIery	|
nlistTemplates	|
Legend
□ object and collection
□ object only
Click red arrow to expand chart
Рис. 10.12
Word-коллекция
Application.Documents в справочной системе VBA
;^Слраяка Microsoft Visual Basic
Contents j Мастер ответов Як.«]Л
1 ^ведите ключевые слова pbject.
Очистить Найти I
2. Или выберите ключевые слова
Э-D	л |
abbreviation	'
Accelerator	(
accent	>
AccentedLetters accept	
AcceptAll	v	»
3. Выберите раздел (найдено 599) ,
Documents Collection Object
(Application	I
^Documents (Document) I
Acofe : open I.
Bookmarks Collection Object Characters CoSecoon Object ComrrandBars Collection Object Comments Collection Object Documentproperties Collection Object
Usln<
Use th Emad Object collect] Endnotes Collector । Ofrect open
Envelope Object
-e currently
•cuments
imes of the
Ш ®	® йг-

Object Property
KeysBoundTo Collection Object Interaction (Object Browser) Set Reference to a Type Lbran *
For Each aDoc In Documents aName = aName & aDoc.Name & vbCiv
В данном объектном выражении используется Excel-коллекция Workbooks для ссылки на рабочую книгу Sales.xls, а затем используется коллекция Worksheets, содержащаяся в объекте рабочей книги Sales.xls, для ссылки на конкретный лист. (Как обозначаются отдельные элементы в коллекции, описывается немного дальше в этой главе.) Следующий пример выражения показывает еще более сложную объектную ссылку:
Application.Workbooks("Sales.xls").Worksheets("Отчет").Range("Al")
Здесь объектное выражение ссылается на ячейку А1 в листе Отчет рабочей книги Sales.xls. Как видно из этих двух примеров, определение полной объектной ссылки посредством всех контейнеров объекта может быть довольно утомительным. К счастью, VBA позволяет опускать объектную ссылку Application почти
Объекты и коллекции, введение
245
для всех объектов, которые содержит объект Application. Если опускается объектная ссылка Application, VBA «полагает», что имеется в виду host-приложение, и подставляет ссылку автоматически. Следующее объектное выражение ссылается на тот же объект, что и предыдущее выражение (ячейка А1 в листе Отчет рабочей книги Sales.xls):
Workbooks ("Sales . xls") .Worksheets ("Отчет") .RangefAl")
Вам необходимо определять Excel-объектную ссылку Workbooks только тогда, когда ссылка может быть неоднозначной или при использовании встроенных функций рабочих листов Excel.
Если Excel-объектная ссылка Workbooks (или объектная ссылка Documents в Word) опускается, VBA обычно (но не всегда) «полагает», что имеется в виду текущая активная рабочая книга или документ. Следующее объектное выражение эквивалентно предыдущему при условии, что рабочая книга Sales.xls является активной:
Worksheets("Отчет").Range("Al")
Если Sales.xls — активная рабочая книга, а Отчет — активный лист, то следующее объектное выражение также эквивалентно предыдущему:
Range("Al")
Однако во многих процедурах невозможно определить с уверенностью, что какая-либо отдельная рабочая книга (рабочий лист или документ) является активной, во время выполнения процедуры, поэтому, вероятно, потребуется определить, по крайней мере, некоторые из контейнеров для объекта, на который необходима ссылка.
Не забывайте использовать методы и свойства, возвращающие объекты (такие как ActiveWorkbook и ActiveDocument ), чтобы делать контейнерные объектные ссылки короче. Использование структуры With...End With является идеальным способом избежать записи длинных объектных ссылок более одного или двух раз в одной процедуре.
Чтобы лучше понять контейнерные объекты и коллекции, необходимо помнить, что программный объект не является физическим предметом, находящимся в другом физическом предмете. Помните, что объект, содержащий другой объект, на самом деле просто имеет адрес памяти другого объекта. Контейнеры ссылаются на объекты, которые они «содержат», посредством их адресов. Точно так, как многие различные люди могут иметь ваш почтовый адрес, но вы не присутствуете физически в их доме, на любой отдельный программный объект могут ссылаться несколько других объектов через его адрес.
При необходимости ссылаться на контейнер какого-либо объекта используйте свойство Parent этого объекта. Все объекты имеют свойство Parent, которое возвращает объектную ссылку на контейнер объекта. Например, следующее объектное выражение ссылается на Excel-объект Application, содержащий коллекцию Workbooks:
Workbooks.Parent
В табл. 10.7 перечислены несколько наиболее часто используемых коллекций объектов в Excel 2000/2002 версии Visual Basic for Applications. В таблице приводится имя коллекции и краткое описание ее назначения.
Таблица 10.7. Общие коллекции Excel 2000/2002
Коллекция	Назначение
Addins	Коллекция надстроек приложения.
Charts	Коллекция всех таблиц (Chart sheets) в рабочей книге.
246
Глава 10
Коллекция	Назначение
Chartobjects	Коллекция всех объектов Chart в рабочем листе.
Dialogs	Коллекция всех диалогов в приложении.
Windows	Коллекция всех окон в приложении, независимо от того, отображается ли окно на экране.
Workbooks	Коллекция всех открытых в данных момент рабочих книг в приложении.
Worksheets	Коллекция всех рабочих листов в рабочей книге.
В табл. 10.8 перечислены некоторые наиболее часто используемые коллекции объектов в Word 2000/2002 версии VBA. В таблице приводится имя коллекции и краткое описание ее назначения.
Таблица 10.8. Общие коллекции Word 2000/2002
Коллекция	Назначение
Addins	Коллекция надстроек приложения.
Bookmarks	Коллекция всех закладок в документе, разделе или диапазоне (в зависимости от контейнера).
Characters	Коллекция всех символов в документе, разделе или диапазоне (в зависимости от контейнера). Каждый элемент в коллекции Characters является объектом Range, содержащим один символ.
Comments	Коллекция всех комментариев документа.
Dialogs	Коллекция диалогов приложения.
Documents	Коллекция всех открытых в данный момент документов.
Paragraphs	Коллекция объектов Paragraph в документе, разделе или диапазоне (в зависимости от контейнера).
Sections	Коллекция разделов в документе, разделе или диапазоне (в зависимости от контейнера).
Styles	Коллекция описаний стилей в документе для встроенных и определенных пользователем стилей.
Templates	Коллекция всех шаблонов приложения.
Windows	Коллекция всех окон в приложении или коллекция всех окон (отображающих документ в зависимости от контейнера).
Добавление к коллекциям
Большую часть времени вы будете работать с элементами, уже существующими в коллекции. Время от времени будет необходимо добавить какой-либо элемент в коллекцию. В Excel вы, вероятно, захотите создать новую рабочую книгу или добавить новый рабочий лист в рабочую книгу; в Word нужно будет создать новый документ или добавить новую закладку в документ. В этих случаях необходимо добавлять новый элемент в соответствующую коллекцию объектов.
Каждая коллекция имеет метод Add (это один из базовых методов коллекции), который добавляет новый элемент в эту коллекцию. Многие из методов Add имеют один или несколько аргументов, которые позволяют задавать различные начальные значения или условия для свойств новых объектов. Следующий опера
Объекты и коллекции, введение
247
тор показывает метод Add коллекции Workbooks, используемый для создания новой рабочей книги Excel:
Workbooks.Add
Этот оператор создает новую рабочую книгу и делает ее активной. Следующий оператор показывает метод Add коллекции Documents, используемой для создания нового документа Word: .
Documents.Add
Этот оператор создает новый документ и делает его активным.
Ссылка на конкретные объекты в коллекции или контейнере
Для задания отдельного элемента в коллекции используйте следующий синтаксис:
СИНТАКСИС
Collection (Index)
Collection — любое допустимое объектное выражение, ссылающееся на коллекцию. Index может быть либо строкой, либо целым, обозначающим конкретный необходимый элемент. Если аргумент Index является строкой, строка должна содержать текстовое имя объекта.
Например, в Excel можно использовать имя рабочего листа (показано на ярлычке листа), именованного диапазона в рабочем листе, файла рабочей книги, кнопки панели инструментов или команды меню и так далее в качестве Index для соответствующей коллекции. Например, для ссылки на рабочий лист с именем Данные июля в активной рабочей книге следует использовать такой оператор:
Worksheets("Данные июля")
В Word можно использовать имя файла документа, закладки, стиля и так далее в качестве аргумента Index для коллекции. Например, для ссылки на закладку с именем Последняя закладка в документе Отчет за июль нужно использовать следующий оператор:
Documents("Отчет за июль").Bookmarks("Последняя закладка")
Когда Index — целое, оно является номером элемента в коллекции. Каждый элемент нумеруется в том порядке, в котором он добавляется в коллекцию. Поэтому не существует легкого способа определения индексного номера любого данного элемента коллекции.
Обычно следует использовать текстовое имя для ссылки на элемент в коллекции; это не только позволяет точно определить, на какой элемент необходима ссылка, но и делает код более читабельным. Worksheets("OT4eT”) гораздо понятнее, чем Worksheets(5).
Для ссылки на все элементы в коллекции не включайте никакого индекса. Следующий оператор закрывает все видимые открытые рабочие книги в Excel:
Workbooks.Close
Следует помнить о том, что методы и свойства в объекте Application принадлежат host-приложению, а не VBA. Когда вы работаете с различными host-прило-жениями VBA, некоторые из методов и свойств в объекте Application могут варьироваться в зависимости от конкретного host-приложения: Excel 2000/2002, Word 2000/20 02 и т.д.
Не забывайте, что объект Application предоставляет много полезных методов и свойств, а также предоставляет контейнер для объектов host-приложения. Например, помните, что Excel-функции рабочего листа, такие как SUM, MIN, MAX
248
Глава 10
и так далее, доступны через объект Application. Word-объект Application содержит методы для преобразования дюймов в точки, точек в дюймы и другие.
Как уже отмечалось, объект Application может содержать методы с именами, дублирующими имена процедур или функций VBA. При использовании метода host-приложения, дублирующего имя процедуры или функции VBA, необходимо задавать объект Application, иначе VBA «полагает», что вы хотите использовать процедуру или функцию VBA.
Например, Excel-объект Application содержит метод InputBox. Excel-метод InputBox — это не то же самое, что VBA-функция InputBox: Excel-метод Application.InputBox имеет на один аргумент больше (подробно описано в конце главы 6), чем VBA-метод InputBox; этот дополнительный аргумент позволяет ограничивать тип данных (численный, даты, текстовый), вводимый пользователем в диалоговое окно. Чтобы использовать Excel-метод InputBox, необходимо задать объект Application:
Application.InputBox
В противном случае VBA «полагает», что вы хотите использовать VBA-функ-цию InputBox.
Фигуры в слое векторной графики
VBA поддерживает общую модель объектов слоя векторной графики в Microsoft Word, Microsoft Excel и Microsoft PowerPoint. Верхним уровнем этой модели является коллекция Shapes, содержащая все графические объекты (Shape-объекты), которые включаются в слой векторной графики. Кроме коллекции Shapes, можно в качестве коллекции нескольких Shape-объектов использовать коллекцию ShapeRange, объединяющую некоторое подмножество фигур в векторном слое (часть коллекции Shapes).
Добавление к коллекции Shapes «автофигур»
Прежде чем работать с Shape-объектом, необходимо добавить его к (быть может, пока еще пустой) коллекции Shapes, используя ее метод AddShapes:
СИНТАКСИС
expression.AddShape(Type, Left, Top, Width, Height)
Здесь expression — любое Shapes-выражение; Type — константа (тип Long), определяющая тип фигуры и принимающая одно из msoAutoShapeType-зна-чений (например, msoShapeFlowchartData, msoShapeFlowchartMerge, msoS-hapeLeftBracket, msoShapcRectangle, msoShapeHeart, msoShapeRightTri-angle, msoShapeHexagon, msoShapeHorizontalScroll, msoShapeWave — всего около 140 констант); Left — положение (тип Single) левого угла автофигуры (измеряется в «пойнтах»); Тор — положение (тип Single) верхнего угла автофигуры; Width— ширина (тип Single) автофигуры; Height — высота (тип Single) автофигуры.
При добавлении в коллекцию Shapes фигура получает имя (свойство Name) по умолчанию, но его можно указать, используя следующий синтаксис:
expression.AddShape(Type, Left, Top, Width, Height) .Ыате=<и^1я фигуры>
Для получения ссылки на всю коллекцию объектов в слое векторной графики необходимо использовать следующий синтаксис:
СИНТАКСИС
mDocument.Shapes.SelectAll
Объекты и коллекции, введение
249
В листинге 10.7 приведен код, использующий метод AddShape для добавления фигур к коллекции Shapes текущего документа Word. На рис. 10.13 добавленные фигуры отображены в текущем документе.
Листинг 10.7. Добавление фигур к документу
1	Sub ActDocumShapes() ♦
2	' добавление фигур к документу 3
4	' добавить к коллекции Shapes прямоугольник:
5	ActiveDocument.Shapes.AddShape(msoShapeRectangle, _
6	150, 150, 70, 70).Name = "Rectangle"
7
8	' добавить к коллекции Shapes правый треугольник:
9	ActiveDocument.Shapes.AddShape(msoShapeRightTriangle, _
10	300, 150, 70, 40).Name = "RightTriangle"
11
12	' добавить "горизонтально ракручивающийся лист":
13	ActiveDocument.Shapes.AddShape(msoShapeHorizontalScroll,
14	450, 150, 70, 90).Name = "Horizontalscroll"
15
16	' выделить все фигуры коллекции:
17	ActiveDocument.Shapes.SelectAll
18
19	End Sub
Рис. 10.13
Добавленные к коллекции Shapes фигуры отображены в текущем документе
В листинге 10.8 приведен код, использующий метод AddShape для добавления фигур к коллекции Shapes первого слайда1 текущей презентации. На рис. 10.14 добавленные фигуры отображены на слайде 1 текущей презентации.
Листинг 10.8. Добавление фигур к презентации 1 2 3 4 5 6
1 Sub ActPreShapes()
2 ' добавление фигур к первому слайду текущей презентации
3
4	' добавить фигуру к коллекции Shapes:
5 ActivePresentation.Slides(1).Shapes.AddShape( _
6	msoShape24pointStar, 150, 150, 70, 70).Name = "pointStar24"
1 Подобно листам в Excel в PowerPoint имеется коллекция слайдов.
250
Глава 10
7
8	' добавить фигуру к коллекции Shapes:
9	ActivePresentation.Slides(1).Shapes.AddShape( _
10	msoShape32pointStar, 250, 150, 200, 120).Name = "pointSta32"
11	End Sub
Рис. 10.14
Добавленные к коллекции Shapes фигуры отображены на первом слайде текущей презентации
^Microsoft PowerPoint - [Презентация 11	; гл
-spj Файл Ставка Вид Вставка Формат Сервис Показ слайдов Окно £гравка
Действия ” । tfr Автофис/ры» u J [ 1 4 t ’ 2 ’ 4 • ” Слайд 1 из 1 кормление по умолчана русский (Россия)
Чтобы получить коллекцию ShapeRange, являющуюся подмножеством коллекции Shapes, необходимо использовать следующий синтаксис:
СИНТАКСИС
Shapes.Range(index)
Здесь index — имя/индекс фигуры или массив имен/индексов фигур.
Чтобы получить коллекцию ShapeRange, представляющую все фигуры коллекции Shapes, необходимо использовать следующий синтаксис:
СИНТАКСИС
Selection ShapeRange
Чтобы получить коллекцию ShapeRange, представляющую все фигуры коллекции Shapes, необходимо использовать следующий синтаксис:
СИНТАКСИС
Selection.ShapeRange(index)
Здесь index — имя/индекс фигуры или массив имен/индексов фигур.
Например, при помощи кода листинга 10.9 можно «закрасить» фигуры, созданные кодом листинга 10.7. На рис. 10.15 отображены закрашенные фигуры.
Листинг 10.9. Использование коллекции ShapeRange
1 Sub ActDocumShapeRange()
2 ' Использование коллекции ShapeRange
3
Объекты и коллекции, введение
251
4	' "закрасить" первые две фигуры в коллекции Shapes:
5	ActiveDocument.Shapes.Range(Array(1, 2)).Fill.PresetGradient
6	msoGradientHorizontal, 1, msoGradientLateSunset
1
8	' выделить все фигуры коллекции:
9	ActiveDocument.Shapes.SelectAll
10
11	' "закрасить" третью фигуру коллекции ShapeRange:
12	ActiveWindow.Selection.ShapeRange(3).Fill.PresetGradient _
13	msoGradientVertical, 1, msoGradientLateSunset
14
15	End Sub

Рис. 10.15
Добавленные к коллекции Shapes фигуры закрашены кодом листинга 10.9
ц! Chapter 10 - Microsoft Word
файл фавка &дд Встдоа Формат Сервис Таблица фно Оправка
51 115%	* * Listing top + Times N -
Исправления в измененном документе - Показать*	р .
L.	il>-2»3'-4-i5i6'7i8'9il0<llil2
Например, при помощи кода пистннга 10 9 можно '<закрэ«лпы> фигуры созданные кодом лисп
Листинг 10.9. Использование коллекцип
1 1 2 3
4 5 б
7 8
9
' 'закг Аспу nys<
фигуры в коллекци ^ng^(Arr%v(l,2))Fjl
1. rnsoQfgdienii^Sunset
'выдедр	^*1ллекции
'Исполь^МвНм* ShapesRange
10
11	' 'закрасить' третью фигуру коллекции ЗДареКадде
12	УШ PresetGradient
13	(Ti50Gr?dierity ?rti?al, 1, rn$o<ftadientMHSunset
Стр 23 Разд 1	23/24 На S Зсм Ст 6 Кол 1
Добавление к коллекции Shapes специальных фигур
Кроме добавления к коллекции Shapes документа (листа, презентации) «автофигуры» (методом AddShape), можно также добавлять специальные элементы оформления, используя такие методы, как AddCallout, AddComment и другие (см. таблицу 10.9).
Таблица 10.9. Методы для добавления фигур в документы, листы или слайды
Метод	Синтаксис	Назначение
Word:		
AddCallout	AddCallout( Type As MsoCalloutType, Left As Single, Top As Single, Width As Single, Height As Single, [Anchor]) As Shape	Добавляет в документ не имеющую границ выноску. Возвращает Shape-объект, представляющий эту выноску, и добавляет его в коллекцию Shapes.
AddCanvas	AddCanvas( Left As Single, Top As Single, Width As Single, Height As Single, [Anchor]) As Shape	Добавляет в документ «полотно» для рисования (drawing canvas). Возвращает Shape-объект, представляющий «полотно» для рисования, и добавляет его в коллекцию Shapes.
252
Глава 10
Метод	Синтаксис	Назначение
AddCurve	AddCurve( SafeArrayOfPoints, [Anchor]) As Shape	Возвращает в документ Shape-объект, который представляет кривую Безье.
AddDiagram	AddDiagram( Type As MsoDiagramType, Left As Single, Top As Single, Width As Single, Height As Single, [Anchor]) As Shape	Возвращает в документ Shape-объект, который представляет только что созданную диаграмму.
AddLabel	AddLabel(Orientation As MsoTextOrientation, Left As Single, Top As Single, Width As Single, Height As Single, [Anchor]) As Shape	Добавляет в документ надпись в виде прямоугольника с невидимыми границами и без заливки. Возвращает Shape-объект, который представляет эту надпись, и добавляет его в коллекцию Shapes.
AddLine	AddLine(BeginX As Single, BeginY As Single, EndX As Single, EndY As Single, [Anchor]) As Shape	Добавляет линию в документ. Возвращает Shape-объект, который представляет эту строку, и добавляет его в коллекцию Shapes.
AddOLE-Control	AddOLEControl([C/assTi/pe], [Left], [Top], [Width], [Height], [Anchor]) As Shape	Создает элемент управления ActiveX (ранее известный как OLE-элемент управления). (Только в Word; в Excel и PowerPoint используйте AddOLEObject) Возвращает Shape-объект, который представляет новый элемент управления ActiveX.
AddOLE-Object	AddOLEObject([CZassTi/pe], [FileName], [LinkToFile], [DisplayAsIcon], [IconFileNante], [Iconindex], [IconLabel], [Left], [Top], [Width], [Height], [Anchor]) As Shape	Создает OLE-объект. Возвращает Shape-объект который представляет новый OLE-объект.
AddPicture	AddPicture(FiZeName As String, [LinkToFile], [SaveWithDocument], [Left], [Top], [Width], [Height], [Anchor]) As Shape	Добавляет картинку в документ. Возвращает Shape-объект, который представляет эту картинку, и добавляет его в коллекцию Shapes.
AddPolyline	AddPolyline(SafeAzrai/OfPoints, [Anchor]) As Shape	Добавляет ломаную линию или многоугольйик в документ. Возвращает Shape-объект, который представляет эту ломаную линию или многоугольник, и добавляет его в коллекцию Shapes.
Объекты и коллекции, введение
253
Метод	Синтаксис	Назначение
AddTextbox	AddTextbox(Onentation As MsoTextOrientation, Left As Single, Top As Single, Width As Single, Height As Single, [Anchor}) As Shape *	Добавляет в документ прикрепленную текстовую рамку в виде прямоугольника с невидимыми границами и без заливки. Возвращает Shape-объект, который представляет эту текстовую рамку, и добавляет его в коллекцию Shapes.
AddText-Effect	AddTextEffec^PresetTextEffect As MsoPresetTextEffect, Text As String, FontName As String, FontSize As Single, FontBold As MsoTriState, Fontltalic As MsoTriState, Left As Single, Top As Single, [Anchor]) As Shape	Добавляет WordArt-объект в документ. Возвращает Shape-объект, который представляет этот WordArt-объект и добавляет его в коллекцию Shapes.
Excel:		
AddCallout	AddCallout(Ti/pe As MsoCalloutType, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Добавляет в документ не имеющую границ выноску. Возвращает Shape-объект, представляющий эту выноску.
Add-Connector	AddConnector(Tz/pe As MsoConnectorType, BeginX As Single, BeginY As Single, EndX As Single, EndY As Single) As Shape	Создает соединительную линию. Возвращает Shape-объект, который представляет новую соединительную линию. Когда добавляется соединительная линия,она не соединена ни с чем.
AddCurve	AddCurNe(SafeArrayOfPoints) As Shape	Когда применяется к объекту коллекции Shapes, возвращает Shape-объект, который представляет кривую Безье в электронной таблице.
AddDiagram	AddDiagramCType As MsoDiagramType, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает диаграмму. Возвращает Shape-объект, который представляет новую диаграмму.
AddForm	AddFormControl(Ti/pe As XlFormControl, Left As Long, Top As Long, Width As Long, Height As Long) As Shape	Создает элемент управления Microsoft Excel. Возвращает Shape-объект, который представляет новый элемент управления.
AddLabel	AddLabel(Orientation As MsoTextOrientation, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Добавляет в документ надпись в виде прямоугольника с невидимыми границами и без заливки. Возвращает Shape-объект, который представляет эту новую надпись.
254
Глава 10
Метод	Синтаксис	Назначение
AddLine	AddLine(BeginX As Single, BeginY As Single, EndX As Single, EndY As Single) As Shape	Когда применяется к объекту коллекции Shapes, возвращает Shape-объект, который представляет новую линию в электронной таблице.
AddOLE- Object	AddOLEObj ect([ClassType], [Filename], [Link], [DisplayAslcon], [IconFileName], [Iconindex], [IconLabel], [Left], [Top], [Width], [Height]) As Shape	Создает OLE-объект. Возвращает Shape объект, который представляет этот новый OLE-объект.
AddPicture	AddPicture(Fi/ename As String, LinkToFile As MsoTriState, SaveWithDocument As MsoTriState, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает картинку из существующего файла. Возвращает Shape-объект, который представляет новую картинку.
AddPolyline	AddPolyline(SafeArrayOfPoints) As Shape	Создает ломаную линию или многоугольник. Возвращает Shape-объект, который представляет новую ломаную линию или многоугольник.
AddTextbox	AddTextbox(Orientation As MsoTextOrientation, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает прикрепленную текстовую рамку в виде прямоугольника с невидимыми границами и без заливки. Возвращает Shape-объект, который представляет новую текстовую рамку.
AddText-Effect	AddTextEffect(PresetTextEffect As MsoPresetTextEffect, Text As String, FontName As String, FontSize As Single, FontBold As MsoTriState, Fontltalic As MsoTriState, Left As Single, Top As Single) As Shape	Создает WordArt-объект. Возвращает Shape-объект, который представляет новый WordArt-объект.
PowerPoint:		
AddCallout	AddCallout(Type As MsoCalloutType, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает не имеющую границ выноску. Возвращает Shape-объект, представляющий эту новую выноску
Add- Comment	AddComment([Left As Single = 1], [Top As Single = 1], [Width As Single = 145], [Height As Single = 145]) As Shape	Добавляет комментарий. Возвращает Shape-объект, который представляет новый комментарий.
Add-Connector 1	AddConnector(Type As MsoConnectorType, BeginX As Single, BeginY As Single, EndX As Single, EndY As Single) As Shape	Создает соединительную линию. Возвращает Shape-объект, который представляет новую соединительную линию. Когда добавляется соединительная линия,она не соединена ни с чем.
Объекты и коллекции, введение
255
Метод	Синтаксис	Назначение
AddCurve	AddCurve(SafeArrayOfPoints) As Shape	Создает кривую Безье. Возвращает Shape-объект, который представляет новую кривую.
AddDiagram	AddDiagram(Type As MsoDiagramType, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Возвращает Shape-объект, который представляет диаграмму, вставленную в слайд, master-слайд или slide range-слайд.
AddLabel	AddLabel(Orientation As MsoTextOrientation, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает надпись в виде прямоугольника с невидимыми границами и без заливки. Возвращает Shape-объект, который представляет эту новую надпись.
AddLine	AddLine(BeginX As Single, BeginY As Single, EndX As Single, EndY As Single) As Shape	Создает линию. Возвращает Shape-объект, который представляет эту новую линию.
AddMedia-Ob ject	AddMediaObject(FileName As String, [Left As Single], [Top As Single], [Width As Single = -1], [Height As Single = -1]) As Shape	Создает media-объект. Возвращает Shape-объект, который представляет новый media-объект.
AddOLE- Ob ject	AddOLEObject([Left As Single], [Top As Single], [Width As Single = -1], [Height As Single = -1], [ClassName As String], [FileName As String], [DisplayAslcon As MsoTriState], [IconFileName As String], [Iconindex As Long], [IconLabel As String], [Link As MsoTriState]) As Shape	Создает OLE-объект. Возвращает Shape-объект, который представляет новый OLE-объект.
AddPicture	AddPicture(FileName As String, LinkToFile As MsoTriState, SaveWithDocument As MsoTriState, Left As Single, Top As Single, [Width As Single = -1], [Height As Single = -1]) As Shape	Создает картинку из существующего файла. Возвращает Shape-объект, который представляет новую картинку.
AddPlace-holder	AddPlaceholder(Type As PpPlaceholderType, [Left As Single = -1], [Top As Single = -1], [Width As Single = -1], [Height As Single = -1]) As Shape	Восстанавливает ранее удаленное поле для текста или графического объекта на слайде. Возвращает Shape-объект, который представляет это восстановленное поле.
AddPolyline	AddPolyline(SafeArrayOfPoints) As Shape	Создает ломаную линию или многоугольник. Возвращает Shape-объект, который представляет новую ломаную линию или многоугольник.
256
Глава 10
Метод	Синтаксис	Назначение
AddShape	AddShape(Type As MsoAutoShapeType, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает автофигуру (AutoShape). Возвращает Shape-объект, который представляет эту новую автофигуру.
AddTable	AddTable(NumRows As Long, NumColumns As Long, [Left As Single = -1], [Top As Single = -1], [Width As Single = -1], [Height As Single = -1]) As Shape	Добавляет объект-таблицу в слайд.
AddTextbox	AddTextbox(Orientation As MsoTextOrientation, Left As Single, Top As Single, Width As Single, Height As Single) As Shape	Создает прикрепленную текстовую рамку в виде прямоугольника с невидимыми границами и без заливки. Возвращает Shape-объект, который представляет новую текстовую рамку.
AddText-Effect	AddTextEffect(PresetTextEffect As MsoPresetTextEffect, Text As String, FontName As String, FontSize As Single, FontBold As MsoTriState, Fontltalic As MsoTriState, Left As Single, Top As Single) As Shape	Создает WordArt-объект. Возвращает Shape-объект, который представляет новый WordArt-объект.
AddTitle	AddTitle() As Shape	Восстанавливает ранее удаленное заглавие слайда. Возвращает Shape-объект, который представляет восстановленное заглавие.
Фигуры коллекции Shapes после их добавления в коллекцию можно редактировать: перемещать, удалять, изменять размеры, изменять внешний вид (как это, например, делается в коде листинга 10.9), добавлять в них текст. Редактирование фигур осуществляется изменением их свойств. Объекты коллекции Shapes обладают как общими (Left, Top, Height и Width), так и специфическими (зависящими от типа объекта) свойствами. Например, код листинга 10.10 сначала добавляет объект clock.avi к первому слайду презентации, а затем (строки 12-15) изменяет его высоту (свойство Height) и ширину (свойство Width). Результат работы кода листинга 10.10 представлен на рис. 10.16.
Листинг 10.10. Изменение свойств фигуры коллекции Shapes
1	Sub PropertyChangingl()
2	' добавление объекта к коллекции Shapes
3	' и изменение его размеров 4
5	Set myDocument = ActivePresentation.Slides(1) 6
7	' добавить объект к коллекции Shapes:
8	myDocument.Shapes.AddMediaOb^ect FileName:= _
9	"e:\win_xp\clock.avi", Left:=5, Top:=5, _
10	Width:=100, Height:=100
11
Объекты и коллекции, введение
257
12	' изменение размеров объекта:
13	With myDocument.Shapes(3)
14	Height = 200
15	.Width = 200
16	End With
17
18	End Sub
Рис. 10.16
Изменение размеров объекта коллекции Shapes кодом листинга 10 10
Код листинга 10.11 при добавлении к коллекции Shapes прямоугольника помещает в него текст. Результат работы кода листинга 10.11 (в Excel) представлен на рис. 10.17.
Рис. 10.17
Ввод текста для объекта коллекции
Shapes кодом
листинга 10 11
Листинг 10.11. Изменение свойств фигуры коллекции Shapes
1	Sub PropertyChanging2()
2	' добавление прямоугольника к коллекции Shapes
3	' и занесение в него текста 4
5	Set myDocument = Worksheets(1)
6
7
9 Программирование на VBA 2002
258
Глава 10
8	With myDocument.Shapes.AddShape(msoShapeRectangle, _
9	0, 0, 100, 40).TextFrame
10	.Characters.Text = "Пример текста внутри прямоугольника"
11	.MarginBottom = 10
12	.MarginLeft = 10
13	.MarginRight = 10
14	.MarginTop =10
15	End With
16	*
17	End Sub
Использование Object Browser с объектами, методами и свойствами
Вы уже знаете, как использовать Object Browser для нахождения и получения справки VBA и функций host-приложений, процедур и констант. Подобным образом Object Browser используется с объектами, методами и свойствами; в действительности, основное назначение инструмента Object Browser (как предполагает его имя) — это обеспечивать возможность просмотра всех доступных объектов (с их различными методами и свойствами) в VBA и host-приложении.
Вы уже знаете, как запустить Object Browser: щелкните на кнопке Object Browser на панели инструментов Visual Basic или выберите команду View | Object Browser (Вид | Просмотр объектов) для отображения окна Object Browser (рис. 10.18).
Рис. 10.18
Используйте Object Browser для определения того, какие объекты доступны и какие свойства и методы принадлежат определенному объекту
Members of 'Documents'
Classes
«3 DiagramNode *
<3 DiagramNodeCh
<3 DiagramNodes
3 Dialog
3 Dialogs
3 Dictionaries
3 Dictionary
3 Document
3 Documents
3 DropCap
3 DropDown
<Л| Prnsil	v
Й? Application CanCheckOut Checkout Close
Й? Count
Й* Creator
Item
Open
& Parent
* Save

Function Add([7empjlate]4 [NewTempiate] [DocumentType], [Vte/bte]) As Dyurnent Member of Л i I P vtiti^iit
Чтобы просмотреть список доступных объектов host-приложения и просмотреть список свойств и методов для каждого заданного объекта, выполните следующие шаги:
1.	Выберите библиотеку host-приложения в раскрывающемся списке Project/Lib-rary (Проект | Библиотека) в верхней части окна Object Browser. На рис. 10.18 показано открытое окно Object Browser в сеансе работы Редактора VB в Word; библиотека Word уже выбрана в раскрывающемся списке Project/Library. После выбора host-приложения в списке Project/Library список Classes (Классы) содержит все доступные для VBA объекты host-приложения.
2.	В списке Classes выберите объект, методы и свойства которого вас интересуют. На рис. 10.18 показана коллекция Documents.
Объекты и коллекции, введение
259
3.	Чтобы получить более подробную информацию об объекте, выбранном вами в списке Classes, щелкните на кнопке со знаком вопроса (?) (в верхней правой части окна Object Browser) для доступа к справочной системе VBA.
После выбора объекта в списке Classes список Members of <class> (Компонент <класс>) в окне Object Browser отображает все методы и свойства для этого объекта.
4.	В списке Members of<class> выберите нужный вам метод или свойство. Object Browser теперь отображает имя метода или свойства в нижней части окна; при выборе метода, имеющего аргументы, Object Browser перечисляет также все аргументы метода. На рис. 10.18 показан выбранный метод Add коллекции Documents.
5.	Щелкните на кнопке с вопросительным знаком в окне Object Browser для доступа к справочной системе VBA с целью получения подробной информации о методе или свойстве, выбранном в списке Members of<class>.
Чтобы вы могли различать методы и свойства в списке Members of <class>, Object Browser отображает особые значки слева от каждого элемента в списке. Свойства обозначаются значком с изображением руки, указывающей на индексную карту. Методы обозначаются значком, похожим на зеленый прямоугольник. Синий мячик (видимый как часть значка метода Item на рис. 10.18) обозначает, что свойство или метод является глобально доступным.
Используйте Object Browser для ознакомления с различными доступными объектами, методами и свойствами и для ускорения написания программного кода.
9*
Fnaea 11
Повторение действий в Visual Basic: циклы
У нас осталась, пожалуй, последняя тема (если не рассматривать работу с массивами, о которых вы узнаете из следующей главы), без которой пока еще невозможно писать хорошие программы на языке VBA. Теперь, когда вы научились выбирать различные действия на основе предопределенных условий, вы узнаете, что необходимо делать, чтобы процедуры VBA повторяли действия заданное количество раз или пока выполняется (или не выполняется) некоторое условие.
Команды организации циклов
Как уже вам стало ясно, макрорекордер позволяет записывать не все необходимые пользователю действия. Особенно это наглядно показано на примере операторов, изменяющих порядок выполнения кода процедур и функций. То же самое относится и к таким операторам, которые позволяют организовать циклическое повторение выполнения некоторых частей кода VBA.
Для организации циклов VBA предоставляет несколько мощных и гибких структур, позволяющих легко повторять различные действия. Программные структуры, приводящие к неоднократному повторению одного или нескольких операторов, называются структурами организации циклов, потому что поток выполнения операторов процедуры проходит циклично по одним и тем же операторам неоднократно.
Процесс выполнения всех операторов, заключенных в структуру цикла, один раз называется итерацией (iteration) цикла. Некоторые структуры цикла организуются так, что они всегда выполняются заданное количество раз. Структуры цикла, всегда выполняющиеся заданное количество раз, называются циклами с фиксированным числом итераций (fixed iteration). Другие типы структур цикла повторяются переменное количество раз в зависимости от некоторого набора условий. Поскольку количество раз повторений этих гибких структур цикла является неопределенным, такие циклы называются неопределенными циклами (indefinite loops).
Существуют два основных способа создания неопределенного цикла. Можно построить цикл так, что VBA будет тестировать некоторое условие (детерминант цикла) перед выполнением цикла: если условие для повторения цикла не равно True, VBA пропускает все операторы в цикле. Можно также построить цикл таким образом, что VBA будет тестировать услове детерминанта цикла после выполнения операторов в цикле.
Для цикла, в котором детерминант проверяется перед выполнением операторов внутри цикла, VBA определяет следующую последовательность действий:
	В верхней части цикла тестируется условие детерминанта.
	Если условия для выполнения цикла удовлетворяются, выполняются операторы внутри цикла.
	После выполнения последнего оператора внутри цикла VBA возвращается к началу цикла и снова оценивает условие детерминанта цикла.
Повторение действий в Visual Basic: циклы
261
	Если условия для выполнения цикла все еще удовлетворяются, VBA повторяет операторы внутри цикла и снова возвращается к началу цикла для тестирования детерминанта.
	Как только условия для выполнения цикла перестанут удовлетворяться, VBA останавливает выполнение цикла и начинает выполнение операторов после цикла.
Заметьте, что если условия для выполнения цикла не удовлетворяются, когда VBA тестирует условие детерминанта цикла в первый раз, VBA не выполняет операторы внутри цикла ни разу; при этом тело цикла пропускается (не выполняется). Тело (body) цикла — зто блок операторов VBA, находящийся между началом и концом цикла.
Для цикла, в котором детерминант проверяется после выполнения операторов в теле цикла, VBA определяет следующую последовательность действий:
	Выполняются все операторы в теле цикла.
	При достижении конца тела цикла, VBA оценивает условие детерминанта цикла.
	Если условия для выполнения цикла удовлетворяются, VBA возвращается к началу цикла и повторяет инструкции в теле цикла.
	В конце цикла VBA снова тестирует условие детерминанта цикла.
	Как только условия для выполнения цикла больше не удовлетворяются, VBA прекращает выполнение цикла и начинает выполнение операторов после цикла.
Заметьте, что VBA всегда выполняет операторы в таком цикле, по крайней мере, один раз.
Можно также создать неопределенный цикл таким образом, чтобы он не имел условия детерминанта вообще; циклы, не имеющие условия детерминанта, повторяются бесконечно и называются бесконечными циклами (infinite loops). Бесконечный цикл не заканчивается никогда; большинство бесконечных циклов являются результатом ошибок программирования, хотя имеется несколько случаев, когда удобно использовать бесконечные циклы.
Повторение цикла фиксированное число раз: циклы For
Самой простой структурой цикла является фиксированный цикл. VBA предоставляет две различные структуры фиксированного цикла: For ...Next и For Each... Next. Обе структуры фиксированного цикла называются циклами For, потому что они всегда выполняются для (for) заданного количества раз.
Использование цикла For...Next
Первый из VBA-циклов For — это цикл For...Next. Используйте цикл For ...Next, когда вам необходимо повторить действие или ряд действий заданное количество раз, известное до начала выполнения цикла.
Цикл For...Next имеет следующий синтаксис:
СИНТАКСИС	а
For counter = Start То End [Step Stepsize] Statements
Next [counter]
Здесь counter — любая численная переменная VBA, обычно — переменная типа Integer или Long; Start — любое численное выражение и определяет начальное значение для переменной counter; End — зто также численное выражение, определяет конечное значение для переменной counter (см. следующую диаграмму).
262
Глава 11
По умолчанию VBA увеличивает переменную counter на 1 каждый раз при выполнении операторов в цикле (считает количество циклов). Можно задавать другое значение (StepSize), на которое будет изменяться counter, включая необязательное ключевое слово Step. При включении ключевого слова Step необходимо задавать значение для изменения переменной counter. В указанной синтаксической конструкции StepSize представляет любое численное выражение и определяет значение для изменения переменной counter.
Statements представляет один, несколько или ни одного оператора VBA. Эти операторы составляют тело цикла For; VBA выполняет каждый из этих операторов при каждом выполнении цикла.
Ключевое слово Next сообщает VBA о том, что достигнут конец цикла; необязательная переменная counter после ключевого слова Next должна быть той же самой переменной counter, которая была задана после ключевого слова For в начале структуры цикла. Включайте необязательную переменную counter после ключевого слова Next для улучшения читабельности программного кода (особенно при использовании вложенных циклов For ...Next) и для повышения скорости выполнения кода (иначе VBA придется потратить время на определение того, какая переменная counter является правильной, для ее изменения после достижения ключевого слова Next).
При выполнении цикла For ...Next VBA поступает следующим образом:
	Присваивает значение, представленное Star, переменной counter.
	Выполняет все операторы, представленные с помощью Statements, пока не достигнет ключевого слова Next. Ключевое слово Next указывает VBA на то, что достигнут конец тела цикла.
	Изменяет переменную counter на величину StepSize (если включается необязательное ключевое слово Step). Если Step не определено, то VBA увеличивает переменную counter на 1.
	Возвращается к началу цикла и сравнивает текущее значение переменной counter со значением, представленным с помощью End. Если значение counter меньше или равно End, VBA выполняет цикл снова. Если значение counter больше End, VBA продолжает выполнение кода с первого оператора после ключевого слова Next.
Использование For...Next с возрастающим счетчиком
В листинге 11.1 демонстрируется использование цикла For ...Next. Эта процедура получает два числа от пользователя, складывает все числа в диапазоне, заданном этими двумя числами, а затем отображает результирующую сумму.
Повторение действий в Visual Basic: циклы
263
Листинг 11.1. Демонстрация цикла For...Next с возрастающим счетчиком
1	Sub Demo_ForNext() 2
3	Dim	k As	Integer
4	Dim	sStart As String
5	Dim	sEnd	As String
6	Dim	ISum	As Long
7
8	sStart = InputBox("Введите целое число:")
9	sEnd = InputBox ("Введите другое целое число:")
10
11	ISum = 0
12	For i = CInt(sStart)	To Clnt(sEnd)
13	ISum = ISum + i
14	Next i
15
16	MsgBox "Сумма чисел от " & sStart & _
17	" до " & sEnd & " равна: " & ISum
18	End Sub
Переменная i используется как счетчик цикла For ...Next (буквы i, j, k, 1, m, n чаще всего используются программистами в качестве счетчиков цикла, видимо, они больше других напоминают переменные целых типов); другие переменные используются для сохранения начального (sStart) и конечного значений (sEnd), полученных от пользователя, и для сохранения суммы чисел (ISum). Обратите внимание на типы этих переменных. Переменные sStart и sEnd в этой процедуре чаще всего используются для работы со строками (строки 8, 9, 16-17) и только в одном операторе (строка 12) нам понадобилось преобразовать их в числа. Переменная ISum, по существу, должна иметь тип числовой, причем как можно больший, потому что неизвестно, насколько большой диапазон будет вводиться пользователем, который будет испытывать этот код.
В процедуре предполагается, что первое вводимое число меньше, чем второе. Иначе тело цикла не выполнится ни разу и значение переменной ISum будет равно 0, так как она инициализируется этим значением в строке 11.
Со строки 12 начинается описание цикла For...Next. При обработке этой строки VBA сначала выполняет вызов функции CInt, которая преобразует пользовательский строковый ввод в числа типа Integer, а затем вставляет результирующие целые значения в оператор. VBA присваивает целый эквивалент значения, хранимого в sStart, переменной счетчика i. Затем значение в i сравнивается с целым эквивалентом числа, сохраненного в sEnd. Если i меньше или равно значению в sEnd, VBA выполняет тело цикла.
Этот цикл имеет только один оператор в своем теле: выражение сложения и присваивания (в строке 13). В строке складывается текущее значение i с текущим содержимым переменной ISum, а затем результат сложения присваивается переменной ISum.
Далее VBA переходит к оператору Next (в строке 14), который указывает на конец тела цикла For; VBA увеличивает переменную счетчика на 1 (по умолчанию) и возвращается к началу цикла (строка 12) и снова сравнивает значение в переменной счетчика i с числом, хранимым в переменной sEnd.
Как только значение в счетчике цикла превысит значение, определенное для конечного значения счетчика (а это зависит от вводимых данных), VBA прекращает выполнение цикла.
Теперь, когда цикл закончился, VBA продолжает выполнение кода с оператора MsgBox в строке 16, который отображает два введенных числа и сумму всех целых в этом диапазоне.
264
Глава 11
Рис. 11.1
Результирующее окно кода листинга 11.1
Сумма чисел от 10 до 20 равна: 165
|  ОК
Если вы хорошо разобрались с циклом For...Next, то, наверное, заметили, что этот цикл (как, впрочем, и рассматриваемые далее) можно реализовать оператором If...Then...Else. Чтобы зто понять, достаточно сравнить диаграммы, спровож-дающие синтаксис этих операторов. Дело только в том, что оператор For...Next и короче в записи, и быстрее при выполнении кода.
Использование For...Next с убывающим счетчиком
Не всегда бывает нужно записывать циклы For...Next с возрастающим счетчиком. Иногда легче или полезнее писать цикл For с убывающим счетчиком. Чтобы цикл For...Next имел убывающий счетчик, используйте ключевое слово Step и отрицательное число (в синтаксической конструкции StepSize может иметь любой знак) для значения шага.
В листинге 11.2 показана процедура, полученная из предыдущего кода, но здесь добавлена возможность вводить значения шага цикла. Если при тестировании сначала ввести большее число, затем — меньшее и -1, то мы получим цикл For...Next с убывающим счетчиком. Понятно, что при вводе сначала меньшего числа, затем — большего и +1, мы получим обычный цикл с возрастающим счетчиком.
Листинг 11.2. Цикл For...Next с использованием шага изменения счетчика цикла
1	Sub Demo_ForNext()
2
3	Dim	i As Integer
4	Dim	sStart As String	'
5	Dim	sEnd As String
6	Dim	sStep As String
7	Dim	uSum As Long
8
9	uStart = InputBox("Введите целое число:")
10	uEnd = InputBox("Введите другое целое число:")
11	sStep = InputBox ("Введите шаг цикла (целое число):")
12
13	uSum = О
14	For i = CInt(uStart) To CInt(uEnd) Step CInt(sStep)
15	uSum = uSum + i
16	Next i	,
17
18	MsgBox "Сумма чисел от " & uStart & _
19	" до " & uEnd & " шагом " & sStep & " равна: " & uSum
20	End Sub
Просматривая код листинга 11.2, помните, что при уменьшении счетчика цикла For...Next цикл выполняется, пока переменная счетчика больше или равна конечному значению, а когда счетчик цикла увеличивается, цикл выполняется, пока переменная счетчика меньше или равна конечному значению.
Приведем еще один пример с использованием цикла For...Next и обработки строковых переменных. Довольно часто в различных приложениях приходится создавать уникальные строки для использования их в качестве кодов некоторых объектов (например, в базах данных). Обычно для этих целей используют генераторы случайных (чаще всего — псевдослучайных) чисел и (при необходимости) пе
Повторение действий в Visual Basic: циклы
265
реводят их в строки. Если получаемые строки используются и создаются в течение долгого времени, существует вероятность совпадения новых строк со старыми. Если уникальные строки (и соответствующие им другие данные) располагать в порядке возрастания (строки ведь тоже можно сравнивать), то их можно создавать так, что следующая создаваемая строка должна быть больше последней имеющейся в наборе, отличаясь только «на один символ». Например, для строк из четырех символов можно записать неравенства:
"АООХ" < "A00Y" < "A00Z" < "А0010" ...
Код листинга 11.3 является примером функции, которая создает строку, отличающуюся от аргумента так, как отличаются друг от друга строки, приведенные выше.
Листинг 11.3. Использование For...Next - пример в Excel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1Э
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Function NextCode(PrevCode As String) As String ' функция возвращает код такой же длины, что и входной параметр ' первый символ строки выбирается из диапазона символов, ' отличающегося от диапазона для остальных символов
Dim masl As String, masi As String, s4 As String, s3 As String Dim s2 As String, si As String, lenmasl As Integer Dim lenmas2 As Integer, lenmasNewCode As Integer
Dim masNewCodeO As String ' массив с новыми значениями ' символов кода ' строки для выбора символов masl = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"	' для первого символа
masi = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ' для остальных
lenmasl = Len(masl)	' длина строки masl
lenmasi = Len(masi)	' длина строки masi
lenmasNewCode == Len(PrevCode) ' длина входной строки
' заполнение массива символами входной строки: For i = 1 То lenmasNewCode
ReDim Preserve masNewCode(i) masNewCode(i - 1) = Mid(PrevCode, i, 1) Next ' замена символов входной строки на новые, ' начиная с последнего символа: For i = lenmasNewCode - 1 То 0 Step -1 If i > 0 Then ' положение i-го символа в заданном диапазоне: posi = InStr (1, masi, masNewCode(i)) If posi = lenmasi Then
1 символ последний в диапазоне: masNewCode(i) = Mid(masi, 1, 1) Else
' выбор следующего символа из диапазона: masNewCode(i) = Mid(masi, posi + 1, 1) Exit For
End If
Else ' изменение первого символа в строке: posi = InStr(1, masl, masNewCode(i)) If posi = lenmasl Then ' аварийный, но вряд ли достижимый случай: MsgBox "Первый символ вышел из своего диапазона!"
Else masNewCode(i) = Mid(masl, posi + 1, 1)
266
Глава 11
47	End If
48	End If
49
50 Next
51
52	' формирование	результата функции:
53	NextCode =
54	For i = 0 Io	lenmasNewCode -	1
55	NextCode = NextCode & masNewCode(i)
56	Next
57
58	End Function * 1 2 3 4 5
Основная идея алгоритма, реализованного этим кодом, заключается в следующем. Каждая позиция в генерируемой строке может содержать символы из некоторого диапазона символов1, который можно задавать произвольным образом, но символы диапазона должны быть упорядочены по возрастанию. С использованием цикла с отрицательным шагом (строки 27-50) входная строка просматривается, начиная с последнего символа; определяется позиция последнего символа в заданном для него диапазоне. Если текущий рассматриваемый символ не совпадает с последним символом допустимого диапазона (находится в середине диапазона), то в выходной строке только этот символ заменяется на следующий символ из диапазона; на этом работа алгоритма заканчивается. Если же рассматриваемый символ совпадает с последним символом заданного диапазона, то он в выходной строке заменяется на первый символ диапазона, а символом, стоящим во входной строке слева от рассматриваемого, производятся те же действия, т.е. он становится текущим рассматриваемым символом.
Для задания диапазона допустимых символов используются строки символов: masl — допустимый диапазон начала строки (первый символ), masi — допустимый диапазон для остальных символов. Для положения текущего символа в диапазоне (в подстроке) используется функция InStr, позволяющая найти положение одной строки в другой строке. Функция Mid используется для выделения указанного (индексом) символа из строки.
На рис. 11.2 приведен пример использования функции: в колонке А помещены заданные строки (различной длины), а в колонке В — формулы NextCode(Ai). Обратите внимание на то, что результирующие строки отличаются от исходных на один или два символа (в конце).
Рис. 11.2
Использование функции листинга 11 4
Е) Microsoft Excel - Книга! ,
ЙГ] Файл Правка Вид вставка Формат Сервис Данные Окно Справка	-Эх
100% - ” Anal Суг	- 10 - Ж /< Д
В4 -г ft =NetxCode(A4)
1	AXXXY	AX.XXZ
2	AZZ04	AZZ05
3	BZZZZZ	С00000
4 iDCDFHZYIDCDFHZZ |
5	’
К < ► и\Лист1/ Лист 2 / Л11 <	| И]
В общем случае для каждой позиции в строке можно задавать свой диапазон допустимых символов. В рассматриваемом коде только первый символ выходной строки имеет диапазон символов, отличный от диапазона для остальных символов, что определялось спецификой реальной задачи, которая послужила поводом для включения этого кода в книгу.
Повторение действий в Visual Basic: циклы
267
Цикл For Each...Next
Второй цикл For, который имеется в VBA — это цикл For Each...Next. В отличие от цикла For...Next цикл For Each...Next не использует счетчик цикла. Циклы For Each...Next выполняются столько раз, сколько имеется элементов в определенной группе, такой как коллекция объектов или массив. (Коллекции объектов описываются в предыдущей, а массивы — в следующей главе.) Другими словами, цикл For Each-Next выполняется один раз для каждого элемента в группе.
Цикл For Each—Next имеет следующий синтаксис:
СИНТАКСИС	» г*,
For Each Element In Group
Statements
Next (Element]
Element — это переменная, используемая для итерации по всем элементам в определенной группе. Group — это объект коллекции или массив. Если Group — это объект коллекции, то Element должен быть переменной типа Variant, Object или заданным объектным типом, таким как Range, Worksheet, Document, Paragraph и так далее. Если Group — это массив, то Element должен быть переменной типа Variant; Statements — один, несколько или ни одного оператора VBA, составляющих тело цикла.
Цикл For Each—Next имеет меньше опций, чем цикл For...Next. Цикл For Each—Next всегда выполняется столько раз, сколько имеется элементов в определенной группе.
В листинге 11.4 показана функция с именем SheetExists, использующая цикл For Each—Next для определения того, существует ли определенный лист в рабочей книге Excel.
Листинг 11.4. Использование For Each—Next — пример в Excel
1 Function SheetExists(sName As String) As Boolean
2 1 11 Возвращает True, если лист sName в активной книге
3
4	Dim aSheet As Object
5	SheetExists = False
6
7	' цикл по всем листам co сравнением имен c sName,
8	' сравнение текстовое
9	For Each aSheet In ActiveWorkbook.Sheets
10	If (StrComp(aSheet.Name, sName, 1) = 0) Then
11	SheetExists = True ' найдено имя
12	Exit For	' выход из цикла
13	End If
14 Next aSheet
15 End Function
16
17 Sub Test_SheetExists ()
18 ' тестирует функцию SheetExists
19
20 Dim uStr As String
21
22 uStr = InputBox("Введите имя листа " & _
23	"текущей книги:")
24 If SheetExists (uStr) Then
25	MsgBox "Лист 1" & uStr & _
26	в текущей книге."
27 Else
268
Глава 11
28	MsgBox "Листа '" & uStr & _
29	НЕТ в текущей книге."
30	End If
31	End Sub
Функция SheetExists имеет один обязательный аргумент sName, в котором функции передается строка, содержащая имя искомого листа.'SheetExists возвращает значения типа Boolean: True, если лист с именем в sName, существует в текущей рабочей книге, иначе — False. Можно использовать подобную функцию в одной из процедур, чтобы убедиться в том, что рабочий лист (или диаграмма) существует, перед тем, как процедура выполнит команду обращения к этому листу. Если этого не предусмотреть, а лист действительно отсутствует, такая команда вызовет сообщение о runtime-ошибке и VBA прекратит выполнение программы. Функция, подобная SheetExists, позволяет писать процедуры так, чтобы они могли обнаруживать и исключать ошибки, которые могут возникнуть, например, когда пользователь вводит имя несуществующего рабочего листа.
В строке 4 объявляется объектная переменная aSheet для использования в цикле For Each...Next. В строке 5 результату функции SheetExists присваивается значение False. Теперь функция должна только установить, существует ли лист, и присвоить True результату функции в случае положительного результата. Если результату функции SheetExists не удалось присвоить значение True, значит лист не найден или случилось что-то еще, что подразумевает отсутствие листа.
В строке 9 начинается цикл For Each...Next, использующий объектную переменную aSheet как переменную Element для цикла. В качестве Group здесь выступает коллекция ActiveWorkbook.Sheets. Свойство Active Workbook — это свойство объекта Application и оно возвращает объектную ссылку на текущую активную рабочую книгу. Sheets — зто метод рабочей книги, который возвращает коллекцию всех листов в рабочей книге, включая рабочие листы и диаграммы.
В строке 10 начинается тело цикла, которое состоит из одного оператора If...Then. При выполнении строки 10 VBA сначала вызывает StrComp для сравнения строки в sName со строкой, сохраненной в свойстве Name листа, на который в данный момент ссылается aSheet. Этот вызов функции StrComp определяет, что сравнение должно быть текстовым, и, следовательно, на него не оказывают влияние различия в регистре строки в sName и строки в свойстве Name листа.
Если строка в sName совпадает со строкой в свойстве Name листа, VBA выполняет оператор в строке 11, который присваивает значение True результату функции. В строке 12 располагается оператор Exit For. Если вы еще не догадались, к чему приводит этот оператор, значит, вы еще не задумывались над тем, сколько же раз будет выполняться цикл в данном примере, даже если необходимый лист найдется в первой же итерации. На самом деле Exit For — это оператор немедленного выхода из цикла. Он не зависит от текущей итерации. Данный пример, как никакой другой, подходит для демонстрации этого оператора. Как только строка в sName совпадет со строкой в свойстве Name листа, VBA выполнит операторы в строках 11-12 и дальнейшая необходимость в цикле отпадет, хотя его можно было бы без вреда для программы выполнять и далее. В данной функции досрочный выход из цикла экономит только время (слово «только» использовано здесь не том смысле, что об этом не стоит беспокоиться; чаще всего в программах с хорошим пользовательским интерфейсом время — основная характеристика системы после надежности).
Когда заканчивается (или прерывается) выполнение цикла, VBA продолжает выполнение кода со строки 15, которой заканчивается функция SheetExists, и возвращает результат функции.
В строках 17-30 описана процедура Test_SheetExists для тестирования функции SheetExist. Процедура использует только уже изученные вами операторы, и, видимо, нет необходимости в ее подробном разборе.
Повторение действий в Visual Basic: циклы
269
На рис. 11.3 приведен фрагмент работы тестовой процедуры, которая обнаружила лист, имя которого было введено пользователем. Перед тестированием этого кода не забудьте создать лист с необходимым именем, чтобы не получать одни только сообщения об отсутствии листа.
Рис. 11.3
Результат поиска листа в рабочей книге кодом листинга 11.4
В листинге 11.5 показан еще один пример использования For Each...Next: на этот раз — для Word. Функция BookmarkExists из листинга 11.5 проверяет, существует ли определенная закладка в активном в данный момент документе, и если существует, переводит курсор к этой закладке.
Листинг 11.5. Поиск закладки в документе Word
1	Function BookmarkExists(BkMark As String) As Boolean
2	' Возвращает True, если закладка BkMark существует
3	' в активном документе
4
5	Dim InstBkMark As Object
6
7	BookmarkExists = False ' предположим, закладка не найдена
8
9	' цикл по всем закладкам; сравнение имени каждой
10	' закладки с BkMark; сравнение текстовое
11	For Each InstBkMark In ActiveDocument.Bookmarks
12	If (StrComp(InstBkMark.Name, BkMark, vbTextCompare) = 0) Then
13	' перейти к закладке:
14	Selection.GoTo	What:=wdGoToBookmark,	Name:=BkMark
15	BookmarkExists	= True
16	Exit For
17	End If	.	.
18	Next InstBkMark
19	End Function
20
21
22	Sub Test_BookmarkExists()
23	' тестирует функцию BookmarkExists
24
25	Dim uStr As String
26
27	uStr = InputBox("Введите имя закладки " & _
28	"в текущем документе:")
29	If BookmarkExists(uStr) Then
30	MsgBox "Закладка '" & uStr & _
270
Глава 11
31	"1 НАХОДИТСЯ в этом документе"
32	Else
33	MsgBox "Закладки '" & uStr & _
34	"' НЕТ в этом документе"
35	End If	,	’ ’
36	End Sub
Функция BookmarkExists работает в основном так же, как и функция Sheet-Exists. BookmarkExists имеет один обязательный аргумент BkMark, который содержит строку, представляющую имя закладки, поиск которой выполняется. BookmarkExists возвращает значение типа Boolean: True, если закладка, определяемая с помощью BkMark, находится в текущем документе, иначе — False.
В строке 5 объявляется объектная переменная InstBkMark для использования в цикле For Each...Next.
В строке 11 начинается цикл For Each...Next, использующий объектную переменную InstBkMark как переменную Element для цикла. В качестве Group выступает коллекция ActiveDocument.Bookmarks: ActiveDocument — это свойство объекта Word Application, которое возвращает объектную ссылку на активный в текущий момент документ. Bookmarks — это метод документа, возвращающий коллекцию всех закладок в документе.
В строке 12 начинается тело цикла, которое состоит из одного оператора If...Then. При выполнении строки 12 VBA сначала вызывает функцию StrComp для сравнения строки в BkMark со строкой, сохраненной в свойстве Name закладки, на которую в данный момент ссылается InstBkMark. При сравнении строк используется функция StrComp для текстового сравнения строк независимо от установок Option Compare.
Если строка в BkMark совпадает со строкой в свойстве Name закладки, VBA выполняет код в строках 14-15. В строке 15 присваивается значение True результату функции. С этим вы уже встречались в предыдущем листинге. В 14 строке располагается оператор перехода к найденной закладке. Этот оператор был получен из макроса, записанного рекордером, и состоит из вызова метода GoTO объекта Selection. Метод имеет два аргумента: What, которому присваивается значение встроенной константы wdGoToBookmark (выделенный фрагмент — закладка), и Name (наименование закладки), которому присваивается значение найденной метки.
Как и в предыдущем листинге, здесь используется «досрочный» выход из цикла, если закладка найдена.
Когда выполнение цикла для всех объектов в коллекции ActiveDocument.Bookmarks заканчивается, VBA продолжает выполнение кода со строки 19, которая заканчивает функцию BookmarkExists и возвращает результат функции.
В строках 22-36 объявляется процедура Test_BookmarkExists для тестирования функции BookmarkExists.
I
Циклы Do
VBA имеет чрезвычайно мощный оператор цикла для создания неопределенных структур цикла в процедурах и функциях. Обычно все VBA-неопределенные циклы строятся с помощью одного оператора неопределенного цикла: оператора Do. Оператор Do имеет так много опций и является настолько гибким, что в действительности он предоставляет четыре различных конструкции цикла в двух базовых категориях.
Две базовые категории конструкций цикла Do — это циклы, которые тестируют условие детерминанта до выполнения тела цикла, и циклы, которые тестируют условие детерминанта после выполнения тела цикла.
Условие детерминанта для неопределенного цикла задается с помощью логического выражения таким же образом, каким создаются логические выражения для использования с операторами If...Then.
Повторение действий в Visual Basic: циклы
271
VBA предоставляет два различных способа тестирования условия детерминанта для цикла. Можно построить цикл так, чтобы он выполнялся, пока условие детерминанта цикла будет равно True, и прекращал выполнение, когда это условие становится равным False. Можно также создать цикл так, чтобы он выполнялся, пока условие детерминанта цикла будет равно False, и прекращал выполнение, когда это условие станет равным True.
Чтобы цикл выполнялся, пока его условие детерминанта равно True, используйте в операторе цикла Do необязательное ключевое слово While. В этом случае VBA выполняет цикл, пока (while) условие детерминанта равно True, и прекращает выполнение цикла, как только это условие становится равным False.
Предположим, вам необходимо написать процедуру, помогающую пользователю вводить данные в рабочий лист. Для процедуры ввода данных обычно желательно, чтобы процедура повторяла некоторые операторы, получающие информацию от пользователя, пока еще есть данные для ввода, и прекращала повторение этих операторов, когда данных больше нет. Можно написать цикл Do, неоднократно получающий данные от пользователя, продолжающийся, пока пользователь вводит непустые строки, и прекращающий выполнение, как только пользователь вводит пустую строку. Условие детерминанта для этого цикла записывается так, чтобы логическое выражение было равно True (и поэтому цикл продолжал выполняться), пока пользовательский ввод не является пустой строкой. Если пользовательский ввод сохраняется в переменной с именем uStr, логическое выражение для детерминанта цикла может быть любым из следующих (оба логических выражения равны True, когда строка в uStr имеет ненулевую длину):
uStr о ""
Len(Trim(uStr)) о О
Для того чтобы цикл выполнялся пока его условие детерминанта равно False, используйте в операторе цикла Do необязательное ключевое слово Until. VBA выполняет такой цикл до тех пор, пока (until) условие не будет равно True, то есть цикл продолжает выполняться, пока условие детерминанта равно False, и прекращает выполнение, как только это условие становится равным True.
Например, может понадобиться написать процедуру, продвигающуюся по столбцам рабочего листа, применяя определенное форматирование текста, и останавливающуюся в первом пустом столбце. Можно написать цикл Do, который повторяет операторы для форматирования заголовка столбца по достижении пустой ячейки. Условие детерминанта для этого цикла записывается так, что соответствующее логическое выражение равно False, пока текущая ячейка не является пустой, и равно True, когда текущая ячейка пустая. При использовании свойства ActiveCell объекта Application для возврата текущей активной ячейки и при использовании свойства Value для получения содержимого ячейки это логическое выражение для детерминанта может быть любым из следующих (оба выражения равны True, если текущая ячейка пустая):
ActiveCell. Value .= ""
Len(Trim(ActiveCell.Value)) = 0
Используется ли ключевое слово While или Until — зависит в основном от того, как вы представляете условие, определяющее, должен ли цикл выполняться, и от вашего умения строить логическое выражение для условия детерминанта цикла:
	используйте While, если хотите, чтобы цикл продолжал выполняться, пока заданное условие равно True.
	используйте Until, если хотите, чтобы цикл продолжал выполняться, пока заданное условие равно False.
272
Глава 11
Как прервать выполнение макроса или процедуры
Поскольку одной из наиболее распространенных проблем, возникающих при работе с неопределенными циклами, является нечаянное создание бесконечного цикла, важно знать, как прерывать работу VBA, когда выполняются макросы и процедуры. Используйте один и тот же метод для прерывания записанных рекордером макросов или для прерывания процедур и функций, написанных вами самостоятельно.
Для прерывания выполнения VBA нажмите клавишу Esc или комбинацию клавиш Ctrl+Break. VBA заканчивает выполнение текущего оператора, переходит в состояние ожидания и отображает окно сообщения о runtime-ошибке, показанное на рис. 11.4. Командные кнопки в этом окне сообщения те же и имеют то же назначение, что и в любом другом окне сообщения о runtime-ошибке:
	Continue. Возобновляет VBA-выполнение программных операторов. Обычно не следует выбирать эту кнопку после прерывания бесконечного цикла, поскольку она просто запустит бесконечный цикл снова.
	End. Заканчивает программу. Все переменные и их содержимое теряются. Это командная кнопка, которую обычно следует выбирать после прерывания бесконечного цикла.
	Debug. Активизирует VBA-режим Break (режим прерывания), чтобы вы могли проверить содержимое переменных и по шагам пройти выполнение цикла для определения причины зацикливания.
	Help. Активизирует справочную систему VBA для отображения информации о том, почему было прервано выполнение кода. Кнопка Help не очень полезна, если вы прервали выполнение кода нажатием на клавишу Esc или на Ctrl+Break; раздел справки констатирует, что выполнение кода было прекращено в результате нажатия на Esc или Ctrl+Break, и дает инструкции, как ввести режим Break или закончить выполнение кода.
Не следует прерывать VBA во время отображения диалогового окна; необходимо закрыть все окна ввода, окна сообщения или другие до того, как вы прервете процедуру.
В зависимости от конкретного цикла и операторов, которые в нем содержатся, VBA может не реагировать на одно нажатие на Esc или Ctrl+Break. В действительности, обычно необходимо нажимать и удерживать нажатой клавишу Esc для прерывания выполняющейся процедуры. Если вы удерживаете нажатой клавишу Esc, вы можете нечаянно закрыть окно сообщения о runtime-ошибке. В результате этого окно сообщения об ошибке может промелькнуть на экране слишком быстро, и вы не сможете его прочитать. Если такое случится, не стоит беспокоиться, вы можете понять, какой цикл был заблокирован, зная, насколько была выполнена процедура перед сбоем.
Рис. 11.4
VBA отображает это окно, когда вы нажимаете Esc или Ctrl+Break для прерывания выполняющейся процедуры (или макроса)
Microsoft Visual Basic
Code execution has been interrupted
Continue j
End
Debug
Help
Повторение действий в Visual Basic: циклы
273
Использование циклов, тестирующих условия до выполнения тела цикла
Для VBA-тестирования условия детерминанта цикла до выполнения тела цикла следует помещать логическое выражение для детерминанта цикла в начало блока операторов, составляющего тело цикла.
*
Циклы Do While
Первой конструкцией цикла, тестирующей свое условие детерминанта до выполнения цикла, является Do While со следующим синтаксисом:
СИНТАКСИС i
Do While Condition Statements
Loop
Condition — логическое выражение для детерминанта цикла; Statements — один, ни одного или несколько операторов, которые составляют тело цикла. Ключевое слово Loop после Statements указывает на окончание тела цикла и обозначает место, из которого VBA возвращается в начало цикла для проверки условия детерминанта (см. диаграмму ниже).
В операторе Do While выражение Condition находится в начале цикла, поэтому VBA проверяет условие детерминанта до выполнения цикла. Поскольку в этой форме используется ключевое слово While, VBA выполняет цикл, пока логическое выражение, представленное с помощью Condition, равно True.
При выполнении цикла Do While VBA сначала тестирует логическое выраже-' нйе, представленное с помощью Condition; если оно равно True, VBA выполняет операторы, представленные с помощью Statements. При достижении ключевого слова Loop VBA возвращается в начало цикла и снова проверяет, равно ли True логическое выражение Condition. Если Condition равно True, VBA выполняет цикл снова; если выражение Condition равно False, VBA продолжает выполнение кода с любых операторов после ключевого слова Loop, т.е. прекращает работу цикла.
Заметьте, что если логическое выражение, представленное с помощью Condition, равно False, когда VBA выполняет оператор Do While в первый раз, VBA просто пропускает цикл, не выполняя его ни одного раза. Т.е. цикл Do While позволяет ни разу не выполнять операторы внутри него.
В листинге 11.6 показан простой пример цикла Do While, который неоднократно получает некоторое число от пользователя, останавливаясь только после того, как пользователь введет столько нечетных чисел, что их сумма превысит число 100.
1
274
Глава 11
Л	Листинг 11.6. Демонстрация цикла Do While
1	Sub Test_DoWhile()
2	' считает нечетные числа, вводимые пользователем;
3	' запоминает строку с нечетными числами;
4	1 останавливается, когда их сумма нечетных чисел превысит 100;
5	' выводит строку с нечетными числами в диалоговом окне
6	*
7	Const ocTitle - "Сумматор нечетных чисел" 8
9	Dim OddSum	As	Integer	'	сумма нечетных чисел
10	Dim OddStr	As	String	'	строка с нечетными числами
11	Dim Num	’	для приема данных пользователя
12	о
13	OddStr = ""	'	инициализация выходной строки
14	OddSum = 0	’	инициализация суммы OddSum
15
16	Do While OddSum < 100	' начало цикла
17	Num = InputBox("Введите число:", ocTitle)
18	If (Num Mod 2) <> 0 Then ' проверка на четность
19	OddSum = OddSum + Num ' изменение суммы OddSum
20	OddStr = OddStr & Num & " "
21	End If
22	Loop
23
24	' вывод строки с нечетными числами:
25	MsgBox prompt:“"Вы ввели следующие нечетные " & _
26	"числа: " & Chr(13) & OddStr, _
27	Title:=ocTitle
28	End Sub
Процедура Test_DoWhile демонстрирует использование цикла Do While. Цикл в процедуре выполняется, пока сумма введенных пользователем нечетных чисел (нечетное (odd) число — это число, которое нельзя разделить на 2 без остатка) меньше 100. Очевидно, что эту задачу нельзя выполнить с помощью цикла For...Next (без дополнительного использования условного оператора). Заметьте, что переменная OddSum, которая входит в условие детерминанта, изменяется только, когда пользователь вводит нечетное число. Поэтому цикл Do While в этой процедуре всегда будет выполняться различное количество раз: все зависит от пользовательского ввода.
Если вы не раз запустите эту процедуру, то, вероятно, обратите внимание, что в диалоговом окне ввода, кроме кнопки ОК, находится кнопка Cancel. Чем меньшие нечетные числа вы будете вводить для тестирования процедуры, тем чаще (так как сумма будет расти медленно) будете видеть, эти две кнопки. Когда-нибудь вы поддадитесь соблазну нажать на кнопку Cancel, и увидите, что программа прекратит работу с выдачей окна runtime-ошибки. Это обстоятельство не является таким уж неожиданным: программа рассчитана на «правильного» пользователя, который дол-, жен вводить четные и нечетные числа и не «капризничать». Конечно, если бы мы могли убрать из диалогового окна кнопку Cancel, то все проблемы были бы решены.
Выход из этой ситуации может быть один — проверять, не была ли нажата кнопка Cancel во время ввода чисел. В листинге 11.7 содержится код, который учитывает возможность отказа от ввода данных.
Листинг 11.7. Демонстрация цикла Do While 1 2 3 4
1 Sub Test_DoWhile2()
2 ' считает нечетные числа, вводимые пользователем;
3 ' запоминает строку с нечетными числами;
4 ' останавливается, когда их сумма нечетных чисел превысит число,
Повторение действий в Visual Basic: циклы
275
5	' вводимое в диалоговом окне первым;
6	' выводит строку с нечетными числами в диалоговом окне
7
8	Const ocTitle = "Сумматор нечетных чисел"
9
10	Dim	Limit	'	предел суммы нечетных чисел
11	Dim	OddSum	As	Integer	'	сумма нечетных чисел
12	Dim	OddStr	As	String	'	строка с нечетными числами
13	Dim	Num	'	для приема данных пользователя
14
15	OddStr = ""	' инициализация выходной строки
16	OddSum = 0	' инициализация суммы OddSum
17
18	Limit = InputBox("Введите максимальную сумму:", ocTitle)
19	If Len(Limit) = 0 Then Exit Sub
20
21	Do While OddSum < Limit ' начало цикла
22	Num = InputBox("Введите число:", ocTitle)
23	If Len(Num) = 0 Then Exit Do
24	If (Num Mod 2) <> 0 Then ' проверка на четность
25	OddSum = OddSum + Num ' изменение суммы OddSum
26	OddStr = OddStr & Num & " "
27	End If
28	Loop
29
30	' вывод строки с нечетными числами:
31	MsgBox prompt:="Вы ввели следующие нечетные " & _
32	"числа: " & Chr(13) & OddStr, _
33	Title:=ocTitle
34	End Sub
Программа Test_DoWhile2 немного продвинута относительно своей предшественницы. Во-первых, она позволяет вводить в диалоге предел суммы нечетных чисел, после которого происходит выход из цикла (строка 18), во-вторых, в окне ввода можно использовать все (две) кнопки, так как операторы в строках 19 и 23 проверяют, не была ли нажата кнопка Cancel, и в первом случае (строка 19) прекращают выполнение процедуры, а во втором (строка 23) — цикла Do While.
Во всяком случае, если вы пишете тестовый код не для себя, следует учитывать даже такие мелочи. Иначе пользователей ваших тестов будут больше занимать проблемы неработоспособности кода, чем его алгоритмическая сущность.
Циклы Do Until
Вариант Do While оператора Do — это один из способов создания оператора Do, тестирующего условие детерминанта до выполнения тела цикла. Можно также использовать форму Do Until оператора Do для создания цикла, тестирующего условие детерминанта до выполнения тела цикла.
Оператор Do Until имеет следующий общий синтаксис:
СИНТАКСИС
Do Until Condition Statements
Loop
Condition — логическое выражение для детерминанта цикла, a Statements — это операторы VBA, составляющие тело цикла. Ключевое слово Loop после Statements указывает на конец тела цикла и также обозначает место, из которого VBA возвращается в начало цикла для проверки условия детерминанта (см. диаграмму синтаксиса цикла Do While).
276
Глава 11
VBA тестирует условие детерминанта цикла Do Until до выполнения операторов цикла. Поскольку эта форма включает ключевое слово Until, VBA выполняет цикл пока логическое выражение, представленное выражением Condition, равно значению False.
При выполнении цикла Do Until VBA сначала тестирует логическое выражение, представленное с помощью Condition; если оно равно False, VBA выполняет операторы, представленные с помощью Statements. После достижения ключевого слова Loop VBA возвращается в начало цикла и снова проверяет, равно ли логическое выражение Condition значению False. Если Condition равно False, VBA выполняет цикл снова; если же оно равно True, VBA продолжает выполнение кода с операторов после ключевого слова Loop, т.е. прекращает работу цикла.
Если Condition равно True, когда VBA встречает оператор Do Until в первый раз, VBA пропускает цикл без его выполнения. Т.е. цикл Do Until позволяет ни разу не выполнять операторы внутри него.
В листинге 11.8 показан простой пример цикла Do Until, который неоднократно получает число от пользователя, прекращаясь, когда пользователь вводит четное число, большее 10.
Листинг 11.8. Демонстрация цикла Do Until
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Sub Test_DoUntil() ' принимает от пользователя числа, пока не будет ' введено четное число, большее десяти
Const evTitle = "Останов при четном, большем десяти"
Dim EvenFlag As Boolean Dim Num
EvenFlag = False Do Until EvenFlag Num = InputBox("Введите число:", evTitle) If Len(Num) = 0 Or TypeName(Num) <> "Integer" Then Exit Do If ((Num Mod 2) = 0) Then If Num > 10 Then
MsgBox prompt:="Вы ввели четное число, " & "большее, чем 10 - Цикл заканчивается", _ Title:=evTitle
EvenFlag = True Else
MsgBox prompt:="Вы ввели четное число, " & "меньшее, чем (или равное) 10", _ Title:=evTitle	,,
End If Else
MsgBox prompt:="Bbi ввели нечетное число", _ Title:=evTitle End If Loop
MsgBox prompt:^"Выполнение цикла прекращено", Title:=evTitle End Sub
Процедура Test_DoUntil показывает, как построить цикл Do Until. Цикл в этой процедуре демонстрирует управляемый условием цикл и выполняется до тех пор, пока пользователь не введет четное число, большее 10. Условие, заканчивающее выполнение цикла — это ввод пользователем четного числа. На самом деле этим условием является получение значения True переменной EvenFlag, что про-
Повторение действий в Visual Basic: циклы
277
исходит (в строке 19), когда код обнаруживает с помощью вложенных операторов If (в строках 14-15) факт введения пользователем четного числа, большего 10.
Перед выполнением цикла переменной EvenFlag присваивается значение False, чем и обеспечивается, по крайней мере, первое выполнение цикла. Внутри цикла организуется прием числа, и анализ его на предмет четности и превышения 10. Если эти последние проверки дают положительный результат, выводится сообщение (строки 16-17) об окончании цикла и переменная EvenFlag получает значение True, что приводит к окончанию цикла.
В строке 13 находится оператор, предупреждающий возникновение runtime-ошибок при работе с программой пользователей, склонных к экспериментам.
Использование циклов, тестирующих условия после выполнения тела цикла
Для VBA-тестирования условий после выполнения тела цикла необходимо поместить логическое выражение для детерминанта цикла в конец блока операторов, составляющих тело цикла, после ключевого слова Loop, которое сообщает о конце цикла.
Циклы Do...Loop While
Первая рассматриваемая нами конструкция цикла, тестирующая условие детерминанта после выполнения тела цикла, — это Do...Loop While.
Оператор Do...Loop While имеет следующий синтаксис:
СИНТАКСИС
Do
Statements
Loop While Condition
Statements — один, ни одного или несколько операторов VBA, составляющих тело цикла. Ключевое слово Loop после Statements обозначает конец тела цикла и также указывает место, из которого VBA возвращается в начало цикла; Condition представляет логическое выражение для детерминанта цикла (см. диаграмму ниже).
В этой форме синтаксиса оператора Do...Loop While VBA проверяет условие детерминанта после выполнения операторов цикла. Поскольку эта форма оператора Do использует ключевое слово While, VBA выполняет цикл, пока логическое выражение, представленное с помощью Condition, равно True.
278
Глава 11
При выполнении оператора Do...Loop While VBA сначала выполняет операторы, представленные с помощью Statements. Когда VBA достигает ключевых слов Loop While, выполняется тестирование логического выражения, представленного с помощью Condition; если это выражение равно True, VBA возвращается в начало цикла и снова выполняет тело цикла. Когда VBA снова достигает ключевых слов Loop While в конце цикла, снова выполняется проверка, является ли логическое выражение Condition все еще равным True. Если Condition равно True, VBA выполняет цикл снова; если — нет, VBA продолжает выполнение кода с любых операторов после строки, содержащей ключевое слово Loop, т.е. прекращает работу цикла.
Заметьте, что независимо от значения логического выражения, представленного с помощью Condition, этот цикл всегда выполняется, по крайней мере, один раз. (Сравните с циклами, проверяющими условие детерминанта до выполнения тела цикла.)
Процедура Test_DoLoopWhile в листинге 11.9 использует конструкцию цикла Do...Loop While для получения в диалоговом окне данных от пользователя до тех пор, пока пользователь не введет слово "exit", указывая на то, что ввод данных завершен.
Листинг 11.9. Пример использования структуры Do...Loop While
1	Sub Test_DoLoopWhile()
2	1 демонстрирует структуру Do...Loop While.
3	' Цикл повторяется, пока не будет введено слово "exit"
4
5	Const iTitle = "Ввод данных"
6	Dim uStr As String
7
8	Do
9	uStr = InputBox(prompt:="Введите строку " & _
10	"('exit' для окончания):",	_
11	Title:=ilitle,
12	Default:="exit")
13	' операторы обработки или проверки вводимых данных
14	' или сохранения данных в ячейках рабочего листа и т.д.
15	MsgBox prompt:="Bbi ввели: " & uStr, Title:=iTitle
16	Loop While uStr <> "exit"
17
18	MsgBox prompt:="Ввод данных завершен.", _
19	Title:=iTitle, buttons:=vbExclamation
20	End Sub
По-видимому, комментировать здесь нечего. К моменту рассмотрения этого листинга вы должны иметь знания, достаточные для того, чтобы понять представленный код.
Циклы Do...Loop Until
Для построения Do-цикла, тестирующего свое условие детерминанта после выполнения тела цикла можно также использовать форму Do...Loop Until оператора Do.
Оператор Do...Loop Until имеет следующий синтаксис:
СИНТАКСИС
Do
Statements	'	‘
Loop Until Condition
Statements представляет операторы VBA, составляющие тело цикла; Condition — логическое выражение для детерминанта цикла (см. диаграмму синтаксиса цикла Do...Loop While).
Повторение действий в Visual Basic: циклы
279
VBA проверяет условие детерминанта цикла Do...Loop Until после выполнения тела цикла. Поскольку эта форма Do-оператора использует ключевое слово Until, VBA выполняет цикл, пока логическое выражение, представленное с помощью Condition, равно False.
При выполнении оператора Do...Loop Until VBA сначала выполняет операторы, представленные с помощью Statements. Когда VBA достигает ключевого слова Loop, выполняется тестирование логического выражения, представленного с помощью Condition", если логическое выражение равно False, VBA возвращается в начало цикла и снова выполняет тело цикла. Когда VBA снова достигает ключевого слова Loop в конце цикла, снова выполняется проверка, является ли логическое выражение Condition равным False. Если Condition равно False, VBA выполняет цикл снова; если оно равно True, VBA продолжает выполнение кода с любых операторов после строки, содержащей ключевое слово Loop, т.е. прекращает работу цикла.
Заметьте, что этот цикл всегда выполняется, по крайней мере, один раз, независимо от значения логического выражения, представленного с помощью Condition. (Сравните с циклами, проверяющими условие детерминанта до выполнения тела цикла.)
Процедура Test_DoLoopWhile в листинге 11.10 использует конструкцию цикла Do...Loop While для получения данных ввода от пользователя до тех пор, пока пользователь не введет слово "exit", указывая на то, что ввод данных завершен.
	Листинг 11.10. Пример использования структуры Do...Loop Until
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20	Sub Test_DoLoopUntil() ' демонстрирует структуру Do...Loop Until. ' Цикл повторяется, пока не будет введено слово "exit" Const iTitle = "Ввод данных" Dim uStr As String Do uStr - InputBox(prompt:“"Введите строку " & _ "('exit' для окончания):", _ Title:“iTitle, _ Default:“"exit") ' операторы обработки или проверки вводимых данных ' или сохранения данных в ячейках рабочего листа и т.д. MsgBox prompt:="BH ввели: " & uStr, Title:=iTitle Loop Until uStr = "exit" MsgBox prompt:="Ввод данных завершен.", _ Title:“iTitle, buttons:=vbExclamation End Sub
Код этого листинга практически ни чем не отличается от кода предыдущего листинга, кроме того, что здесь используется структура Do...Loop Until, а не Do...Loop While (строка 16).
Вложенные циклы
Можно помещать циклы внутрь других циклов, аналогично тому, как можно помещать операторы If ...Then один в другой. Помещение одной структуры цикла в другую называют вложением (nesting) циклов. Можно помещать структуры циклов любого типа (смешанные For и Do циклы) в любой уровень.
280
Глава 11
При вложении циклов необходимо соблюдать следующие правила:
	При вложении циклов For...Next каждый цикл должен иметь свою уникальную переменную счетчика.
	При вложении циклов For Each...Next каждый цикл должен иметь свою уникальную е/етеп<-переменную.
	Если вы используете оператор Exit For или Exit Do во вложенном цикле, этим оператором заканчивается только выполняемый в данный момент цикл; VBA продолжает выполнение следующего цикла более высокого уровня.
Вложение циклов For
В листинге 11.11 показана простая процедура, которая использует вложенные циклы For ...Next. Процедура Test_ForNext предназначена для использования в Excel и применяет полужирный шрифт к первым п (вводится пользователем) строкам первых m (вводится пользователем) столбцов активного в данный момент рабочего листа. Внешний цикл в процедуре считает строки, а внутренний — столбцы.
Листинг 11.11. Вложенные циклы For...Next
1	Sub	Test ForNext()
2 3	' Применяет шрифт Arial, полужирный ' к первым п строкам и m столбцам активной рабочей книги	
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38	End	Dim sTitle As String Dim Rnum As Integer, Cnum As Integer Dim n As Integer, m As Integer sTitle = "Форматирование ячеек листа" n = Application.InputBox(prompt:“"Введите число строк", _ Title:“"Форматирование ячеек", Туре:=1) If п = 0 Then Exit Sub m - Application.InputBox(prompt:“"Введите число столбцов", Title-.“"Форматирование ячеек", Туре:=1) If m = 0 Then Exit Sub Worksheets("Sheetl").Activate For Rnum = 1 To n For Cnum = 1 To m Cells(Rnum, Cnum).Select * With Selection.Font	’ .Name = "Arial" .Fontstyle = "Bold" .Strikethrough = False .Superscript “ False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlNone	» .Colorindex = xlAutomatic End With Next Cnum Next Rnum	, Sub
Повторение действий в Visual Basic: циклы
281
Процедура Test_ForNext использует циклы For ...Next, один, вложенный в другой, для применения полужирного шрифта Arial к ячейкам листа, начиная с первой и заканчивая в строке п и столбце ш. Значения пит вводятся в строках 10-11, 14-15 при помощи метода Application.InputBox, который, как уже отмечалось, позволяет сократить проверочный код пользователя использованием необязательного аргумента Туре. При значении Туре, равном 1, пользователь не сможет ввести в окне ввода ничего, кроме числа. Вы можете сами в этом убедиться. Набор чего-либо, не похожего на число, приведет к выдаче окна сообщения, подобного приведенному на рис. 11.5. Кроме контроля За вводом, в процедуре проверяется, не введены ли нулевые или отрицательные значения для пит (строки 12, 16). Работа процедуры продолжается только при введении положительных значений этих переменных.
Рис. 11.5
Excel-метод Application.InputBox не позволяет вводить ничего, кроме того, что определено его необязательным аргументом Туре
Счетчик внешнего цикла For...Next изменяется от 1 до п, и процедура использует переменную счетчика внешнего цикла для предоставления координат строки каждый раз при выполнении цикла. Следовательно, внешний цикл обрабатывает п строк от начала рабочего листа.
Счетчик внутреннего цикла For...Next изменяется от 1 до т, и процедура использует переменную счетчика внутреннего цикла для предоставления координат столбца каждый раз при выполнении цикла. Следовательно, внутренний цикл обрабатывает в рабочем листе m столбцов слева направо.
В строке 22 используется метод Cells объекта Application Excel для возвращения объекта Range, определенного с использованием Rnum и Спит в качестве координат строки и столбца. Оператор использует также метод Select объекта Range для выбора заданной ячейки в активном рабочем листе. Оператор Cells был скопирован из записанного рекордером макроса, который содержал только два действия: выбор ячейки и применение нужного форматирования. Оператор выбора ячейки был скопирован в эту процедуру, а литеральные значения из записанного рекордером оператора были заменены переменными Rnum и Спит.
В строках 24-34 расположен оператор With, используемый для текущего выделенного фрагмента (ячейки). Объект Selection.Font содержит все установки шрифта для текущего выбора. Операторы внутри With (в строках 25-33) изменяют свойства объекта Selection.Font так, чтобы выбор имел нужный полужирный шрифт Arial. Эти операторы были также скопированы из записанного рекордером макроса.
Вложенные циклы Do
В листинге 11.9 показана процедура, использующая вложенные циклы Do, чтобы пользователь мог выполнить ввод данных, необходимых для получения накладной. Внешний цикл в процедуре Makelnv получает номера накладных от пользователя до тех пор, пока пользователь не отменит окно ввода. Внутренний цикл в процедуре Makelnv получает элементы записей накладной до тех пор, пока пользователь не отменит окно ввода. Когда вы будете изучать эту процедуру, помните, что
282
Глава 11
это просто эскизная процедура. На самом деле вам, вероятно, потребуется получить гораздо больше информации, чем используется здесь. Вам, конечно, предстоит также самим писать код для занесения вводимой информации в какие-либо хранилища данных. (Листинг 11.12 будет выполняться и в Excel, и в Word).
Листинг 11.12. Вложенные циклы Do
1	Sub Makelnv()
2	' обеспечивает ввод данных для накладных и элементы
3	' записей для каждой накладной. Внешний цикл получает
4	' информацию об отдельной накладной, внутренний -
5	' о записях этой накладной (наименование и количество
6 ' товара)
7
8 Const miTitle = ""
9
10 Dim InvcNum As String * 5	1 номер накладной
11	Dim	ItemNuml	As	String *	16
12	Dim	ItemNum2	As	String *	16
13	Dim	ItemDone	As	Boolean	
14	Dim	InvcDone	As	Boolean	
15 Dim pos As Integer
16
17
18 InvcDone = False
19 Do Until False
20	InvcNum = InputBox(prompt:="Введите номер накладной:",
21	Title:=miTitle)
22	If Trim(InvcNum) = "" Then
23	MsgBox prompt:="0тмена ввода накладной.", _
24	Title:="Ввод накладных", Buttons:=vbExclamation
25	Exit Do
26
27
28
29
30
31
32
33
34
35
36
37
38 39'
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
End If
pos = 1
Do Until False ' цикл для получения элемента строки
' Ввод наименования товара
ItemNuml = InputBox(prompt:= _
"Введите наименование товара", _
Title:="Накладная №" & InvcNum & "Позиция N’" & pos) If Trim(ItemNuml) = "" Then
MsgBox prompt:="Ввод позиций для накладной №" & _
InvcNum & " завершен.", _
Title:=miTitle
Exit Do
End If	,	\
1 ввод количества товара
ItemNum? = InputBox(prompt:= _
"Введите количество товара", _
Title:“"Накладная №" & InvcNum & "Позиция N‘" & pos)
If Trim(ItemNum2) = "" Then
MsgBox prompt:="Ввод позиций для накладной №" & _
InvcNum & " завершен.", _
Title:=miTitle
Exit Do
End If
’ операторы для сохранения вводимых данных, получения
' большей информации об элементе записи и т.д.
MsgBox prompt:“"Введенный элемент N’" & pos & " " &
Повторение действий в Visual Basic: циклы
283
56	ItemNuml & " кол-во " & ItemNum2 & _
57	" в накладной №" & InvcNum, _
58	Title:“"Контрольная выдача "
59
60	роз - роз + 1
61	Loop
62	Loop
63
64	MsgBox prompt:="Ввод накладной завершен", Title:=miTitle
65	End Sub
Процедура Makelnv демонстрирует применение вложенных Do-циклов на примере имитации ввода накладных. В процедуре использованы бесконечные циклы (строки 19, 29), выход из которых осуществляется оператором Exit Do (строки 25, 50). Накладная имеет номер и записи, включающие наименование товара и количество.
Номера накладных вводятся во внешнем цикле (начинается в строке 19). Сразу после ввода накладной производится проверка необходимости выхода из цикла (строки 22-26). Если пользователь не ввел номер или нажал кнопку Cancel, внешний цикл прекращается с предварительным сообщением об отмене ввода накладной (строки 23-24 ).
Перед началом выполнения внутреннего цикла переменной pos (счетчик количества позиций в накладной) присваивается значение 1 (строка 28). В конце внутреннего цикла (строка 60) значение счетчика увеличивается на единицу. В теле внутреннего цикла вводятся наименования (строки 32-34) и количества (строки 43-45) товаров. После ввода каждого из этих элементов производится проверка ввода (строки 35-40, 46-50), после которой выполнение внутреннего цикла может быть завершено операторами Exit Do (строки 39, 50). Если наименование и количество товаров введены успешно, в конце внутреннего цикла (строки 55-58) производится контрольная выдача введенных данных на экран.
Вот и все, что можно было рассказать в рамках этой главы о циклах, применяемых в VBA для выполнения различных повторяющихся действий.
Гя@зо 12
Массивы
В этой главе описываются массивы. Массивы являются распространенным и полезным способом сохранения многих различных частей связанных данных. Массивы полезны при создании отсортированных и неотсортированных списков данных, при сохранении таблиц данных и для выполнения многих других задач. Информация, сохраненная в массиве, может быть доступна в любом порядке.
Массив (array) — это коллекция переменных, которые имеют общие имя и базовый тип. Массив является удобным способом хранения нескольких связанных элементов данных в едином контейнере для большего удобства и эффективности программирования. Все элементы данных, сохраняемых в массиве, должны иметь один и тот же тип; например, при создании массива для сохранения типов Integer (Double, String, Currency и т.д.) все элементы данных, сохраненных в этом массиве, должны быть числами Integer (Double, String, Currency и т.д.).
Массив позволяет сохранять и манипулировать многими элементами данных посредством единственной переменной. Кроме уменьшения общего числа различных имен переменных, которые необходимо отслеживать, другим основным преимуществом использования массивов является то, что можно использовать циклы для легкой обработки различных элементов массивов. Объединяя массивы и структуры цикла (обычно For ...Next или For ...Each), можно написать небольшое число операторов, которые обрабатывают большой объем данных. Выполнение тех же задач с использованием отдельных переменных может потребовать написания сотен операторов.
Размерность массива
В языках программирования обычно используются одномерные и многомерные массивы, одни из которых описывают относительно простые, а другие — более сложные объекты.
Одномерные массивы
Наименее сложный массив — это просто список элементов данных; такого рода массив называется простым (simple) или одномерным (single-dimensional) массивом. Такой массив можно представить в виде таблицы (рис. 12.1). Каждый элемент данных, хранимых в массиве, называется элементом (element) массива. Массив на рис. 12.1 имеет 8 элементов; каждый элемент сохраняет число типа Double. Заметьте, что элементы в массиве пронумерованы от 0 до 7, что составляет 8 элементов. Такая система нумерации довольно распространена в программировании и называется нумерацией с нулевой базой (zero-based).
Для доступа к данным, хранящимся в определенном элементе массива, следует указывать имя массива с последующим числом, называемым индексом (subscript или index) элемента. Индекс всегда заключается в круглые скобки. Например, если массив на рис. 12.1 имеет имя DoubleArray, то следующий оператор присваивает число 0.11 переменной Double Any:
DoubleAny = DoubleArray (6)
В этом операторе число 6 является индексом массива; заметьте, что он заключен в круглые скобки и не отделяется пробелами от имени массива. Поскольку ну
Массивы
285
мерация элементов начинается с нуля, элемент, на который ссылается этот оператор, является, фактически, седьмым элементом массива DoubleArray.
10.2	11.2	22.1	1.1	21.3	123.0	0.11	1.1
0-й	1-й	2-й	3-й	4-й	5-й	6-й	7-й
элемент	элемент	элемент	элемент	элемент	элемент	элемент	элемент
Рис. 12.1. Одномерный числовой массив; одномерные массивы - это, в основном, просто списки данных одного и того же типа
Посмотрите снова на рис. 12.1 и обратите внимание, что элемент массива с номером 6 содержит значение 0.11. При выполнении приведенного выше оператора VBA выбирает значение 0.11 из указанного элемента массива и сохраняет это значение в переменной DoubleAny — точно так же, как в любом другом присваивании переменной.
Можно также использовать индекс всякий раз, когда необходимо сохранить данные в отдельном элементе массива. Например, следующий оператор сохраняет число 12.3 в восьмом элементе массива, показанном на рис. 12.1:
DoubleArray (7) =12.3
При выполнении этого оператора VBA помещает значение 12.3 в указанный элемент массива, заменяя предыдущее содержимое этого элемента — точно так же, как в любом другом присваивании переменной. Можно использовать элемент массива в любом выражении VBA — точно так же, как используется значение константы или переменной в каком-либо выражении.
Одномерные массивы обычно используются для представления различных списков данных.
Многомерные массивы
Одномерные массивы хорошо подходят для представления простых списков данных. Однако часто бывает необходимо представить таблицы данных в программах с организацией данных в формате строк и столбцов, подобно ячейкам в рабочих листах Excel. Для этого необходимо использовать многомерные (multi-dimensional) массивы. Поскольку вы уже имеете опыт работы с ячейками Excel, то нет необходимости в подробном разъяснении сущности двумерного массива. Адрес каждой ячейки листа состоит из двух чисел (измерений), одно из которых (номер строки) является первым индексом, а второе (номер столбца) — вторым индексом массива. На примере организации листов Excel можно представить и трехмерные массивы. Здесь третьим индексом массива может быть номер листа.
В VBA можно также создавать массивы, имеющие более трех измерений; фактически, VBA позволяет создавать массивы, имеющие до 60 измерений. Работа с массивами, имеющими 4 или более измерений, быстро становится запутанной; к счастью, вам, вероятно, не придется работать с такими массивами. Чаще всего в программировании используются одно- и двумерные массивы.
Статические и динамические массивы
В следующем разделе вы узнаете, что число элементов в массиве обычно задается во время объявления массива. Объявление массива указывает VBA величину различных измерений массива (диапазон изменения каждого индекса). После того как массив объявлен, VBA выделяет достаточный объем памяти для всех элементов массива. Например, для массива на рис. 12.1 VBA выделит объем памяти, достаточный для 8 чисел типа Double.

I лава *Q
Переменные типа массив подчиняются тем же правилам области действия, что и любые другие переменные.
VBA сохраняет зарезервированной область памяти для всех элементов в массиве, пока существует переменная типа массив. Подобные массивы называются статическими (static), потому что число элементов в массиве не меняется.
Выбор размера массива может быть затруднен, если неизвестно, сколько данных будет введено в массив, или если объем данных, собираемых для массива, значительно меняется. Если вам иногда приходится сохранять 100 значений, а иногда — только 10 значений, то потенциально напрасно расходуется область памяти, необходимая для сохранения 90 значений.
Для подобных ситуаций VBA поддерживает особый тип массивов, называемый динамическим (dynamic) массивом. Динамические массивы получили свое название, потому что можно изменять число элементов в массиве при выполнении VBA-программы. Динамический массив (в сочетании с правильным программированием) может увеличиваться или сжиматься (уменьшаться в размере), чтобы вмещать точно необходимое число элементов без напрасного расходования памяти. Для изменения размера динамического массива используйте оператор ReDim, описываемый далее в этой главе.
Оператор Option Base
Обычно в VBA используются массивы с нулевой базой. В системе нумерации с нулевой базой индекс для первого элемента в любом измерении массива является равным 0; массив с 10 элементами имеет индексы от 0 до 9. Очевидно, что система нумерации с нулевой базой может быть непонятной, потому что индекс 0, в действительности, обозначает 1-й элемент массива, индекс 5 обозначает 6-й элемент массива и так далее.
Было бы гораздо удобнее, если бы элементы массива нумеровались, начиная с 1, а не с 0. Если бы нумерация элементов начиналась с 1, то индекс 1 обозначал бы 1-й элемент массива, индекс 5 — 5-ый и так далее.
VBA позволяет задавать начальное число для элементов массива. Можно задавать нижнее число для индексов массива при объявлении массива (описывается далее в этой главе), или использовать директиву компилятора Option Base для указания того, должна ли нумерация индексов начинаться с 0 или с 1.
Директива компилятора Option Base имеет следующий синтаксис:
СИНТАКСИС
Option Base 0 | 1
Оператор Option Base позволяет задавать 0 или 1 как начальное число по умолчанию для индексов массива. Если оператор Option Base не используется, VBA начинает нумерацию индексов массива с 0 (по умолчанию). Необходимо помещать оператор Option Base в область объявлений модуля перед объявлениями любых переменных, констант или процедур. Нельзя помещать оператор Option Base внутри процедуры. Можно иметь только один оператор Option Base в модуле. Оператор Option Base влияет на все массивы, объявляемые в модуле, независимо от того, являются ли они локальными в процедуре или объявляются 'на модульном уровне.
Следующие два оператора являются примерами директивы компилятора Option Base:
Option Base 0	1 установка по умолчанию
Option Base 1	1 индексы массивов начинаются с 1
Массивы
287
Объявление массивов
Вы уже знакомы с оператором Dim, используемым для объявления переменных. Этот же оператор используется и для объявления массивов. В действительности, ключевое слово Dim является сокращением слова dimension (измерение). В оригинальном языке программирования BASIC ключевое слово Dim использовалось исключительно для изменения размеров массивов (dimensioning), отсюда и сокращение Dim. Однако современный язык VBA расширил использование ключевого слова Dim до использования со всеми переменными. С помощью Dim можно объявлять как одномерные, так и многомерные массивы.
Объявление массива с помощью оператора Dim имеет следующий синтаксис:
СИНТАКСИС
Dim VarName ( [Subscripts'] ) [As Туре]	'
VarName — любое имя для массива, удовлетворяющее VBA-правилам для имен идентификаторов. Subscripts — измерение (измерения) массива. Можно объявлять массивы, имеющие до 60 измерений. Для одномерного массива включается один Subscripts-, для двумерного массива — два (отделенные друг от друга запятой) и так далее. Каждый Subscripts добавляет новое измерение в массив.
Можно также объявлять статические и динамические массивы, используя ключевые слова Public, Private и Static — точно так же, как для любой другой переменной и с тем же влиянием на область действия. Используйте показанный здесь синтаксис объявления массива и просто подставляйте ключевое слово Public, Private или Static вместо ключевого слова Dim, если необходимо.
Оператор Subscripts имеет следующий синтаксис:
СИНТАКСИС
[lower То] upper [,[lower То] upper]...
Здесь lower определяет нижний диапазон допустимых индексов для массива; upper — верхний предел. Заметьте, что только верхний предел является обязательным; часть lower То оператора Subscripts является необязательной. При определении только предела upper VBA нумерует элементы массива в зависимости от установки Option Base. Если действует установка Option Base 1, VBA нумерует элементы в массиве от 1 до upper, иначе — от 0 до upper.
Включение части lower То оператора Subscripts помогает сделать код более легким и понятным, а также выявить ошибки программирования. Это также позволяет определять иной начальный индекс для массива, чем 0 или 1. Например, можно создать массив с элементами, имеющими номера от 5 до 10 или от -5 до 0, в зависимости от конкретной выполняемой задачи.
Подобно обычным объявлениям переменных, можно объявлять определенный тип данных для массива, включая в объявление оператор As type. При этом type представляет любой допустимый тип VBA — Currency, Double, String и так далее. Можно также объявлять массивы, имеющие определенный пользователем тип (создание пользовательских типов в книге не рассматривается). Если опустить type, все элементы в массиве имеют тип Variant. VBA инициализирует элементы числовых массивов нулями и элементы строковых массивов пустыми строками.
Заметьте, что оператор Subscripts является необязательным. Для создания динамического массива не используйте оператор Subscripts (необходимо включать круглые скобки в объявление массива, независимо от того, определяется ли Subscripts).
288
Глава 12
Следующие примеры являются допустимыми объявлениями массива:
Dim strarray(l То 100) As String
Dim variant_array()
Dim str_Multiplication(0 To 15, 0 To 15) As String
При объявлении массивов следует помнить, что включение оператора Subscripts в объявление массива создает статический массив с фиксированным числом элементов, пропуск оператора Subscripts в объявлении массива создает динамический массив, а установка Option Base может повлиять на общее число элементов в массиве.
Использование массивов
После объявления массива использовать его в коде VBA довольно просто. Как уже объяснялось в начале этой главы, для доступа к элементу массива необходимо указать имя массива, за которым следует значение индекса, заключенное в круглые скобки.
Обращение к элементу массива имеет следующий синтаксис:
СИНТАКСИС
arrayName(validlndexl, [validlndex2]...)
Здесь arrayName — имя массива; validlndexl — допустимое значение индекса для первого измерения массива; validlndex2 — допустимое значение индекса для второго измерения массива, если таковое имеется. Необходимо предоставлять значение индекса для каждого измерения массива при каждом обращении к какому-либо элементу в массиве.
Например, для двумерного массива необходимо всегда определять два индекса. Допустимым индексом является любая переменная VBA или выражение, имеющее результатом целое число в диапазоне объявленных измерений массива. Например, допустимым значением индекса для одномерного массива, объявленного с индексами 1-10, может быть любое выражение VBA, имеющее результатом целое число в диапазоне от 1 до 10. Использование меньшего или большего индекса, чем диапазон для определенного измерения в массиве, приводит к тому, что VBA отображает runtime-ошибку.
Следующий фрагмент кода показывает типичное объявление и использование массива.
. Dim Factorial(0 То 30) As Double ' объявление массива из 31 элемента
Factorial(0) = 1	' инициализировать 1-й элемент
For i = 1 То 30	' начало цикла для работы с массивом
Factorial(i) = i* Factorial(i - 1)	' изменить i-й элемент
Next i
Рассмотрим простой пример работы с одномерным массивом, представленный кодом листинга 12.1. Процедура в первом цикле For...Next принимает в диалоговом окне целые числа (для простоты без всякой проверки) и заносит их в элементы массива. Во втором цикле значения элементов массива заносятся в строку и выводятся на экран в диалоговом окне оператора MsgBox.
Листинг 12.1. Работа со статическим одномерным массивом
1	Sub DemoStatArray()
2	Dim Int_Array(5) As Integer
3	Dim str_msg As String
4
Массивы
289
5	str_msg = ""
6
7	For i = 1 To 5
8	Int_Array(i) = InputBox("Введите целое число для "
9	& i & "-го элемента массива", _
10	"Ввод элементов массива")
11	Next
12
13	For ] = 1 То 5 *
14	str_msg = str_msg & Int_Array(j) & ", "
15	Next
16
17	MsgBox "Введено: " & str_msg, _
18	, "Вывод ранее введенного массива"
19
20	End Sub
В строке 2 объявляется одномерный массив Int_Array (размерностью 5 элементов) целых чисел Int_Array. Далее (строка 3) объявлена рабочая переменная str_msg для завершающего вывода данных из массива в диалоговом окне (строка 19). В первом цикле For...Next (строки 7-11) в массив Int_Array записываются значения из окна ввода. Обратите внимание, как формируется значение аргумента Prompt функции InputBox. На рис. 12.2 приведен фрагмент ввода 3-го элемента массива.
Рис. 12.2
Фрагмент ввода 3-го элемента массива
Ввод элементов массива
Введите целое число для 3-го элемента массива
ОК
Cancel
В строках 13-15 располагается второй цикл, который формирует строку из значений элементов массива для выдачи ее в диалоговом окне (рис. 12.3).
Рис. 12.3
Результат работы кода листинга 12 1
Процедура DemoStatАггау2 в листинге 12.2 предназначена для демонстрации работы с двумерным массивом.
Листинг 12.2. Работа со статическим двумерным массивом
1	Sub DemoStatArray2()
2	Dim Int_Array(3, 6) As Integer
3	Dim str_msg As String
4
5	str_msg = ""
6
7	For i = 1 To 3
8	For ] = 1 To 6
9	Int_Array(i,j)“InputBox("Введите целое число для "
10 Программирование на VBA 2002
290
Глава 12
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
& " элемента (" & i &	& j &	_
"Ввод элементов массива; строка " & i)
Next j
Next i
For i = 1 To 3
For j = 1 To 6
str_msg = str_msg & Int_Array(i, j) & ", "
Next ]	'
str_msg = str_msg & Chr(13) 'перевод строки Next i
MsgBox "Введено: " 4 Chr(13) & str_msg, _
, "Вывод ранее введенного массива"
26 End Sub
Для инициализации массива используется вложенный цикл в строках 7-13. Обратите внимание на строки 12-13. Здесь, как ранее отмечалось, указывается, по какой переменной заканчивается цикл. Это необязательно, но лучше привыкнуть к такому стилю программирования с самого начала.
В окне ввода теперь для указания, какой элемент вводится в конкретный момент времени, выводятся оба индекса (рис. 12.4). Это уже довольно дружественный интерфейс для ввода двумерного массива: пользователю трудно не догадаться, чего от него добивается программа. Чтобы понять, как это достигается, внимательно проанализируйте оператор в строках 9-11.
Рис. 12.4
Дружественный интерфейс для ввода элемента двумерного массива
• ।
Ввод элементов массива, строка 2
Введите целое число для элемента (2,6)
ОК
Cancel
|26f
Вторая часть процедуры DemoStatArray2 также состоит из вложенных циклов и, как и в предыдущем листинге, эта часть предназначена для выдачи инициализированного массива в окне MsgBox при помощи переменной str_msg. Для осуществления этой задачи во внутреннем цикле (строки 16-18) формируется строка из элементов массива при постоянном первом индексе (переменная i). При этом меняется только второй индекс (переменная j). После заполнения строки, но перед изменением первого индекса к переменной str_msg добавляется символ перехода на другую строку (строка 20).
Результат работы кода листинга 12.2 приведен на рис. 12.5.
Рис. 12.5
В результате работы кода листинга 12.2 инициализирован массив размерностью 3x6
Массивы
291
М Процедуры листингов 12.1 и 12.2 работают при наличии в модуле, где они описаны, директивы компилятора Option Base 1.
Использование ReDim с динамическими массивами
Как упоминалось ранее Н” этой главе, могут сложиться обстоятельства, при которых точно не известно, сколько элементов потребуется в массиве. В VBA имеется возможность переопределять размерность массивов, а во время объявления не указывать размерность. Используя динамический массив, можно создавать массив такой большой или такой маленький, какой необходимо. Динамические массивы создаются с помощью оператора Dim, затем их размер устанавливается с помощью оператора ReDim во время выполнения процедуры.
Оператор ReDim имеет следующий синтаксис:
СИНТАКСИС	а--	 Л-.'W
ReDim [Preserve] varname (subscripts') [As type] [, _ varname(subscripts) [As type]]
Необязательное ключевое слово Preserve, как предполагает его имя, приводит к тому, что VBA сохраняет данные в имеющемся массиве, когда изменяется размер массива с помощью ReDim; varname — имя существующего массива; subscripts — это измерения массива (синтаксис для оператора subscripts в операторе ReDim такой же, как для оператора Dim); type — любой тип VBA или определенный пользователем тип. Необходимо использовать отдельный оператор As type для каждого массива, который вы определяете.
Далее следуют допустимые примеры объявлений динамических массивов и возможные операторы ReDim, используемые с этими динамическими массивами:
Dim aMonth() As String	1	объявляет динамический массив aMonth
ReDim aMonth(l To 30)	’	изменяет размер массива до 30 элементов
ReDim aMonth(31)	'	изменяет размер массива до 31 элемента
ReDim Preserve aMonth(l To	31) ' изменяет размер массива до 31
	' элемента, сохраняя содержимое
Dim Table()As Integer	' объявляет динамический массив
ReDim Table(3, 15)	1 делает массив двумерным
ReDim Table (4, 20)	' изменяет размер двумерного массива
ReDim Preserve Table (4, 25)	' только изменяет последний размер
	' массива
Dim Mas as Variant	' объявляет переменную типа Variant
ReDim Mas(20) As Integer	' создает массив 20 целых в Variant
Предыдущие примеры иллюстрируют некоторые важные моменты, относящиеся к динамическим массивам. Во-первых, можно изменять только последнее измерение многомерного массива, когда используется ключевое слово Preserve. Во-вторых, можно использовать ReDim для создания типизированного массива внутри переменной типа Variant. Поскольку переменные типа Variant могут содержать данные любого типа, можно использовать переменную типа Variant для сохранения динамического массива! (Использование переменной типа Variant для сохранения динамического массива дает возможность изменять размер массива с помощью ReDim и изменять тип данных массива.)
Обычно оператор ReDim используется для изменения размера динамического массива, который уже был объявлен ранее с помощью операторов Dim, Private, Public или Static. Можно использовать оператор ReDim для изменения числа элементов и измерений в динамическом массиве столько раз, сколько необходимо. Однако нельзя использовать оператор ReDim для изменения типа данных массива,
10'
292
Глава 12
если только массив не содержится в переменной типа Variant или сами элементы массива не имеют тип Variant. Если динамический массив сохраняется в переменной типа Variant, можно изменять тип данных, используя оператор As type в операторе ReDim.
Попытка использовать ReDim для статического массива (массив, измерения которого были явно определены в объявлении Dim, Public, Private или Static) приводит к тому, что VBA отображает runtime-ошибку.
Код листинга 12.3 является примером использования динамического одномерного массива и выполняет задачу ввода данных в массив, подобную решаемой в листинге 12.1. Это делается для того, чтобы концентрировать внимание читателя на отличиях использования разных типов массивов, а не деталях различных задач.
Листинг 12.3. Работа с динамическим одномерным массивом
1	Option Base 1
2	Sub DemoDinArray()
3	Dim Int_Array()	As	Integer
4	Dim str_msg As String,	i	As Integer
5	Dim Num
6
7	strmsg = ""
8	i = 0	'
9
10	Do
11	i = i + 1
12	Num = InputBox("Введите целое число для " _
13	& i & "-го элемента массива", _
14	"Ввод элементов массива")
15	If Len(Num) = 0 Then Exit Do ’ выход из цикла
16
17	1 изменение размера массива
18	' с сохранением элементов
19	ReDim Preserve Int_Array(i)
2°
21	' ввод данных в i-й элемент массива
22	Int_Array(i) = Num
23	Loop
24
25	For j = 1 To i - 1
26	str_msg = str_msg & Int_Array(j) & ", "
27	Next
28
29	MsgBox "Введено: " & str_msg, _	«,
30	, "Вывод ранее введенного массива"
31
32	End Sub
В строке 3 объявлен массив Int_Array без указания размерности. Это подразумевает, что где-то в коде при помощи оператора ReDim размерность будет указана. Для ввода данных в массив используется бесконечный цикл Do (строки 10-23), так как количество вводимых данных заранее неизвестно. В цикле в диалоговом окне функции InputBox (строки 12-14) вводятся значения для элементов массива. Если значение введено (пользователь не отказался от ввода посредством кнопки Cancel), размерность массива увеличивается (строка 19) с сохранением предыдущих значений элементов массива и очередному (новому) элементу массива присваивается введенное значение (строка 22). За количеством элементов в массиве «следит» целая переменная i, значение которой увеличивается в начале цикла.
Массивы
293
Если пользователь отказывается от ввода, оператор Exit Do (строка 15) прекращает работу цикла Do. При этом значение переменной i в этот момент оказывается на единицу больше размерности массива: оператор в строке 11 выполнился (увеличение i), а в строке 19 — нет (увеличение размерности массива).
Во второй части процедуры размерность массива уже известна (i— 1), поэтому можно для формирования строки выдачи на экран использовать цикл с определенным количеством итераций, т.е. цикл For...Next (строки 25-27). Остальное по причине сходства с предыдущими двумя листингами должно быть понятно без комментариев.
В листинге 12.4 приведен код, который демонстрирует один из возможных способов работы с динамическим массивом.
	Листинг 12.4. Работа с динамическим двумерным массивом
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47	Option Base 1 Sub DemoDinArray2() Dim Int_ArraylO As Integer Dim Int_Array() As Integer Dim str_msg As String Dim i As Integer, m As Integer, n As Integer Dim Num str msg = "" i = 0 Do i = i + 1 Num = InputBox("Введите целое число для " _ & i & "-го элемента массива", _ "Ввод элементов массива") If Len(Num) = 0 Then Exit Do ' выход из цикла ' изменение размера массива ' с сохранением элементов ReDim Preserve Int_Arrayl(i) ' ввод данных в i-й элемент массива Int_Arrayl(i) = Num Loop m = i - 1	’ вторая размерность массива ' ввести первую размерность: п = InputBox("Введите количество строк массива ") ReDim Int_Array(n, m) ' запись в выходной массив уже введенной строки: For j = 1 То m Int_Array(l, j) = Int_Arrayl(j) Next ' теперь работаем с обычным двумерным массивом, ' только первую строку не заполняем: For i = 2 То п For j = 1 То m Int_Array(i, j) = InputBox("Введите целое число для " _ & " элемента (" & i &	& j & ")", _ "Ввод элементов массива; строка " & i) Next j Next i
294
Глава 12
48
49	' подготовка строки выдачи
50	For i = 1 То п
51	For j = 1 То m
52	str_msg = str_msg & Int_Array(i, j) & ", " t
53	Next j
54
55	str_msg = str_msg & Chr(13) 'перевод строки
56	Next i	*
57
58	MsgBox "Введено: " & Chr (13) & str_msg, _
59	, "Вывод ранее введенного массива"
60
61	End Sub
В первой части процедуры DemoDinArray2 (строки 9-27) в динамический массив Int_Arrayl записывается первая строка будущего многомерного массива и определяется его вторая (количество столбцов) размерность. Как только пользователь во время ввода первой строки отказался от ввода, формирование первой строки заканчивается. В этот момент программе известна вторая размерность будущего двумерного массива: m=i—1. В строке 30 функция InputBox запрашивает ввести первую размерность массива Int_Array, а в строке 31 объявляется этот двумерный массив. В строках 33-36 данные из одномерного массива Int_Arrayl переписываются в первую строку двумерного массива Int_Array.
Со строки 41 программа почти ничем не отличается от кода листинга 12.2, начиная со строки 7. Отличие состоит только в том, что в последнем коде заполнение двумерного массива во вложенном цикле осуществляется со второй строки и пределы цикла заданы не литерами, а переменными.
В качестве еще одного примера использования динамического массива рассмотрим программу, при помощи которой можно пронумеровать выделенное количество строк. При этом эта нумерация будет отличаться от автонумерации Word тем, что строки, пронумерованные таким образом, ничем не отличаются от обычного текста и могут быть восприняты другими редакторами при передаче в них данного текста.
Листинг 12.5. Нумерация строк
1 ' НумерацияСтрок Macro
2 1 11 Macro recorded 28.04.01 by Владимир Кузьменко
3 '
4 ' Нумерует строки выделенного текста
5 ' Вызов: Ctrl+Alt+N
6 ' •
7	' количество выделенных строк:
8 ii = Selection.Paragraphs.Count()
9
10	' объявление массива для хранения строк:
11 Dim mas() As String
12
13	1 цикл считывания строк и добавления нумерации:
14 For i = 1 То ii
15	ReDim Preserve mas(i)
16	tt = Selection.Paragraphs(i)	»
17	mas(i) = Str(i) &	& vbTab & tt '
18 Next
19
20	' удаление выделенного	фрагмента:
21	Selection.Cut
22
23	1 цикл печати массива:
Массивы
295
24	For i = 1 То ii
25	Selection.TypeText Text:=mas(i)
26	Next
27
Если вам необходимо начинать нумерацию с некоторого числа и вместо символа использовать какой-либо другой, макрос можно переписать, например, так, как это сделано в следующем листинге.
Листинг 12.6. Работа с динамическим одномерным массивом
1	Sub НумерацияСтрок()
2	'
3	1 НумерацияСтрок Macro
4	' Macro recorded 28.04.01 by Владимир Кузьменко
5	'
6	' Нумерует строки выделенного текста
7	' Вызов: Ctrl+Alt+N
8	'
9
10	BeginNumber = CInt(InputBox("Введите начальный номер строки", _
11	"Ввод номера первой строки", 1))
12
13	NumberChar = InputBox("Введите символ разделения", _
14	"Ввод символа разделения",
15
16	' количество выделенных строк:
17	ii = Selection.Paragraphs.Count()
18
19	' объявление массива для хранения строк:
20	Dim mas() As String
21
22	' цикл считывания строк и добавления нумерации:
23	For i - 1 То ii
24	ReDim Preserve mas(i)
25	tt = Selection.Paragraphs(i)
26	mas(i) - Str(i + BeginNumber - 1) & NumberChar & vbTab & tt
27	Next
28
29	1 удаление выделенного	фрагмента:
30	Selection.Cut
31
32	' цикл печати	массива:
33	For i =	1	To	ii
34	Selection.TypeText Text:=mas(i)
35	Next
36	End Sub
Как и в предыдущем макросе, в строке 26, кроме вводимого символа разделения номера и кода, используется символ табуляции (его роль играет константа vbTab). Это необходимо для того, чтобы строки кода были выровнены слева. Заметьте, что для нумерации последнего макроса в качестве символа разделения использовался символ
функции LBound и UBound
Для контроля за размерами как статических, так и динамических массивов можно использовать одну или пару переменных для сохранения минимального и максимального индекса массива, как это делается в ранее рассмотренных лис
296
Глава 12
тингах. Если для отслеживания верхнего и нижнего пределов индексов массива пользователь полагается на собственные переменные, то он полностью отвечает за обновление и точность этих переменных. В противном случае процедуры не будут работать правильно — будет обрабатываться меньше элементов, чем в действительности содержит массив, или будет получено сообщение об ошибке при попытке доступа к массиву с индексами, выходящими за фактический размер массива. Такие программные ошибки бывает трудно отслеживать.
VBA имеет пару функций, которые освобождают пользователя от необходимости вручную отслеживать верхний и нижний пределы массива — функции LBound и UBound. Эти функции возвращают нижнее и верхнее граничные значения индексов статического или динамического массива.
Функции LBound и UBound имеют следующий синтаксис:
СИНТАКСИС	- «
LBound(arrayName [, dimension])
UBound(arrayName [, dimension])
Функция LBound возвращает первый индекс массива, представленного с помощью arrayName. Функция UBound возвращает наибольший индекс массива, представленного с помощью arrayName. Можно использовать эти две функции как со статическими, так и с динамическими массивами. Аргумент dimension представляет целое число, определяющее измерение массива, для которого необходимо получить нижний или верхний предел. Если опустить dimension, VBA возвращает предел для первого измерения массива.
Следующие фрагменты кода являются примерами использования функций LBound и UBound:
Dim А(3 То 9) As String
For i = LBound(A) To UBound(A)
A(i) = String(10, 65 + 1)
Next i
Dim aMatrix(l To 365, 1990 To 1999)
For i = LBound(aMatrix, 1) To UBound(aMatrix, 1)
For j = LBound(aMatrix, 2) To UBound(aMatrix, 2) Matrix(i, j) = Rnd
Next j
Next i
Заметьте, что во втором примере функции LBound и UBound используют необязательный аргумент dimension. Внешний цикл For...Next выполняется столько раз, сколько элементов имеется в первом измерении массива aMatrix, тогда как внутренний цикл For ...Next выполняется столько раз, сколько элементов имеется во втором измерении массива aMatrix.
Использование Erase для очистки или удаления массивов
VBA имеет особый оператор Erase, позволяющий выполнять одну из двух за- -дач в зависимости от того, каким массивом манипулирует пользователь — статическим или динамическим. В случае статических массивов Erase позволяет очищать все элементы массива, в основном переустанавливая массив в то же самое состояние, какое он имел, когда VBA создавал его в оперативной памяти. В случае динамических массивов Erase позволяет полностью удалять массив и его содержимое из оперативной памяти.
Массивы
297
Когда элементы массива заполнены, данные в массиве остаются (независимо от того, является данный массив статическим или динамическим) до тех пор, пока пользователь не присвоит новые значения элементам массива или пока VBA не освободится от массива. (Массивы следуют тем же правилам области действия и персистенции, что и любая другая переменная в VBA, как описывается в главе 4.)
При некоторых обстоятельствах может понадобиться очистить все значения в массиве, устанавливая числовые значения на 0, строковые значения на пустые строки и так далее. Обычно следует использовать цикл For...Next или For...Each для установки всех элементов в массиве на определенное значение. Следующие фрагменты кода показывают оба цикла For...Next и For ...Each, используемые для инициализации всех значений в числовом массиве на 0:
For k = LBound(NumArray) То UBound(NumArray) NumArray(к) - О
Next к
For Each Num In NumArray
Num = 0
Next Num
Первый фрагмент кода использует цикл For ...Next и функции LBound и UBound для прохождения в цикле по всем элементам массива; второй фрагмент кода использует For...Each для прохождения в цикле по каждому элементу массива, также устанавливая каждый элемент на 0. Хотя эти циклы довольно короткие, можно выполнить ту же самую задачу для статического массива даже более эффективно с помощью единственного оператора Erase:
Erase NumArray
Массивы «имеют тенденцию» занимать относительно большой объем оперативной памяти — например, массив из 20 элементов занимает такой же объем памяти, как 20 отдельных переменных одного и того же типа. Поскольку массивам требуется так много памяти, следует удалять динамические массивы из оперативной памяти, когда они фактически не используются. (Статические массивы не могут удаляться из оперативной памяти до тех пор, пока VBA автоматически не освобождается от массива.)
VBA удаляет из памяти массивы, объявляемые локально в процедуре (так же, как и любые другие локальные переменные), каждый раз, когда процедура прекращает выполняться. Однако массивы, объявляемые на модульном уровне, существуют пока любая процедура в этом модуле выполняется. Если программа большая, вам может понадобиться восстановить ресурс памяти, используемой динамическими массивами модульного уровня. Оператор Erase позволяет делать именно это.
Оператор Erase имеет следующий синтаксис:
СИНТАКСИС
Erase arrayI [, array2, . ]
Здесь arrayl и аггау2 представляют любое допустимое имя массива VBA. Можно перечислить столько массивов в операторе Erase, сколько хотите, отделяя каждое имя массива запятой.
Оператор Erase удаляет из памяти динамические массивы, освобождая область памяти, ранее используемую этим массивом. При удалении динамического массива с помощью оператора Erase необходимо повторно создать массив с помощью оператора ReDim перед тем, как можно будет использовать этот определенный динамический массив снова. При попытке доступа к элементам в динамическом массиве, для которого был использован оператор Erase, без его переопределения VBA отображает сообщение о runtime-ошибке.
298
Глава 12
Поведение оператора Erase для статических массивов немного сложнее и зависит от конкретного типа элементов массива. В следующей таблице описывается действие оператора Erase со статическими массивами различных типов:
Тип статического массива	Действие оператора Erase
Любой числовой тип	Устанавливает элементы массива на 0.
Любой строковый тип	Устанавливает элементы массива на строку нулевой длины (""); устанавливает строки фиксированной длины как все символы пробелов.
Variant	Устанавливает элементы массива на Empty.
Object	Устанавливает элементы массива на Nothing.
Любой пользовательский тип	Устанавливает каждую переменную в пользовательском типе индивидуально: численные типы устанавливаются на 0, строковые — на строки нулевой длины, Variant — на Empty, Object — на Nothing.
Использование массивов в качестве аргументов процедур и функций
VBA дает возможность передавать массивы в качестве аргументов процедур и функций. Эта возможность может быть очень полезной; поскольку нет необходимости задавать размер массива, который передается как аргумент, можно писать универсальные процедуры или функции обработки массива. Например, можно написать функцию, получающую числовой массив в качестве аргумента и возвращающую среднее значение всех чисел в массиве как результат функции. Еще один пример: можно написать процедуру, получающую массив в качестве аргумента, передаваемого по ссылке, и сортирующую этот массив. И в одном, и в другом примерах можно написать процедуру или функцию для работы с массивом любого размера — пять элементов, 10 элементов, 100 элементов и так далее.
Общий синтаксис для аргументов-массивов для процедур или функций такой же, как для любых аргументов процедур или функций:
* СИНТАКСИС
[ByVai I ByRef] arrayname() As type
Как в случае аргументов процедур и функций, о которых вы уже знаете, ключевое слово ByVai указывает VBA передать аргумент-массив по значению, а ключевое слово ByRef указывает VBA, что следует передавать аргумент-массив по ссылке. Если ByVai и ByRef пропущены, VBA передает аргумент-массив по ссылке.
В этой синтаксической конструкции аггаупате() представляет аргумент-массив; можно использовать любой допустимый идентификатор VBA в качестве имени аргумента-массива. Необходимо всегда включать пустые круглые скобки после arrayname', круглые скобки указывают VBA, что этот аргумент является массивом. Параметр type представляет любой допустимый тип VBA или определенный пользователем тип.
Следующий фрагмент кода показывает, как включать массивы в качестве аргументов для процедур и функций:
Массивы
299
Sub ShowText(Lines(), NumLines As Integer)
1 получает массив типа Variant, передаваемый по ссылке
End Sub
Sub SortList(ByRef List() As String, NumLines As Integer) 1 получает массив типа String, передаваемый по ссылке
End Sub
Если вы помните, передача аргументов по значению (с помощью ключевого слова By Vai) приводит к тому, что VBA передает копию данных функции или процедуре. Не передавайте массивы по значению, если в этом нет особой необходимости — передача больших массивов по значению может быстро исчерпать ресурсы памяти вашего компьютера, приводя к runtime-ошибкам из-за нехватки памяти.
Если вы обратили внимание, в двух из трех последних примерах вместе с именами массивов в качестве параметров передаются целые переменные NumLines. Здесь подразумевается передача вместе с ссылкой на массив его размерности. Однако замечательным свойством VBA является то, что он позволяет посредством ранее рассмотренных нами функций Lbound и Ubound внутри процедуры, которая принимает массив в качестве аргумента, определить размерность переданного ей массива. Отметим, что далеко не все системы программирования обладают такой возможностью. Ниже (листинг 12.7) приведен пример передачи массива в качестве параметра процедуре, единственный оператор которой выдает в диалоговом окне размерность переданного ей массива.
Листинг 12.7. Определение размерности массива-аргумента
1	Sub TestUBoundLBound(mas())
2	MsgBox "размерность массива " & "(" & _
3	UBound(mas, 1) &	& UBound(mas, 2) & ")" .
4	End Sub
5
6	Sub a ()
7	Dim arr(9, 7)
8	Call TestUBoundLBound(arr)
9	End Sub
В результате работы этого кода на экране появляется диалоговое окно, представленное на рис. 12.6.
Рис. 12.6
Размерность массива, передаваемого в качестве аргумента, легко определяется в вызывающей процедуре
размерность массива (9,7)
Microsoft Word
иинажоигис!и oxxogodEOj
II «UWh
Глава 13
Управление файлами с помощью VBA
Управление файлами — это одна из интереснейших задач для программиста в любой системе программирования. Когда-нибудь вы, вероятно, захотите (по всей видимости, вы уже захотели), чтобы ваши процедуры были способны копировать или удалять документ, рабочую книгу или другой файл. Visual Basic for Applications предоставляет различные операторы, функции и методы для выполнения общих задач управления файлами.
Управление файлами
В этом разделе описывается, что такое управление файлами, обсуждаются некоторые из типичных действий, которые можно выполнять как часть задач управления файлами, а также описываются VBA-функции, операторы и методы управления файлами.
Что такое управление файлами
Управление файлами (file management) — термин, используемый для описания действий, которые выполняются с файлами, сохраненными на дисковых драйверах. Управление файлами включает действия, такие как копирование файлов, удаление неиспользуемых файлов для освобождения области дисковой памяти, перемещение файлов с одного диска (или папки) на другие и создание или удаление каталогов диска. Управление файлами включает также такие виды обработки, как просмотр списка файлов в папке для определения размера файла или даты и времени, когда этот файл был модифицирован в последний раз.
VBA позволяет выполнять наиболее общие задачи управления файлами под контролем процедуры или функции, которую вы можете написать.
Windows Desktop и справочная система используют термин папка (folder) для обозначения того, что опытные пользователи Windows или DOS знают как каталоги (directories). В этой книге используется термин папка для согласованности с терминологией Windows; в некоторых случаях также используется термин каталог.
Возможности VBA по управлению файлами
В табл. 13.1 приведены VBA-функции, операторы и методы управления файлами. В первом столбце таблицы находится ключевое слово VBA, во втором — указывается, предназначено ли ключевое слово для функции, оператора или объектного метода. Наконец, в третьем столбце содержится краткое описание назначения каждой функции, оператора или метода.
Таблица 13.1. Функции, методы и операторы управления файлами
I Имя	Категория	Назначение
ChDir	Оператор	Изменяет текущий каталог (папку).
ChDrive	Оператор	Изменяет текущий драйвер диска.
Управление файлами с помощью VBA
303
Имя	Категория	Назначение
CurDir	Функция	Возвращает текущий каталог (папку).
Dir	Функция	Возвращает имя каталога или файла, совпадающее с определенным именем файла (включая символы универсального сопоставления), передаваемым как строковый аргумент. Предназначена для нахождения одного или нескольких файлов на диске.
FileCopy	Оператор	Копирует файл.
FileDateTime	Функция	Возвращает значение типа Date, содержащее дату и время, когда этот файл был изменен последний раз.
FileLen	Функция	Возвращает длину файла в байтах.
GetAttr	Функция	Возвращает число, представляющее объединенные атрибуты файла или каталога диска, такие как System, Hidden и так далее.
GetOpen-FileName	Метод	Отображает Excel-диалоговое окно Open и возвращает имя файла, выбранное пользователем. В Word не имеется.
GetSave-AsFileName	Метод	Отображает Excel-диалоговое окно (Save As) и возвращает имя файла, выбранное пользователем. В Word не имеется.
Kill	Оператор	Удаляет файлы с драйвера диска.
MkDir	Оператор	Создает каталог диска (папку).
Name	Оператор	Переименовывает или перемещает файл.
RmDir	Оператор	Удаляет каталог диска (папку).
SetAttr	Оператор	Устанавливает атрибуты файла.
Вы могли заметить, что в табл. 13.1 не приводятся аргументы ни для каких элементов (функций, методов, операторов). Несколько из этих функций, операторов и методов имеют довольно сложные списки аргументов и опций. Начиная со следующего раздела в этой главе, каждая VBA-функция, оператор или метод управления файлами описывается полностью со всеми аргументами и опциями.
Операторы, функции и объектные методы, имеющиеся в VBA, делятся на шесть различных функциональных частей:
	Получение или изменение атрибутов файла.
	Выборка или нахождение имен файлов.
	Получение или изменение текущего драйвера диска и папки или создание и удаление папок диска.
	Копирование или удаление файлов.	'
	Переименование или перемещение файлов.
	Получение информации о файлах, такой как длина файла, дата и время, когда этот файл был модифицирован последний раз.
Атрибуты файла
Каждый файл, сохраненный на любом диске Windows (или более ранней версии DOS), имеет атрибуты (attributes). Независимо от конкретного типа драйвера
304
Глава 13
диска (жесткий диск, гибкий диск, RAM-drive, ZLP-drive, Syquest-drive и так далее) Windows и DOS используют атрибуты файла для определения того, какие действия по управлению файлами допускаются для этого файла. Например, Windows (или DOS) запрещает вам (и любым программам приложений) удалять, модифицировать или переименовывать файлы с атрибутом read-only.
Windows создает информацию об атрибутах файла, когда вы или программа приложения, работающая на вашем компьютере, создает новЬш файл. В каком-то смысле, атрибуты файла подобны свойствам объекта: атрибуты файла дают файлу некоторую характеристику в зависимости от конкретных атрибутов, которые он имеет. Атрибуты файла являются частью информации файла, которую Windows сохраняет на драйвере диска. Windows сохраняет информацию об атрибутах файла вместе с информацией об имени файла, размере, дате и времени.
Windows автоматически обновляет и сопровождает информацию об атрибутах файла. Чаще всего вы не знаете об атрибутах файла, и обычно нет причины, по которой вам было бы необходимо знать, что такое атрибуты. В некоторых же случаях бывает полезно понимать и использовать атрибуты файла. В частности, необходимо понимать атрибуты файла и их значение для того, чтобы использовать все преимущества VBA-функции Dir.
Windows (и DOS) использует всего семь атрибутов файла для определения различных характеристик файла. Каждый отдельный атрибут может объединяться с другими атрибутами, кроме атрибута Volume Label, например, файл может иметь одновременно атрибуты Hidden, System, Directory, Archive и Read-Only. В следующем списке содержится имя каждого атрибута файла и описывается его значение.
	Archive. Атрибут Archive указывает, изменялся ли файл со времени, когда его резервировали последний раз с помощью backup-программы, такой как BACKUP Windows, или backup-программы других поставщиков, таких как Fastback!, Backlt, Norton Backup и других. Если файл имеет атрибут Archive, это означает, что для этого файла необходимо резервирование. Если файл не имеет атрибута Archive, то этот файл не изменялся со времени, когда он был резервирован последний раз.
	Directory. Если файл имеет атрибут Directory, это означает, что файл в действительности является каталогом или подкаталогом (папкой — в терминологии Windows 95). Каталог диска — это файл, который содержит информацию о других файлах; когда вы создаете каталог, Windows создает специальный файл каталога и дает ему атрибут Directory. Атрибут Directory сообщает Windows о том, что этот файл содержит информацию о других файлах и препятствует переименованию, копированию или удалению каталога.
	Hidden. Если файл имеет атрибут Hidden, Windows «скрывает» файл, не показывая его в большинстве случаев при отображении каталога, хотя Windows имеет опцию просмотра, которая отображает имена скрытых файлов.
	Normal. Атрибут файла Normal является на самом деле отсутствием каких-либо специальных атрибутов. Так называемый Normal-атрибут (иногда называемый general) файла просто означает, что файл не имеет никаких других атрибутов, кроме, возможно, атрибута Archive для указания, необходимо ли резервирование для этого файла.
	Read-Only. Атрибут Read-Only означает, что вы можете только читать из файла, но не можете изменять его. Windows 95/98 препятствует изменению, удалению или переименованию файла, который имеет атрибут Read-Only.
	System. Атрибут System указывает Windows, что файл является частью операционной системы компьютера. Как в случае с файлами Read-Only, Windows препятствует изменению файла, имеющего атрибут System. Кроме того, если вы создаете диск автозапуска DOS-командой SYS (или с Windows Control
Управление файлами с помощью VBA
305
Panel), любые файлы, имеющие атрибут System, переносятся на новый диск автозагрузки.
	Volume Label. Атрибут Volume Label информирует Windows о том, что файл является меткой тома диска. (Метка тома (volume label) — это имя, которое вы даете жесткому диску (или дискете) при форматировании, использовании DOS-команды LABEL или изменении свойства Label в листе свойств диска.) Диск может иметь только одну метку тома одновременно.
Windows представляет каждый отдельный атрибут файла уникальным числом и сохраняет это число с информацией об имени и размере файла. Если файл имеет несколько атрибутов, Windows складывает кодовые числа для каждого атрибута и сохраняет их сумму. В следующем разделе описывается, как можно найти и интерпретировать кодовое число для атрибутов файла.
В табл. 13.2 перечисляются коды атрибутов файлов, которые использует Windows, и внутренние константы VBA для этих кодов атрибутов. Как и в случае с другими Числовыми кодами, для которых VBA определяет константу, следует использовать VBA-константу для кодового числа вместо самого кодового числа.
Таблица 13.2. Константы атрибутов файла Visual Basic for Applications
Константа VBA	Значение	Что означает
vbNormal	0	Normal
vbReadOnly	1	Read-Only
vbHidden	2	Hidden
| vbSystem	4	System
vb Volume	8	Volume Label
vbDirectory	16	Каталог или подкаталог диска.
vb Archive	32	Archive. Если установлен, указывает, что этот файл был изменен со времени последнего резервирования.
vb Alias	64	Указанное имя файла является алиасным. Доступна только в Macintosh.
Получение атрибутов файла
Для того чтобы определить, какие атрибуты имеет определенный файл, используйте VBA-функцию GetAttr.
Функция GetAttr возвращает число, содержащее сумму всех числовых кодов для атрибутов файла, и имеет следующий синтаксис:
СИНТАКСИС
GetAttr(pathname)
Аргумент pathname — любое строковое выражение VBA, представляющее допустимое имя файла; pathname может включать буквенную метку диска и полный путь папки; если вы не включаете буквенную метку, GetAttr ищет указанный файл на текущем драйвере диска; если вы не включаете путь папки, функция GetAttr выполняет поиск в текущей папке.
В листинге 13.1 содержится пример, в котором используется функция GetAttr и показывается, как интерпретировать результат функции.
306
Глава 13
Листинг 13.1. Использование функции GetAttr и интерпретация результата
1	Sub ShowFA(fName As String)
2	' отображает окно с сообщением об атрибутах
3	' файла, имя которого передается как аргумент
4
5	Dim fAttr As Integer
6	Dim mStr As String	•
7
8	fAttr = GetAttr(fName)
9	mStr = UCase(fName)
10	mStr = mStr & " has these	attributes: " & vbCr
11	If (fAttr And vbReadOnly)	Then
12	mStr = mStr & "Read-Only" & vbCr
13	If (fAttr And vbHidden) Then _
14	mStr = mStr & "Hidden" & vbCr
15	If (fAttr And vbSystem) Then __
16	mStr = mStr & "System" & vbCr
17	If (fAttr And vbVolume) Then _
18	mStr = mStr & "Volume" & vbCr
19	If (fAttr And vbDirectory) Then
20	mStr = mStr & "Directory" & vbCr	*
21	If (fAttr And vbArchive) Then _
22	mStr = mStr & "Archive" & vbCr
23	MsgBox mStr
24	End Sub	'
25
26	Sub ListFileAttr()
27
28	Dim strPath As String
29
30	ShowFA fName:="c:\io.sys"
31	ShowFA fName:="c:\msdos.sys"
32
33	strPath = "C:\Program Files\Microsoft Office\Office\XlStart"
34	ShowFA fName:=strPath
35
36	End Sub
В листинге 13.1 содержатся две процедуры. Процедура ShowFA занимает строки 1-24, а процедура ListFileAttr — строки 26-36. ListFileAttr просто вызывает ShowFA несколько раз, передавая каждый раз другое имя файла.
Процедура ShowFA имеет один обязательный аргумент с именем fName и типом String. В строке 5 объявляется переменная fAttr типа Integer для сохранения значения, возвращаемого функцией GetAttr. В строке 6 объявляется переменная mStr типа String для сохранения сообщения, формируемого этой процедурой.
При выполнении оператора в строке 8 VBA вызывает GetAttr, передавая строку fName в качестве аргумента и сохраняя результат функции в переменной fAttr. Если строка в fName не содержит допустимого имени файла, VBA отображает сообщение о runtime-ошибке (рис. 13.1).
Рис. 13.1
Сообщения VBA при ошибке в аргументе функции GetAttr
Microtoft Visual Satie .
RurPtime error 53
File not found
OK [ Help
Управление файлами с помощью VBA
307
Строки 9 и 10 формируют первую часть сообщения, которое отображает процедура ShowFA. В строке 9 используется VBA-функция UCase для преобразования имени файла в fName в верхний регистр по «косметическим» причинам.
В строках 11-22 находится ряд операторов If...Then оценивающих число, сохраненное в fAttr, которое содержит сумму всех кодовых чисел для атрибутов этого файла. Заметьте, что эти операторы If...Then не являются вложенными. Значение в fAttr тестируется шесть раз — один раз для каждого возможного значения атрибута. Помните, что значение атрибута, которое Windows 95/98 сохраняет с файлом, является суммой всех кодовых чисел для каждого из атрибутов, которые имеет файл. Если атрибут, наличие которого проверяет определенный оператор If...Then, присутствует, то строка, содержащая соответствующее имя атрибута, добавляется в строку сообщения, сохраняемую в mStr. Оператор MsgBox в строке 23 отображает строку сообщения, которую формируют предыдущие операторы.
В строке 26 содержится объявление процедуры ListFileAttr, которая просто вызывает процедуру ShowFA несколько раз, передавая ей различные имена файлов. Выполнение строки 30 приводит к тому, что ShowFA отображает атрибуты файла для файла IO.Sys. Этот файл является частью операционной системы Windows и всегда находится в корневом каталоге диска автозагрузки. Поскольку IO.SYS является частью операционной системы Windows, он имеет атрибут файла System; он имеет также атрибут Read-Only для предотвращения нечаянного удаления этого важного файла; кроме того, этот файл имеет атрибут Hidden, чтобы он обычно не появлялся в папке рабочего стола Windows или в списках каталога Проводника. При выполнении процедуры ListFileAttr последовательно отображаются диалоговые окна, показанные на рис. 13.2.
Рис. 13.2
Такие окна последовательно отображаются кодом листинга 13 1
В процедуре ShowFA нет тестирования для атрибута файла Normal, потому что атрибут файла Normal — это просто отсутствие любых других атрибутов.
Объявляйте все переменные, которые используете для сохранения кодов атрибутов файла, как переменные типа Integer, так кодовое число атрибута файла всегда находится в допустимом диапазоне типа Integer. Не следует также забывать, что коды атрибутов всегда обрабатываются как одно число, содержащее сумму всех отдельных кодовых чисел для атрибутов данного файла.
Изменение атрибутов файла
Атрибуты файлов можно устанавливать из кода VBA. Например, можно изменить атрибуты файла шаблонного документа, чтобы включить атрибут Read-Only для предотвращения нечаянного удаления этого шаблонного документа.
308
Глава 13
Для изменения атрибутов файла предназначен оператор SetAttr, выполняет ту же самую задачу, что и команда Файл | Свойства (доступная в любых окнах каталога Windows или с помощью щелчка правой кнопкой мыши на значке файла), а также DOS-команда ATTRIB.	1
Оператор SetAttr имеет следующий синтаксис:
СИНТАКСИС
SetAttr pathname, attributes
Здесь pathname — любое строковое выражение, содержащее допустимую спецификацию файла Windows (имя файла и (необязательно) полный путь к каталогу, и буквенную метку диска); attributes — это численное выражение. Численное выражение для attributes должно быть числом между 1 и 255 и состоять из одного из кодовых чисел атрибута файла или суммы кодовых чисел атрибутов.
В листинге 13.2 показан пример того, как можно использовать оператор SetAttr.
Листинг 13.2. Использование оператора SetAttr для изменения атрибутов файла
1	Sub SetReadOnly(fName As String)
2	1 устанавливает атрибут только на чтение	,
3
4	Dim fAttr As Integer
5
6	fAttr = GetAttr(fName)
7
8	' не устанавливать	атрибут, если он уже	установлен
9	If Not CBool(fAttr	And vbReadOnly) Then
10	SetAttr fName, fAttr + vbReadOnly
11	End If
12
13	MsgBox prompt:="Атрибут Read-only для " & _
14	fName & " установлен.", _
15	Title:-"Delete Protection"
16	End Sub
17
18
19	Sub Test_SetReadOnly()
20	Dim iName As String
21	iName = Application.GetOpenFilename
22	SetReadOnly iName
23	ShowFA iName
24	End Sub
Процедура SetReadOnly защищает файлы от случайного удаления тем, что присваивает файлу атрибут Read-Only, не влияя на другие атрибуты. SetReadOnly имеет один обязательный аргумент типа String с именем fName, который используется для передачи имени файла в процедуру. В строке 4 объявляется переменная fAttr; процедура использует эту переменную для сохранения числа для атрибутов файла.
В строке 6 используется функция GetAttr для получения атрибутов файла, определенного с помощью fName. В строках 9-11 содержится оператор If, выполняющий оператор SetAttr, если только этой файл не имеет уже атрибут Read-Only. В строке 10 содержится фактический вызов оператора SetAttr. Заметьте, что старые атрибуты файла арифметически складываются с константой vbReadOnly для задания новых атрибутов. Таким образом, оригинальные атрибуты файла сохраняются.
Управление файлами с помощью VBA
309
Наконец, в строках 13-15 содержится оператор MsgBox, отображающий сообщение для пользователя о том, что атрибут Read-Only для файла установлен.
Процедура Test_SetReadOnly тестирует процедуру SetReadOnly. В строке 21 используется Excel-метод GetOpenFileName (который будет описан в следующем разделе) для получения имени файла от пользователя. В строке 23 вызывается процедура SetReadOnly для задания атрибутов файла с целью включения атрибута Read-Only. Наконец, в стро"Ке 24 вызывается процедура ShowFA (приведенная в листинге 13.1) для отображения окна сообщения с новыми атрибутами файла.
Для добавления нового атрибута файла к имеющемуся набору атрибутов используйте оператор Ог. Использование оператора Ог для объединения атрибутов файла в побитовой операции исключает любые возможные проблемы, которые могут возникнуть при использовании арифметического сложения для объединения новых атрибутов с уже имеющимися. Результатом выражения 0 Or 1 является 1; результатом выражения 1 Or 1 является также 1. Поэтому можно объединять новый атрибут файла с имеющимся числом атрибута файла, используя выражение, подобное OldAttr Or vbArchive. Если атрибут Archive не задан в OldAttr, он будет задан как результат операции Ог. Если атрибут Archive уже задан, он останется неизменным.
Как находить файлы
В этом разделе сначала будет показано, как использовать VBA-функцию Dir для поиска в папке одного или нескольких файлов, совпадающих с определенным именем файла. Затем вы узнаете, как использовать VBA для включения Word- или Excel-собственных диалоговых окон Open (Открытие документа) и Save As (Сохранение документа) в ваши процедуры. Можно использовать Word и Excel-встроенные диалоговые окна Open и Save As для предоставления возможности пользователю легко и правильно передавать имена файлов процедурам.
Использование функции Dir для нахождения файлов
Иногда может быть необходимо проверить, содержит ли каталог диска один или несколько файлов, совпадающих с определенной спецификацией имени файла, такой как \Му Documents\*.xls или \Му Documents\*.doc. Для этого можно использовать VBA-функцию Dir. Функция Dir выполняет в VBA те же задачи, что и список файлов в окне папки Windows или DOS-команда DIR — дает возможность посмотреть, какие файлы сохранены в определенной папке и какие имеются другие папки.
Функция Dir имеет следующий общий синтаксис:
СИНТАКСИС
Dir(pathname[, attributes])
Здесь pathname представляет любое выражение String, имеющее результатом допустимое имя файла. Имя файла может содержать буквенную метку драйвера и полный путь папки. Имя папки может также включать символы универсального сопоставления файлов. Необязательный аргумент attributes является числом, представляющим атрибуты тех файлов, которые необходимо найти. При использовании attributes Dir выполняет поиск файлов, имеющих эти атрибуты. Если опустить аргумент attributes, функция Dir выполняет поиск обычных файлов, то есть любых файлов, кроме имеющих атрибуты Hidden, Volume Label, Directory или System.
При вызове функции Dir с аргументом pathname она возвращает строку, содержащую имя первого найденного ею файла, совпадающее с именем файла
310
Глава 13
в аргументе pathname. Если имя файла содержит символы универсального сопоставления (* или ?), то для того, чтобы найти все файлы в каталоге, совпадающие с этим именем файла, необходимо использовать функцию Dir в два этапа. Во-первых, вызывать Dir с аргументом pathname для получения первого совпадающего файла, затем вызывать Dir неоднократно без аргументов до тех пор, пока Dir не возвратит пустую строку. Как только Dir возвращает пустую строку, значит, больше не остается файлов, совпадающйх с этим именем файла. При вызове Dir без указания имени файла, VBA выдает сообщение о runtime-ошибке.
В листинге 13.3 показан пример использования Dir для нахождения только одного файла.
Листинг 13.3. Использование Dir для нахождения одного файла
1	Function IsFile(fName As String) As Boolean
2	' возвращает Истина (True), если файл на диске найден,
3	' иначе - Ложь (False)
4	If (Dir(fName) О "") Then
5	IsFile = True
6	Else
7	IsFile = False
8	End If
9	End Function
12	Sub Test_IsFile()
13	Diq iName As String
14	Dim str_msg As String
15
16	iName = InputBox(prompt:“"Введите имя файла:", _
17	Title:“"Тестирование функции IsFile")
18
19	str_msg = "Файл " S iName	S результат поиска:
20	If IsFile(iName) Then
21	str_msg = str_msg S " найден"
22	Else
23	str_msg = str_msg & " не найден"	'
24	End If
25
26	MsgBox str_msg
27	End Sub
В строках 1-9 содержится функция IsFile, имеющая один обязательный аргумент fName типа String. IsFile возвращает результат с типом Boolean: True, если имя файла в fName находится на драйвере диска, иначе — False.
Работа функции IsFile очень проста. В строке 4 содержится оператор If... Then...Else, который (как часть его логического выражения) вызывает функцию Dir, передавая содержимое fName в качестве имени файла, поиск которого необходимо выполнить. В этом обращении к функции Dir никакой аргумент для атрибутов не определяется, поэтому она будет находить любой файл, кроме файлов, имеющих атрибуты Hidden, System, Directory или Volume Label.
Поскольку назначением функции IsFile является просто определение тогр, существует ли определенный файл, возвращаемый результат функции Dir не используется, кроме сравнения его с пустой строкой. Если результат функции Dir не является пустой строкой, то Dir нашла указанный файл и VBA выполняет строку 5, которая присваивает результату функции значение True. Если результат функции
Управление файлами с помощью VBA
311
Dir является пустой строкой, то никакого совпадающего файла не было найдено и VBA выполняет строку 7, которая присваивает False результату функции.
В строках 12-27 объявляется процедура для тестирования функции IsFile. Учитывая номер текущей главы, не будем подробно останавливаться на разборе этого кода. Если в таком простом коде что-то неясно, следует прочитать внимательнее предыдущие главы.
Функцию Dir можно также использовать для нахождения в папке всех файлов, совпадающих с определенным именем файла. Эта возможность функции Dir наиболее полезна, когда имя файла содержит символы универсального сопоставления. Можно использовать функцию Dir таким образом, если необходимо, скажем, найти все файлы шаблонов в определенной папке.
В листинге 13.4 показан пример того, как функция Dir используется для нахождения нескольких файлов.
	Листинг 13.4. Использование функции Dir для нахождения нескольких файлов
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45	Sub ShowFA(fName As String, Number As Integer) ' отображает окно с сообщением об атрибутах ' файла, имя которого передается как аргумент Dim fAttr As Integer Dim mStr As String fAttr = GetAttr(fName) mStr = UCase(fName) mStr = mStr & " has these attributes: " & vbCr If (fAttr And vbReadOnly) Then _ mStr = mStr & "Read-Only" & vbCr If (fAttr And vbHidden) Then _ mStr = mStr & "Hidden" & vbCr If (fAttr And vbSystem) Then _ mStr = mStr & "System" & vbCr If (fAttr And vbVolume) Then _ mStr = mStr & "Volume" & vbCr	I If (fAttr And vbDirectory) Then _ mStr = mStr & "Directory" & vbCr If (fAttr And' vbArchive) Then _ mStr = mStr & "Archive" & vbCr ' запись в лист Excel: Cells(Number, 1).Value = mStr End Sub Sub ShowAllFiles() ' отображает имена и атрибуты всех файлов ' в указанном каталоге Введите имя каталога: Dim sAttr As Integer Dim fName As String Dim pName As String Dim fCount As Integer pName = InputBox("Введите имя каталога:") If Trim(pName) = "" Then Exit Sub If Right(pName, 1) <> "\" Then pName = pName & "\" sAttr = vbDirectory + vbArchive + vbReadOnly + _ vbHidden + vbSystem ' получить первое имя файла и атрибуты fName = Dir(pName &	sAttr)
312
Глава 13
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
' 61
62
63
If (fName о "") And _
((fName <> ".") And (fName <>	Then
fCount = 1
ShowFA pName & fName, fCount
End If
Do While (fName <> "") fName = Dir()	•
If (fName <> "") And _
((fName <> ".") And (fName <>	Then
fCount = fCount + 1
ShowFA pName & fName, fCount
End If
Loop
MsgBox "Найдено файлов " & fCount
End Sub
В этом листинге сначала (строки 1-26) описана процедура ShowFA, которая уже встречалась в листинге 13.1. Здесь были внесены небольшие изменения: теперь процедура имеет еще один параметр Number типа Integer и результирующая строка выдается не в окне оператора MsgBox (при длинном списке файлов это будет утомлять пользователя даже в процессе тестирования кода), а записывается в Excel-лист, причем Number указывает номер строки, в которую будет записываться результирующая строка.
Процедура ShowAllFiles запрашивает пользователя ввести имя папки (каталога), а затем использует функцию Dir для нахождения всех файлов в этом каталоге. В строках 32-35 объявляются несколько переменных. Переменная sAttr используется для сохранения числа атрибутов файла, fName — для временного хранения имен файлов, возвращаемых функцией Dir, pName — для сохранения пути каталога, который ищет эта процедура, fCount — для сохранения счетчика всех найденных файлов и в качестве параметра функции ShowFA для записи данных о файле в очередную строку листа.
В строке 39 проверяется, имеет ли путь (введенный пользователем в строке 37) каталога в конце строки символ разделителя пути (\), и добавляет его в конец пути, сохраненного в pName, если символ пропущен.
В строках 41-42 задается переменная sAttr, которая должна содержать атрибуты файлов, поиск которых будет выполнять функция Dir. Заметьте, что sAttr задается так, чтобы содержать все возможные атрибуты файла, кроме Volume Label. При таких атрибутах Dir будет находить любой файл в заданном каталоге, включая любые подкаталоги в нем.
В строке 45 выполняется первый вызов функции Dir с использованием пути каталога в pName с добавленной в него строкой (для нахождения всех файлов) и переменной sAttr (с атрибутами файлов). Результат функции Dir присваивается переменной fName.
В строках 46-50 содержится оператор If...Then, который оценивает строку, возвращаемую функцией Dir и сохраненную в переменной fName. Оператор проверяет: 1) является ли переменная fName пустой строкой, 2) не содержит ли fName строку, состоящую из одной точки (.), 3) не содержит ли fName строку, состоящую из двух точек (..). Эти особые строки используются системой файлов Windows 95/98 для обозначения текущего (.) и родительского каталога (..). Хотя такие особые имена файлов являются каталогами и функция Dir будет сообщать об их существовании с таким атрибутом и спецификацией универсального сопоставления, какие используются в данном примере, они на самом деле не существуют на диске, и любая попытка получить их атрибуты с помощью GetAttr приведет к возникновению runtime-ошибки.
Управление файлами с помощью VBA
313
Если fName не является пустой строкой и не содержит специальных элементов (. или VBA выполняет оператор в строке 48, который устанавливает счетчик найденных файлов в 1 (переменная fCount), и выполняет оператор в строке 49, который вызывает процедуру ShowFA для записи в очередную ячейку текущего листа открытой рабочей книги имени файла и его фактических атрибутов.
Теперь, когда первый совпадающий файл найден, необходимо использовать формат второй ступени функции Dir, чтобы найти остальные файлы в каталоге. В строках 52-60 содержится цикл Do, который выполняется, пока fName не является пустой строкой. Если хотя бы один совпадающий файл был найден в вызове функции Dir (в строке 45), то этот цикл будет выполняться, по крайней мере, один раз.
Обратите особое внимание на строку 53. Этот оператор снова вызывает функцию Dir без аргументов. При таком вызове функции Dir VBA «полагает», что пользователь хочет найти больше файлов, совпадающих со спецификацией для аргументов пути и атрибутов, которые использовались в последнем вызове Dir. Функция Dir возвращает следующий файл в каталоге, совпадающий с предыдущими спецификациями имени и атрибутов. Если файлов больше нет, Dir возвращает пустую строку.
Когда все совпадающие файлы в каталоге будут найдены, Dir возвращает пустую строку и цикл прекращает выполняться. Оператор в строке 62 отображает окно сообщения, указывающее, сколько совпадающих файлов было найдено. На рис. 13.3 представлен результат работы кода этого листинга при введенной в окне InputBox строки "C:\WIN98\" (конечно, на каком-то случайном компьютере).
Рис. 13.3
Один из возможных результатов работы кода из листинга 13 4
Файл Главка Вид Вставка Формат Сдэвис Данные Окно Справка - S х
Microsoft Excel
А В С D Е F
1	С \WIN98\SYSTEM has these attributes □Directory^
2	С \WIN98\WINSOCK DLL has these attributes □ArchiveO
3	C \WIN98\COMMAND has these attributes □Directory’^
4	C \WIN98\WIN INI has these attributes j
5	C \WIN98\INF has these attributes DHiJ
6	C \WIN98\HWINFO EXE has these attnt
7	C \WIN98\NETDET INI has these attnbu Найден0 399
8	C \WIN98\PIDGEN DLL has these attrib i------1
9	C \WIN98\SUBACK BIN has these attnb I .У....ll
10	C \WIN98\W98SETUP BIN has these aH.uuiv..и,..ии
11	C \WIN98\HELP has these attributes □ Directory^
12	C\WIN98\LICENSE TXT has these attributes DArchiveD
•IQ Г 11Л/1К1ЛО1СТ innnDT ТУТ к-Л И.ЛЛЛ AHr К	ПЛглк «ЧП
К < ► н \ Sheetl / Sheet2 \Видеокарты/ ]<
NUM
Использование встроенных диалоговых окон Excel для получения имен файлов
Excel-объект Application имеет два метода — GetOpenFilename и GetSave-AsFilename, которые можно использовать в Excel-коде VBA для упрощения задачи получения имени файла от пользователя. В следующих двух разделах описывается, как использовать эти два метода в процедурах.
Использование метода GetOpenFilename
Во многих примерах в этой книге использовалась функция InputBox для получения имен файлов от пользователя процедуры. Хотя получение имени файла
314
Глава 13
с помощью InputBox является нормальным, при этом не используются преимущества ориентированного на файл диалогового окна, такого как Excel-окно Open, которое фактически позволяет увидеть, какие файлы имеются на диске, и просматривать списки файлов различных драйверов диска и каталогов.
Можно использовать Excel-метод GetOpenFilename в Excel-коде VBA для отображения диалогового окна, которое выглядит и работает так же, как диалоговое окно, отображаемое Excel при выборе команды File | Open (файл | Открыть). Метод GetOpenFilename возвращает строку, которая содержит имя файла, выбранного пользователем, включая буквенную метку диска и полный путь папки. Если пользователь отменяет диалоговое окно, GetOpenFilename возвращает Boolean-значение False в качестве ее результата.
Excel-метод GetOpenFilename имеет следующий синтаксис:
СИНТАКСИС	<•,	......
object.GetOpenFilename(fileFilter, filterindex, title, _ buttonText, multiSelect)
Здесь object — это ссылка на Excel-объект Application. Хотя ссылка object на Excel-объект Application является обязательной, все аргументы GetOpenFilename являются необязательными. Аргумент fileFilter представляет любое допустимое выражение String, специально форматированное для задания фильтров файла, перечисленных в окне раскрывающегося списка Files of type в диалоговом окне Open. Если аргумент fileFilter опущен, фильтр файла для раскрывающегося списка Files of type — это All Files (*.*).
Аргумент filterindex представляет любое численное выражение и указывает, какой фильтр файла должен использовать VBA как фильтр по умолчанию для раскрывающегося списка Files of type (Тип файлов). Если этот аргумент опустить или указать число, большее, чем фактическое количество фильтров файла, то первый фильтр файла становится фильтром по умолчанию. Аргумент title представляет любое выражение типа String и является заголовком, отображаемым VBA в диалоговом окне Open. Если опустить title, VBA отображает диалоговое окно с обычным Open-заголовком.
Аргумент buttonText — необязательный параметр типа Variant. Используется только в Macintosh.
Аргумент multiSelect представляет любое выражение или значение Boolean. Если multiSelect равно True, то диалоговое окно Open дает возможность пользователю выбирать множество имен файлов. Когда multiSelect равно True, GetOpenFilename возвращает массив, содержащий имена всех выбранных файлов.
Для определения строки фильтра файла форматируйте строку следующим образом:
"FilterNamel,filespecl,FilterName2,filespec2,FilterNameN, filespecN"
Аргумент filterName представляет текст, который VBA отображает в окне раскрывающегося списка Files of type. Аргумент filespec представляет спецификацию файла, которую Windows использует для ограничения файлов, приводимых в окне Open. Можно вносить в список сколь угодно много фильтров файла.
В следующей строке показан пример строки фильтра файла:
"Templates (*.xlt), *.xlt, Workbooks (*.xls), *.xls"
Эта строка фильтра приводит к появлению двух опций (Templates и Workbooks) в окне раскрывающегося списка Files of type.
В листинге 13.5 показан пример, использующий метод GetOpenFilename.
Управление файлами с помощью VBA
315
Листинг 13.5. Использование метода GetOpenFilename для получения имени файла от пользователя процедуры
1	Sub TestGetOpenFilename()
2	' открывает указанную рабочую книгу и выбирает
3	' лист, указываемый пользователем в окне функции InputBox
4
5	Const iTitle = "Ввод имени рабочей книги"
6	Dim ShtName As String
7
8	Const FilterList = _
9	"Templates (*.xlt),*.xlt,Workbooks (*.xls),*.xls"
10
11	Dim fName As String
12
13
14	fName = Application.GetOpenFilename(Title:=iTitle, _
15	filefilter:=FilterList, _
16	filterindex:=2)
17
18
19	If fName = "False" Then 'для русской версии "Ложь"
20	MsgBox prompt:“"Операция отменена!", _
21	Title:=iTitle
22	Exit Sub
23	End If
24
25	Workbooks.Open Filename:=fName
26
27	ShtName = InputBox("Введите наименование	листа")
28	ActiveWorkbook.Sheets(ShtName).Select
29	MsgBox prompt:“"Книга " & fName S _
30	" открыта, лист 11 & ShtName & _
31	" выбран ", _
32	Title:“iTitle S " (Завершение)"
33	End Sub
Процедура TestGetOpenFilename открывает рабочую книгу, выбранную пользователем в диалоговом окне с заголовком, определяемым константой iTitle, а затем выбирает рабочий лист с именем, указываемым в окне функции InputBox, в открытой рабочей книге.
В строках 8-9 объявляется константа FilterList, в дальнейшем передаваемая в качестве фильтра файла при обращении к методу GetOpenfilename.
В строках 14-16 содержится один оператор, вызывающий метод GetOpen-Filename и присваивающий его результат переменной fName. При выполнении этого оператора VBA отображает диалоговое окно, показанное на рис. 13.4. На этом рисунке показано открытое окно списка Files of type, чтобы можно было видеть действие аргумента fileFilter. Заметьте, что диалоговое окно на рисунке идентично Excel-окну Open, за исключением заголовка окна и содержимого окна списка Files of type. Поскольку аргумент filterindex (строка 16) установлен на 2, фильтром по умолчанию является фильтр Workbooks (*.xls), а не Templates (*.xlt).
Имя в диалоговом окне можно выбрать точно так же, как в Excel-окне Open. Когда вы выбираете кнопку Open, метод GetOpenFilename возвращает строку, содержащую имя файла, буквенную метку диска и полный путь каталога (аргумент multiSelect не был использован, поэтому можно выбрать только одно имя файла). Если вы выберите Cancel, GetOpenfilename возвращает Boolean-значение False. Поскольку в данном случае fName является переменной String, VBA автоматически преобразует False в строку "False".
316
Глава 13
Рис. 13.4 Процедура TestGetOpenFilename использует метод GetOpenFilename для отображения этого диалогового окна Обратите внимание на фильтры в окне списка Тип файлов
Если операторы в строках 19-23 не обнаружат факт отказа от ввода имени файла, то в строке 25 вызывается метод Workbooks.Open, открывающий выбранную пользователем рабочую книгу. В строке 27 с помощью функции InputBox пользователь может ввести наименование листа уже открытой рабочей книги. В это время ярлычки с именами листов будут видны пользователю (рис. 13.5).
Рис. 13.5
В момент ввода наименования необходимого листа ярлычки листов видны пользователю
Завершается процедура, как обычно, оператором MsgBox с сообщением об успешном выполнении задачи процедуры.
Не следует забывать, что GetOpenFilename возвращает строку, когда пользователь выбирает имя файла, и Boolean-значение False — при отмене диалогового окна. Если вы присваиваете результат метода GetOpenFilename переменной типа Variant, необходимо выполнять тестирование для значения False, а не строки "False".
Метод GetOpenFilename возвращает массив строк, если используется значение True для необязательного аргумента multiSelect, даже если пользователь выбирает только один файл.
Управление файлами с помощью VBA
317
Использование метода GetSaveAsFilename
Вы можете также использовать Excel-метод GetSaveAsFilename для отображения диалогового окна, которое выглядит и работает так же, как окно, отображаемое Excel, йогда пользователь выбирает команду File | Save As.... Метод GetSaveAsFilename также возвращает строку, содержащую имя файла, которое выбирает пользователь, включая буквенную метку диска и полный путь каталога. Если пользователь отменяет диалоговое окно, GetSaveAsFilename возвращает Boolean-значение False.
Метод GetSaveAsFilename имеет следующий синтаксис:
СИНТАКСИС
object.GetSaveAsFilename(initialFilename, fileFilter, _ filterindex, title,buttonText)
Метод GetSaveAsFilename имеет почти такие же аргументы и синтаксис, как метод GetOpenFilename. В этой синтаксической конструкции object — это ссылка на объект Application, fileFilter — выражение String, форматированное для задания фильтров файла, перечисленных в раскрывающемся списке Save as type; filterindex — численное выражение, указывающее, какой фильтр файла должен использовать VBA в качестве фильтра по умолчанию, a title — выражение String для строки заголовка диалогового окна. Если пропускается аргумент title, VBA отображает диалоговое окно с обычным заголовком SaveAs.
Аргумент buttonText — необязательный параметр типа Variant. Используется только в Macintosh.
Метод GetSaveAsFilename имеет еще один аргумент — initialFilename, который представляет любое допустимое имя файла. Если указать этот необязательный аргумент, имя файла, которое задается для initialFilename, появляется в текстовом окне File Name, когда диалоговое окно SaveAs отображается первый раз.
Строки фильтра файла для метода GetSaveAsFilename определяйте таким же образом, каким форматируете их для GetOpenFilename.
В листинге 13.6 показан пример, использующий метод GetSaveAsFilename.
Листинг 13.6. Использование GetSaveAsFilename для получения имени файла от пользователя
1	Sub ConvTemplate()
2	' сохраняет текущую книгу как файл шаблона 3
4	Const FilterList = "Templates (*.xlt),*.xlt"
5	Const iTitle = "Преобразование рабочей книги в шаблон"
6	Static sN As String
7	Static TCount As Variant
8	'	Dim iName As String
9
10	If IsEmpty(TCount) Then
11	TCount = 1
12	Else
13	TCount = TCount + 1
14	End If
15
16	sN = "Temp"	&	CStr(TCount)	&	".xlt"
17	iName =	Application.GetSaveAsFilename(initialfilename:=sN,
18	filefilter:=FilterList, _
19	Title:=iTitle)
318
Глава 13
20
21	If iName = "False" Then
22	MsgBox prompt:^"Преобразование в шаблон отменено",
23	Title:=iTitle
24	Else
25	Activeworkbook.SaveAs Filename:=iName, _
26	FileFormat:=xlTemplate
27	End If
28	End Sub	•
Процедура ConvTemplate сохраняет текущую рабочую книгу как Excel-шаблонный файл и использует метод GetSaveAsFilename для получения имени для нового шаблонного файла. В строке 4 объявляется константа для фильтра файла; в строке 5 — константа для заголовков диалоговых окон, отображаемых этой процедурой.
В строках 6 и 7 объявляются Static-переменные: sN используется для имени нового шаблонного файла, a TCount — для нумерации шаблонных имен по умолчанию. Переменная iName используется для сохранения выбираемого пользователем имени файла.
В строках 10-16 устанавливается счетчик шаблонных файлов и формируется предлагаемое имя шаблонного файла. В строках 17-19 содержится один оператор, который вызывает метод GetSaveAsFilename и присваивает его результат переменной iName. При вызове этого метода VBA отображает диалоговое окно, показанное на рис. 13.6. Заметьте, что это окно точно такое же, как Excel-окно SaveAs (Сохранение документа), за исключением заголовка диалогового окна (поскольку он формируется процедурой и является аргументом метода GetSaveAsFilename) и содержимого списка Тип файла (Save as type).
В строке 21 с помощью оператора If...Then...Else проверяется, не отменил ли пользователь диалоговое окно метода GetSaveAsFilename. Если пользователь выбрал кнопку Cancel (или нажал Esc), то выполняется оператор в строках 22-23, отображая окно сообщения, информирующее пользователя о том, что преобразование в шаблон было отменено. Иначе — оператор в строках 25-26 вызывает метод SaveAs, сохраняя активную рабочую книгу как Excel-шаблонный файл.
Необходимо помнить, что и GetOpenFilename, и GetSaveAsFilename могут изменять текущий диск и папку. Можно использовать функцию CurDir для получения текущего диска и папки и сохранять результат в переменной, чтобы можно было переключаться снова на текущий диск и папку с помощью ChDrive и ChDir (описываются далее в этой главе).
Рис. 13.6
Процедура /
ConvTemplate использует метод GetSaveAsFilename для отображения этого диалогового окна
Управление файлами с помощью VBA
319
Использование встроенных диалоговых окон Word для получения имен файлов
Word не имеет тех же самых методов GetOpenFilename и GetSaveAsFilename, которые предоставляет Excel. Однако Word позволяет использовать VBA для отображения любых встроенных диалоговых окон — это те же самые диалоговые окна, которые отображаются, когда Word используется интерактивно. Можно, следовательно, применять собственные окна Word Открытие документа и Сохранение документа (Save As) в коде VBA для получения имен файлов от пользователя.
Использование встроенных диалоговых окон Word для получения имени файла от пользователя немного сложнее, чем использование Excel-методов GetOpenFilename и GetSaveAsFilename. Встроенные диалоговые окна Word доступны посредством свойства Dialogs Word-объекта Application. Свойство Dialogs возвращает коллекцию встроенных диалоговых окон Word. Для указания необходимого диалогового окна используются различные предопределенные константы Word (каждая из которых обозначается как wdDialog с последующим именем диалогового окна). Предопределенная Word-константа wdDialogFileopen определяет Word-диалоговое окно Open, а константа wdDialogFileSaveAs — диалоговое окно Сохранение документа.
Для ссылки на одно из встроенных окон Word необходимо использовать следующий синтаксис:
СИНТАКСИС
Object.Dialogs(wdDialogConstant)
Здесь object — объектная ссылка на Word-объект Application, которая является обязательной; wdDialogConstant — любая из предопределенных констант Word, которые определяют конкретное встроенное диалоговое окно.
Для просмотра списка констант, предопределенных для Word, и разделов справочной системы для этих констант используйте окно Object Browser. Word предоставляет более сотни констант — слишком много для подробного обсуждения в этой книге.
Для управления встроенными окнами Word необходимо сначала сослаться на конкретное диалоговое окно, которое будет использоваться, а затем вывести его на экран с помощью метода Display объекта Dialog. Метод Display отображает диалоговое окно; когда пользователь закрывает диалоговое окно, можно находить выбор пользователя из свойств объекта Dialog. При желании можно также задавать значения по умолчанию для установок диалогового окна, задавая свойства объекта Dialog перед отображением этого окна на экране.
Два наиболее важных свойства для диалоговых окон, определяемых константами wdDialogFileOpen и wdDialogFileSaveAs, являются также единственными общими для этих окон свойствами: Name и Format.
Свойство Name — это строка, сохраняющая имя файла, которое пользователь выбрал в окне Открытие документа или в окне Сохранение документа. Можно также предлагать имя файла в текстовом окне File Name (Имя файла) диалоговых окон Открытие документа и Сохранение документа, присваивая значение свойству Name перед отображением этих диалоговых окон. Свойство Format указывает, какой тип документа открывается или сохраняется: документ или шаблон. Свойство Format может содержать значение одной из двух Word-констант типа файла: wdTypeDo-cument и wdTypeTemplate.
В целях сбора информации от пользователя для процедур VBA используйте метод Display объекта Dialog. Метод Display возвращает значение, указывающее,
320
Глава 13
закрыл ли пользователь диалоговое окно щелчком кнопки Открыть, кнопки Отмена. В табл. 13.3 приведены возвращаемые значения метода Display и поясняется их смысл.	,	,	>
Таблица 13.3. Возвращаемые значения метода Display
Числовое значение	Что означает
-2	Диалоговое окно было закрыто с помощью кнопки Отмена.
-1	Диалоговое окно было закрыто щелчком кнопки Открыть в диалоговых окнах wdDialogFileOpen и wdDialogFileSaveAs).
0	Диалоговое окно было отменено.
> 0	Командная кнопка; 1 — для первой командной кнопки, 2 — для второй и так далее.
Теперь, когда вы понимаете основы использования Word-встроенных диалоговых окон Открытие документа и Сохранение документа, можно рассмотреть некоторые конкретные примеры работы этих окон.
Использование Word-диалогового окна Открытие документа
В листинге 13.7 показана процедура, использующая Word-встроенное диалоговое окно Открытие документа для получения имени файла документа от пользователя. Процедура открывает документ и помещает курсор в конец документа.
	Листинг 13.7. Использование Word-встроенного диалогового окна wdDialogFileOpen для получения имени файла
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27	Sub OpenWordFile() ' открывает указанный документ и перемещает ' указатель вставки в конец документа Const iTitle = "Открытие файла" Dim fName As String Dim IRetVal As Long With Application.Dialogs(wdDialogFileOpen) IRetVal = .Display	, fName = .Name End With	"	* If IRetVal <> -1 Then MsgBox prompt:^"Операция отменена", _ Title:=iTitle Exit Sub End If Documents.Open FileName:=fName Selection.EndKey unit:=wdStory MsgBox prompt:="Документ	& fName & _ открыт", _	; Title:=iTitle & " завершено" End Sub
Управление файлами с помощью VBA
321
Процедура OpenWordFile использует только одну константу — iTitle — в качестве заголовков диалоговых окон, отображаемых этой процедурой (заголовок диалогового окна Open изменить невозможно). В строках 7 и 8 объявляются переменные, используемые процедурой: fName используется для сохранения имени файла, введенного пользователем, a IRetVal — для сохранения результата метода Display, чтобы процедура могла определить, отменил пользователь или закрыл диалоговое окно Word, не делая выбора.
В строке 10 производится ссылка на диалоговое окно Открытие документа, а строке 11 используется метод Display объекта Dialog для вывода на экран этого окна. В результате отображается диалоговое окно, показанное на рис. 13.7. Это окно идентично во всех отношениях окну, отображаемому Word, когда выбирается команда Файл | Открыть (File | Open).
Рис. 13.7
Word-диалоговое окно Открытие документа, отображаемое оператором в строке 11 листинга 13 7
Выполнение процедуры OpenWordFile приостанавливается на то время, пока открыто диалоговое окно; после закрытия окна Открытие документа (пользователем) значение, возвращаемое методом Display, сохраняется в IRetVal и выполнение кода возобновляется со строки 12. В этот момент свойство Name диалогового окна содержит имя файла, выбранное пользователем (или строку нулевой длины, если пользователь не выбрал имя файла). В строке 12 значение свойства Name диалогового окна сохраняется в fName.
В строках 15-19 оператор If оценивает возвращаемый методом Display результат, который был сохранен в переменной IRetVal. Значение —1 указывает, что диалоговое окно было закрыто щелчком на кнопке Открыть (или эквивалентным действием, таким как двойной щелчок на имени файла). Если окно не было закрыто щелчком на кнопке Открыть или ее эквиваленте, то отображается сообщение о том, что операция была отменена, иначе — выполнение кода продолжается со строки 21.
В строке 21 выбранный файл открывается, а в строке 22 курсор помещается в конец документа. Наконец, в строках 24-26 отображается сообщение об успешном завершении операции.
Использование Word-диалогового окна
Сохранение документа
В листинге 13.8 показана процедура, использующая Word-встроенное диалоговое окно Сохранение документа (Save As) для получения имени файла документа от пользователя, предлагающее формат шаблона документа для файла, который должен быть сохранен. Затем процедура сохраняет документ как .dot-шаблон.
11 Программирование на VBA 2002
322
Глава 13
Листинг 13.8. Использование Word-встроенного диалогового окна wdDialogFileSaveAs для получения имени файла
1	Sub ConvWordTemplate()
2	' сохраняет текущий документ как файл шаблона
3
4	Const iTitle = "Преобразовать документ в шаблон"
5	Static sName As String	•
6	Static TCount As Variant
7
8	Dim iNameas As String
9	Dim IRetVal As Long
10
11	If IsEmpty(TCount) Then
12	TCount = 1
' 13	Else
14	TCount = TCount + 1
15	End If
16
17	sName = "Temp" & CStr(TCount) & ".dot"
18	ж With Application.Dialogs(WdDialogFileSaveAs)
19	.Name =	sName
20	.Format	= wdTypeTemplate
21	IRetVal	= .Display
22	iName =	.Name
23	End With
24
25	If IRetVal о -1 Then
26	MsgBox prompt:“"Преобразование отменено", _
27	Title:“iTitle
28	Else	f
29	ActiveDocument.SaveAs FileName:“iName, _
30	fileformat:“wdTypeTemplate
31	End If
32	End Sub
Процедура ConvWordTemplate сохраняет текущий документ как шаблонный Word-файл и использует диалоговое окно Сохранение документа для получения имени нового шаблонного файла.
В строках 11-17 устанавливается счетчик шаблонных файлов и формируется предлагаемое имя файла. В строке 18 начинается оператор With, который ссылается на диалоговый объект Application.Dialogs(wdDialogFileSaveAs), то есть диалоговое окно, отображаемое Word, когда выбирается команда Файл | Сохранить как (File | Save As).
В строках 19 и 20 устанавливаются некоторые предлагаемые умолчания для окна Сохранение документа. В строке 19 задается свойство Name диалогового окна, чтобы оно содержало предлагаемое имя файла шаблона (в sName). В строке 20 устанавливается свойство Format диалогового окна на wdTypeTemplate, это приводит к тому, что в диалоговом окне Сохранение документа в списке Тип файла (Save as type) выбирается тип файла Шаблон документа (Document Template) в качестве типа по умолчанию.
При выполнении оператора в строке 21 VBA отображает диалоговое окно, показанное на рис. 13.8. Заметьте, что это окно точно такое же, как Word-диалоговое окно Сохранение документа. Как только пользователь делает выбор в окне Сохранение документа, возвращаемое значение метода Display сохраняется в IRetVal и выполнение кода продолжается со строки 22, где выбранное пользователем имя файла (из свойства Name диалогового окна) помещается в iName.
В строках 29-30 документ сохраняется с использованием имени файла (в iName) и формата файла (wdTypeTemplate).
Управление файлами с помощью VBA
323
Рис. 13.8
Word-диалоговое окно, отображаемое оператором в строке 21 листинге 13 8
Работа с дисками и папками
В этом разделе рассматривается, как использовать функции и операторы VBA • для нахождения текущего диска и папки, как изменять текущий диск или папку и как создавать или удалять подпапки. Помните, текущий диск (current drive) — это диск, который использует Word или Excel, когда не указывается определенная буквенная метка диска. Аналогично, текущая папка (current folder) — это папка диска, которую Excel (или Word) использует, если не указывается определенная папка.
Получение пути текущей папки и буквенной метки диска
Выборка текущего диска и пути папки довольно проста. Обе части информации можно получить, используя функцию CurDir. CurDir возвращает строку, которая содержит полный путь текущей папки, включая буквенную метку диска. (CurDir является аббревиатурой слов current directory, помните, что папка и каталог — это одно и то же.)
Функция CurDir имеет следующий синтаксис:
СИНТАКСИС
CurDir[(drive)]
Здесь drive представляет любое выражение типа String и указывает функции CurDir, текущая папка какого диска необходима пользователю. Если аргумент drive опущен, CurDir возвращает текущую папку текущего диска. Обычно drive содержит только одну букву; если пользователь передает строку с несколькими символами, CurDir использует первый символ строки как буквенную метку диска.
В листинге 13.9 показан пример использования функции CurDir.
Листинг 13.9. Использование функции CurDir для получения текущего каталога и диска
1	Sub ShowCurDriveDir()
2	' отображает текущий драйвер и каталог
3
4	Dim DirName As String 'для имени каталога
5	Dim DirLetter As String 'для буквы диска
6
и*
324
Глава 13
7	DirName = CurDir() 'получить текущую папку диска
8
9	' взять первый символ из DirName - буква диска:
10	DirLetter = Left(DirName, 1)
11
12	' вывод на экран:
13	MsgBox "Текущий драйвер: " & DirLetter & _
14	Chr(13) & "Текущий каталог: " & DirName »
15
16	' получить текущий каталог на драйвере С:
17	DirName = CurDir("C") '
18	MsgBox "Текущий каталог на драйвере С: " & _
19	DirName
20	End Sub
Наличие большого количества комментариев и простота синтаксиса функции CurDir, видимо, не требуют анализа данного листинга. В дополнение можно предложить один из возможных результатов работы процедуры на рис. 13.9.
Рис. 13.9
Такие окна могут получиться в результате работы кода из листинга 13.9
Microsoft Word
Текущий драйвер1 F
Текущий каталог: F \VB_books\VBA\Bce о УВА\Часть II Разработка приложенийVлава 13
Управление файлами с помощью VBA
Изменение текущей папки
Если вам необходимо, чтобы процедура VBA изменила текущую папку на какую-либо другую, используйте оператор ChDir. Если у вас есть опыт работы с DOS, вы поймете, что ChDir в VBA выполняет ту же задачу, что DOS-команды CHDIR и CD. (ChDir — это аббревиатура слов change directory).
Оператор ChDir имеет следующий синтаксис:
СИНТАКСИС
ChDir path
Аргумент path представляет любое выражение типа String, имеющее результатом допустимый путь папки; path может (необязательно) содержать буквенную метку диска. Если пользователь включает буквенную метку в аргумент path, ChDir изменяет текущую папку диска на указанную в path без изменения текущего диска.
В листинге 13.10 показан пример использования оператора ChDir.
Листинг 13.10. Использование ChDir 1 2 3
1 Sub Test_ChDir()
2 ’ демонстрирует оператор ChDir
3
Управление файлами с помощью VBA
325
4	Dim oldDir As String ' для текущего каталога
5
6	MsgBox "Текущий каталог: " & CurDir()
7
8	' сохранить текущий (старый) каталог:
9	oldDir = CurDirO
10
11	' изменить каталог:
12	ChDir "\Мои документы"
13
14	' вывести на экран новый	каталог:
15	MsgBox "Новый каталог:	"	&	CurDirO
16
17	1 вернуться к старому каталогу
18	ChDir oldDir
19	MsgBox "Текущий каталог: " & CurDirO
20
21 End Sub
Эта процедура, по всей видимости, также не нуждается в комментариях.
Изменение текущего диска
Для изменения текущего диска необходимо использовать оператор ChDrive. (ChDrive — это аббревиатура слов change drive.)
Оператор ChDrive имеет следующий синтаксис:
СИНТАКСИС
ChDrive drive
Аргумент drive — это любое выражение типа String, представляющее буквенную метку диска. Если drive содержит более одного символа, ChDrive использует только первый символ в строке для буквенной метки. Если для аргумента drive задается пустая строка, то текущий диск не изменяется. Если задается символ, не являющийся одной из букв от А до Z, VBA отображает runtime-ошибку. VBA отображает также runtime-ошибку, если задается буквенная метка для диска, которого фактически нет в данной компьютерной системе, хотя вы можете использовать буквенные метки дисков, соединенных с вашим компьютером через сеть.
В листинге 13.11 демонстрируется использование оператора ChDrive.
	Листинг 13.11. Использование ChDrive для изменения текущего диска
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15	Sub Test_ChDrive() Dim oldDir As String ' запомнить текущий (старый) каталог: oldDir = CurDirO ' выдать на экран текущий каталог: MsgBox "Текущий каталог: " & oldDir ' изменить драйвер на А: ChDrive "D" ' выдать на экран новый драйвер и каталог: MsgBox "Новый драйвер и каталог: " & CurDir
326
Глава 13
16	' восстановить старый драйвер (используется
17	' только первый	символ	строки, содержащий драйвер):
18	ChDrive oldDir
19
20	' восстановить	старый	каталог:
21	ChDir oldDir
22
23	MsgBox "Текущий каталог: " & CurDir ()	.
24	End Sub
Создание дисковых папок
Вам может понадобиться, чтобы одна из процедур создавала новую дисковую подпапку для сохранения в ней новых файлов рабочей книги или документа или по каким-либо другим причинам. Для создания дисковой папки используйте оператор MkDir. Оператор MkDir выполняет ту же задачу, что DOS-команды MKDIR или MD или команда WINDOWS File | New | Folder (Файл | Создать | Папка). (MkDir — это аббревиатура слов make directory.)
Оператор MkDir имеет следующий синтаксис:
СИНТАКСИС
MkDir path
Аргумент path представляет любое выражение типа String, которое имеет результатом допустимый путь папки; path может (необязательно) содержать буквенную метку диска. Если буквенная метка диска не включена в аргумент path, MkDir создает новую папку на текущем диске. Если path указывает имеющуюся уже папку или включает недопустимые символы имени файла, VBA отображает сообщение о runtime-ошибке. При попытке создать подпапку в папке, которой не существует, VBA также отображает сообщение о runtime-ошибке. Использование MkDir не изменяет текущего диска или папки.
В листинге 13.12 показан пример использования оператора MkDir, не требующий никакого анализа.
Листинг 13.12. Использование MkDir для создания нового дискового каталога
1	Sub Test_MkDir()
2	' демонстрирует оператор MkDir
3
4	Dim newDir As String
5
.6	' новый (будущий) каталог:
7	newDir = "A:\testl"
8
9	' создать новый каталог:
10	MkDir newDir
11
12	' перейти к новому	(только что созданному) каталогу:
13	ChDir newDir
14
15	' проверить результат перехода к	новому	каталогу:
16	MsgBox "Текущий каталог драйвера	А: " &	CurDir("А")
17	End Sub
Перед запуском этой процедуры убедитесь, что в дисководе А: имеется диск, иначе VBA отобразит сообщение о runtime-ошибке.
Управление файлами с помощью VBA
327
Удаление дисковых папок
Вам может понадобиться также, чтобы одна из процедур удаляла дисковую подпапку. Для удаления дисковой папки используйте оператор RmDir. Оператор RmDir выполняет ту же задачу, что и DOS-команды RMDIR или RD; в Windows используется команда File | Delete (Файл | Удалить) для удаления как файлов, так и папок. (RmDir — это аббревиатура слов remove directory.)
Оператор RmDir имеет следующий синтаксис:
СИНТАКСИС
RmDir path
Аргумент path представляет любое выражение String, имеющее результатом допустимый путь папки; path может (необязательно) содержать буквенную метку диска. Если буквенная метка не включена в аргумент path, RmDir удаляет папку на текущем диске. Если path определяет папку, которая еще не существует, или включает недопустимые символы имени файла, то VBA отображает сообщение о runtime-ошибке.
В листинге 13.13 показан простой пример использования оператора RmDir.
Листинг 13.13. Использование RmDir для удаления папки
1	Sub Test_RmDir()
2	' демонстрирует оператор RmDir
3
4	Dim delDir As String
5
6	' имя удаляемой папки:	l
7	delDir = "A:\testl"
8
9	' если удаляемая папка - текущая, перейти
10	' в корневую; НЕЛЬЗЯ УДАЛЯТЬ	ТЕКУЩУЮ	ПАПКУ
11	If CurDir("A") = delDir Then	ChDir	"A:\"
12
13	' удалить папку A:\testl
14	RmDir delDir
15
16	End Sub
Предполагается, что была выполнена процедура в листинге 13.12 для создания папки Testi для диска А:. Если текущая папка диска А: является той же папкой, которая должна быть удалена, то в строке 11 вызывается функция ChDir для изменения текущей папки диска А: на корневую папку. Нельзя удалять дисковую папку, если она является текущей или непустой.
Копирование и удаление файлов
Копирование и удаление файлов — это, вероятно, две наиболее часто выполняемые операции по управлению файлами. В этом разделе описывается, как можно копировать или удалять файлы под контролем процедур VBA.
Копирование файлов
Для копирования файла используйте оператор FileCopy. Этот оператор VBA эквивалентен DOS-команде COPY или команде File | Сору (Файл | Копировать) в Windows.
328
Глава 13
Оператор FileCopy имеет следующий синтаксис:
СИНТАКСИС
FileCopy source, destination
Как source, так и destination являются выражениями типа String, имеющие результатом допустимые имена файла. Они могут (необязательно) включать полный путь папки и буквенную метку диска. При попытке копировать файл в самого себя VBA выдает runtime-ошибку. VBA также выдает runtime-ошибку при попытке копировать файл, когда нет достаточного дискового пространства для сохранения копируемого файла.
В листинге 13.14 используется оператор FileCopy. Процедуру следует тестировать в Excel, так как она использует методы GetOpenFilename и GetSaveAsFilename.
Листинг 13.14. Процедура, использующая оператор FileCopy
1	Sub TestCopyFiles()
2	' копирует файл, указанный пользователем, в файл
3	' с новым именем, драйвером или каталогом
4	/
5	Dim	sName	As	String
6	Dim	dName	As	String
7
8	Do
9	With Application
10	sName = .GetOpenFilename(Title:= _
11	'	"File Copy - Source")
12
13	If sName = "False" Then Exit Sub
14
15	dName = .GetSaveAsFilename(Title:= _
16	"File Copy - Destination")
17
18	If dName = "False" Then Exit Sub
19
20	End With
21
22	FileCopy Source:=sName, Destination:=dName
23
24	Loop
25
26	End Sub
Эта процедура дает возможность пользователю выбирать файл-источник, диск, папку и имя файла-приемника, в который будет осуществляться копирование (иногда называют целевым). В строках 5 и 6 объявляются две переменные типа String для имен исходного и целевого файлов. В строке 8 начинается бесконечный цикл Do (цикл без детерминантного условия). Цикл в строках 8-24 выполняется до тех пор, пока пользователь не отменит одно из двух файловых диалоговых окон. В строке 9 начинается оператор With. В строках 10-11 содержится один оператор, вызывающий метод GetOpenFilename для отображения диалогового окна открытия файла и присваивающий имя файла (результат метода) переменной sName.
В строке 13 оператор проверяет, отменил ли пользователь диалоговое окно открытия файла. Если — да, процедура заканчивается. Иначе VBA выполняет оператор в строках 15 и 16, который использует метод GetSaveAsFilename, чтобы дать возможность пользователю выбрать имя файла, диск и папку для копируемо
Управление файлами с помощью VBA
329
го файла. В строке 18 проверяется, отменил ли пользователь диалоговое окно открытия файла. Если — да, выполнение процедуры прекращается. Иначе VBA продолжает выполнять код с оператора FileCopy в строке 22.
Когда VBA выполняет оператор FileCopy в строке 22, файл (имя которого сохранено в sName) копируется с новым именем на новый диск и в новую папку, сохраненные в dName. После копирования файла цикл Do повторяется.
Удаление файла
Для удаления файла используйте оператор с драматическим именем Kill. Оператор Kill выполняет ту же задачу, что DOS-команда DEL или команда File | Delete (Файл | Удалить) в Windows.
Оператор Kill имеет следующий синтаксис:
СИНТАКСИС
Kill pathname
Аргумент pathname — это любое выражение типа String, имеющее результатом допустимую спецификацию имени файла; pathname может включать буквенную метку диска, полный путь папки и символы универсального сопоставления (* и ?). Если pathname включает символы универсального сопоставления, Kill удаляет все файлы, совпадающие со спецификацией в pathname.
В листинге 13.15 показан пример оператора Kill.
Листинг 13.15. Использование Kill для удаления файлов
1	Sub Test_KillFiles()
2	' удаляет файлы, пока пользователь не отменит диалог
3
4	Dim	fName As String
5	Dim	Ans As Integer
6
1	Do
8
9	fName = Application.GetOpenFilename(Title:= _
10	"Delete File")
11
12	If fName = "False" Then Exit Sub
13
14	Ans = MsgBox(prompt:="Delete " & fName & "?",
15	Title:="Delete File", _
16	Buttons:=vbQuestion + vbYesNo)
17
18	If Ans = vbYes Then
19	Kill fName
20	End If
21
22	Loop
23	End Sub
Эта процедура использует метод GetOpenFilename, дающий возможность пользователю выбрать имя файла, подтверждает удаление, удаляет файл. Эти действия повторяются в цикле.
В строке 7 начинается бесконечный цикл Do, который выполняется до тех пор, пока пользователь не отменит файловое диалоговое окно. В строке 9 вызывается метод GetOpenFilename и его результат присваивается переменной fName.
330
Глава 13
В строке 12 проверяется, отменил ли пользователь файловое диалоговое окно, и процедура завершается, если пользователь его отменил. В строках 14-16 содержится оператор MsgBox, запрашивающий пользователя подтвердить удаление выбранного файла. Если пользователь подтверждает удаление, VBA выполняет оператор Kill (в строке 19), который удаляет файл.
Не следует пытаться удалить файл открытой рабочей книги или документа, в таком случае VBA выдает runtime-ошибку. Проверяйте атрибуты файла перед попыткой удалить его. При попытке удалить файл, имеющий какой-либо из атрибутов Hidden, System или Read-Only VBA выдает runtime-ошибку. Используйте функцию GetAttr для выборки атрибутов файла и оператор SetAttr — для их изменения при необходимости удалять файлы с атрибутами Hidden, System или Read-Only.
Переименование или перемещение файлов
Вам может понадобиться изменить имя файла или переместить файл в другую папку на том же диске. Для переименования файла или перемещения его в другую папку используйте оператор Name.
Оператор Name имеет следующий синтаксис:
СИНТАКСИС
Name oldpathname As newpathame
Аргументы oldpathname и newpathname — это выражения типа String, имеющие результатом допустимые имена файлов. Оба могут (необязательно) содержать полный путь папки, включая буквенную метку диска. Если пользователь включает буквенную метку, оба выражения oldpathname и newpathname должны включать одну и ту же буквенную метку диска, иначе VBA выдает runtime-ошибку. Если oldpathname и newpathname ссылаются на разные папки, VBA перемещает файл в новую папку и изменяет его имя.
В листинге 13.16 показана процедура, использующая оператор Name для переименования файлов.
Листинг 13.16. Использование Name для переименования или перемещения файлов
1	Sub Test_RenameOrMoveFile()
2	' переименовывает или перемещает файл
3
4	Const iTitle = "Переименовать или удалить - "
5	Dim oldName As String
6	Dim newName As String
1	Dim oldDir As String
8
9	oldDir = CurDir()
10	With Application
11	oldName = .GetOpenFilename(Title:=iTitle & "Источник")
12	If oldName = "False" Then Exit Sub
13
14	newName = .GetSaveAsFilename(InitialFilename:=oldName,
15	Title:=iTitle & "Новое имя")
16	If newName = "False" Then Exit Sub
17	End With
18
19	If Left(oldName, 1) = Left(newName, 1) Then
20	Name oldName As newName
Управление файлами с помощью VBA
331
21	Else
22	FileCopy oldName, newName
23	Kill oldName
24	End If
25
26	ChDrive	oldDir
27	ChDir oldDir
28	End Sub
Эта процедура переименовывает или перемещает файлы. Пользователь процедуры выбирает имя файла, папку и диск для оригинального файла и для нового имени и/или местоположения.
В строке 9 вызывается функция CurDir, результат которой сохраняется в переменной oldDir. В строке 10 начинается оператор With для объекта Application. В строке 11 используется метод GetOpenFilename для того, чтобы пользователь мог выбрать файл, который будет переименован или перемещен. В строке 12 используется оператор If для проверки того, отменил ли пользователь диалоговое окно GetOpenFilename; если — да, то процедура прекращается.
В строке 14 вызывается метод GetSaveAsFilename для того, чтобы пользователь мог выбрать новое имя файла, диск и папку. Заметьте, что этот вызов GetSaveasFilename использует аргумент InitialFilename для заполнения предлагаемого нового имени файла. В строке 16 проверяется, отменил ли пользователь это диалоговое окно, и, если отменил, процедура заканчивается.
В строке 19 начинается оператор If...Then...Else, который проверяет, выбрал ли пользователь другой диск для перемещения на него файла. Логическое выражение для оператора If в строке 19 использует функцию Left для возвращения первой буквы строк oldName и newName. Если эти две буквы одинаковые, то пользователь переименовывает или перемещает файл на том же самом диске и VBA выполняет оператор Name в строке 20 для переименования файла. Если пути папок в oldName и newName различны, Name перемещает файл в новую папку.
Если первые буквы oldName и newName различные, то пользователь выбрал перемещение файла на другой диск. Нельзя использовать Name для перемещения файлов на другой диск, поэтому процедура использует FileCopy для копирования файла на другой диск и затем использует Kill для удаления оригинального файла.
Наконец, операторы ChDrive и ChDir восстанавливают оригинальный диск и папку, которые были текущими при запуске процедуры. (Помните, методы GetOpenFilename Get Save AsFilename могут'изменить текущий диск и папку.)
Получение информации о файлах
Иногда бывает важно знать размер файла или дату и время, когда файл был модифицирован последний раз. Например, имея процедуру, резервирующую файлы рабочей книги, можно написать ее так, чтобы она проверяла, не заменяет ли она более недавний файл более старой версией.
Получение времени и даты создания/модификации файла
Всякий раз, когда одна из программ приложения, такая как Word или Excel, изменяет дисковый файл, файловая система Windows записывает дату и время (в соответствии с часами данной компьютерной системы) с файлом, чтобы можно было определить, когда этот файл был модифицирован последний раз. Чтобы сделать эту информацию доступной в процедурах VBA, используйте функцию File-DateTime. Эта функция возвращает информацию о дате и времени из файла как VBA-значение типа Date.
332
Глава 13
Функция FileDateTime имеет следующий синтаксис:
СИНТАКСИС
FiledateTime (pathname1 11)
Аргумент pathname — это любое выражение типа String, имеющее результатом допустимую спецификацию файла; pathname может цеобязательно включать буквенную метку диска и полный путь папки, но не может содержать символы универсального сопоставления (* или ?).
В листинге 13.17 в следующем разделе показан пример, использующий функцию FileDateTime.
Получение длины файла
Для того чтобы определить длину файла, используйте функцию FileLen. FileLen возвращает длину файла в байтах.
Функция FileLen имеет следующий синтаксис:
СИНТАКСИС
FileLen(pathname)
Аргумент pathname — это выражение типа String, имеющее результатом допустимую спецификацию имени файла; pathname может (необязательно) включать буквенную метку диска и полный путь папки, но не может включать символы универсального сопоставления. Если pathname определяет открытый файл, FileLen возвращает размер файла, каким он был, когда файл был сохранен на диске последний раз.
В листинге 13.17 показан пример, использующий функцию FileLen, а на рис. 13.10 — один из возможных результатов работы кода этого листинга.
Листинг 13.17. Использование функций FileDateTime и FileLen
1 Sub ShowFDS(sName As String)
2 ' отображает размер и дату последней модификации файла
3
4	Dim msgl As String
5	Dim msg2 As String
6 Dim fDate As Date	‘	,
7	Dim fLen As Long
8
9	fDate = FileDateTime(sName)
10	fLen = FileLen(sName)
11 msgl = "Размер: " & Format(fLen, "###,###,###") &
12	"байт."
13	msg2 = "Последняя модификация: " & _
14	Format(fDate, "long date") & _
15	" в " & Format(fDate, "long time")
16 MsgBox Т1Д1е:="Дата и размер файла", _
17	prompt:=sName & Chr(13) & _
18	msgl & Chr(13) & msg2
19 End Sub
20
21 Sub Test_ShowFDS()
22	Dim sName As String
23
24	Do
Управление файлами с помощью VBA
333
25	With Application
26	sName = .GetOpenFilename(Title:="Дата/Размер файла")
27	End With
28	If sName <> "False"	Then ShowFDS sName
29	Loop Until sName = "False"
30	End Sub
Процедура ShowFDS использует функции FileLen и FileDateTime для отображения окна сообщения, показывающего текущий размер файла и дату и время, когда этот файл модифицировался последний раз. ShowFDS имеет единственный аргумент fName типа String, используемый для указания процедуре ShowFDS., информация о каком файле должна быть отображена.
Рис. 13.10
Процедура ShowFDS использует функции FileLen и FileDateTime для сбора информации о размере файла и о том, когда он был модифицирован последний раз
Дата и размер файла
E:\Documents and Settings'Ll ладимир\Му Documents\Chapterl0.doc
Размер: 987,1366айт.
Последняя модификация: Sunday, January 26, 2003 в 12:45:10 РМ
I 6k
В строках 4-7 объявляется несколько переменных этой процедуры. Первые две переменные (msgl и msg2) используются для формирования текста сообщения, отображаемого процедурой. Переменные fDate и fLen используются для сохранения информации о дате и времени и информации о размере файла, соответственно. Заметьте, что fLen имеет тип Long, потому что длина файла может исчисляться миллионами байт.
В строке 9 вызывается функция FileDateTime с аргументом sName в качестве имени файла, а результат функции сохраняется в fDate. В строке 10 вызывается функция FileLen также с использованием sName для определения аргумента имени файла, а результат этой функции сохраняется в fLen.
В строках 11 и 12 содержится один оператор, который формирует первую часть сообщения, отображаемого этой процедурой, и сохраняет ее в msgl. В строках 13-15 содержится также один оператор, который формирует вторую часть сообщения, отображаемого этой процедурой, и сохраняет ее в msg2. Наконец, оператор MsgBox в строках 16-18 отображает имя файла, его размер и дату и время, когда этот файл модифицировался последний раз.
В строках 21-30 содержится процедура, тестирующая процедуру ShowFDS. Эта процедура использует метод GetOpenFilename, чтобы пользователь мог выбрать файл, а затем вызывает процедуру ShowFDS.
Глава 14
Элементы диалоговых окон
До сих пор вы учились использовать диалоговые окна, которые встроены в VBA, а именно, функции MsgBox и InputBox. Хотя MsgBox и InputBox придают вашим программам гибкость, которой могут обладать только интерактивные программы, их возможности в известной степени ограничены. При разработке более сложных программ вы захотите выводить диалоговые окна, которые дают возможность пользователям ваших программ задавать при помощи одного диалогового окна сразу несколько опций, выбирать пункты из списка или вводить в одном окне несколько значений подобно тому, как это можно делать с помощью диалоговых окон, выводимых Word, Excel и другими приложениями Windows. Часто у вас будет возникать необходимость вместо встроенных окон, принадлежащих Word или Excel, использовать диалоговые окна, созданные специально для вашей программы.
VBA позволяет создавать и применять пользовательские1 диалоговые окна в написанных вами программах и процедурах при помощи добавления в проект объекта UserForm. Используя VBA-формы пользователя (VBA User Forms), вы можете создавать диалоговые окна для вывода данных или получения значений от пользователя вашей программы именно в том виде, который требуется вашей программе. Например, вы можете вывести на экран диалоговое окно со списком различных вариантов формата даты и предоставить пользователю возможность выбрать из списка один из форматов.
Диалоговые окна позволяют вашей программе общаться с пользователем наиболее удобным образом, обеспечивая гибкую форму ввода и вывода данных. Из этой главы вы узнаете об основных элементах диалоговых окон и их свойствах, научитесь создавать простые диалоговые окна.
Формы пользователя
Диалоговое окно в VBA создается добавлением в проект объекта UserForm. Объект UserForm — это пустое диалоговое окно. Настройку диалогового окна можно выполнить добавлением к объекту UserForm (обычно называют просто фор ма) элементов управления. Каждому объекту UserForm присущи определенные свойства, методы и события, которые он наследует от класса объектов UserForm. Каждый объект UserForm включает в себя также модуль класса, в который вы можете добавлять собственные методы и свойства или код обработки событий формы.
Первый шаг в создании пользовательского диалогового окна состоит в добавлении к проекту новой формы (объекта UserForm). Форма содержит рабочую область, в которую вы можете поместить элементы, необходимые для выполнения некоторого диалога пользователя с приложением. Поскольку объекты UserForm хранятся в коллекции UserForms проекта, они являются частью проекта.
Для добавления к проекту новой формы используйте команду VB-редактора Insert | UserForm (Вставка | UserForm). Редактор VB добавляет к текущему проекту новую форму, присваивая ей по умолчанию имя UserFormN и используя ту же систему нумерации, что и для модулей. Редактор VB выводит новую форму в режи ме разработки, как показано на рис. 14.1. [В режиме разработки вы можете добавлять (или удалять) элементы управления к форме, устанавливать свойства формы
1
В переводной литературе встречается термин «настраиваемые) (от анг custom)
Элементы диалоговых окон
335
или ее элементов управления и выполнять другие манипуляции с внешним видом формы в интерактивном режиме. Когда форма выведена и используется как часть выполняющейся программы, она находится в режиме выполнения.]
На рис. 14.1 показана добавленная в проект форма UserForml. Заметим, что широкая рамка вокруг формы указывает на то, что форма выделена. Обратите внимание на сетку из точек на поверхности формы и панель элементов (Toolbox). Сетка из точек помогает выравнивать и контролировать размеры элементов управления, помещаемых на форму, и появляется только в режиме разработки. Панель элементов является «палитрой», с помощью которой вы можете выбирать элементы управления и добавлять их к форме. Панель, как правило, появляется только в том случае, если выбрана форма и ни один из ее элементов управления.
Вы можете переименовать объект UserForm так же, как стандартный модуль или модуль класса. Для этого отредактируйте в Properties Window (окно свойств) свойство Name этого объекта.
Не оставляйте вновь созданной форме имя, присвоенное ей по умолчанию, например UserForml или UserForm2. Напротив, переименовывайте новую форму сразу, как только ее создали.
Когда форма выводится на экран в режиме разработки, вы можете протестировать ее поведение, используя команду Run | Run Sub/UserForm (Запуск | Запуск под-программы/UserForm). После этого редактор VB выведет форму в режиме выполнения и все ее элементы управления будут активными. Однако следует помнить, что любой код, используемый формой, хранящийся не в модуле класса формы, не может быть инициализирован. При запуске формы инициализируется только код, находящийся в модуле класса формы. Переменные в стандартных модулях необязательно будут инициализироваться. В результате этого, если форма не является полностью независимой, некоторые из программ связанных с ней, могут не выполняться, выдавая сообщения о различных runtime-ошибках.
Рис 141
Новая UserForm в режиме разработки
Свойства объекта UserForm
Форма как объект имеет некоторые встроенные свойства, и вы можете устанавливать эти свойства или программным образом, или в Properties Window (окне свойств) редактора VB. Строго говоря, данные способы изменения свойств форм не являются эквивалентными. Некоторые из свойств могут быть установлены только посредством Properties Window. Программным способом свойства форм устанавливаются таким же образом, как и свойства других объектов: путем присвоения
336
Глава 14
свойству нового значения. В Таблице 14.1 перечислены свойства UserForm, на которые вам, скорее всего, придется ссылаться или изменять их.
Таблица 14.1. Наиболее часто используемые свойства объектов UserForm
I Свойство	Описание
| ActiveControl	Возвращает объектную ссылку на элемент управления, находящийся в фокусе в данный момент. Только для чтения.
BackColor	Целое типа Long определяет цвет фона формы. Самый простой способ установить это свойство — использовать Properties Window; чтобы выбрать желаемый цвет (если необходимо), можно скопировать номер цвета из Properties Window в свою программу.
Caption	Текст, выводимый в качестве заголовка формы. Запись/Чтение.
Controls	Возвращает коллекцию всех элементов управления формы. Только для чтения.
Cycle	Определяет, должно ли нажатие клавиши табуляции вызывать последовательный выбор всех элементов управления во всех группах и на каждой странице многостраничных элементов управления или только в пределах текущей группы или страницы. Может содержать одну из двух встроенных констант: fmCycleAUForms или fmCycleCurrentForm. Чтение/Запись.
Enabled	Содержит значение типа Boolean, указывающее, доступна ли форма. Если его значение равно False, ни один из элементов управления формы не доступен. Чтение/Запись.
Font	Возвращает ссылку на объект Font, посредством которого вы можете выбрать параметры шрифта формы или элемента управления.
ForeColor	То же самое, что и свойство BackColor, но устанавливает цвет используемый для переднего плана (обычно — это цвет текста) объекта формы.
Методы объекта UserForm
Всякий раз создавая в проекте новый объект UserForm, вы создаете новый подкласс объекта UserForm. Любые процедуры или функции, написанные вами в разделе General (общий) модуля класса, относящегося к форме, становятся дополнительными методами для отдельного подкласса объекта. Вы также можете создать для формы новые свойства, добавив в ее модуль класса процедуры Property Get и Property Let. Вы можете создавать экземпляры подкласса вашей UserForm с помощью оператора Dim и ключевого слова New.
Однако чаще всего вы будете манипулировать объектом формы при помощи стандартных методов и свойств класса UserForm и при помощи собственных процедур обработки событий для определенной вами формы и ее элементов управления.
В табл. 14.2 перечислены наиболее часто используемые методы для объектов UserForm, которыми вы можете воспользоваться, и кратко изложены их свойства. Эти методы будут доступны для каждой формы, которую вы добавляете в свой проект.
Элементы диалоговых окон
337
Таблица 14.2. Наиболее часто используемые методы для объектов UserForm
Метод	Назначение
Сору	Копирует выделенный в элементе управления текст в буфер обмена Windows. .
Cut	Вырезает выделенный в элементе управления текст и помещает его в буфер обмена Windows.
Hide	Скрывает UserForm, не выгружая ее из памяти, сохраняя значения элементов управления формы и всех переменных, объявленных в модуле класса формы.
Paste	Вставляет содержимое буфера обмена Windows в текущий элемент управления.
PrintForm	Выводит на используемый в Windows по умолчанию принтер изображение формы, включая все данные, введенные в элементы управления.
Repaint	Перерисовывает форму, выведенную на экран. Используйте этот метод, если хотите перерисовать форму, не ожидая, когда она будет перерисована через обычный период времени.
Show	Выводит форму на экран. Если форма еще не загружена в память, то данный метод сначала ее загружает.
В этой главе при написании примеров процедур обработки событий нам понадобится метод Show. Поэтому рассмотрим его подробнее.
Синтаксис метода Show:
СИНТАКСИС
FormName.Show
В данной синтаксической конструкции FormName может быть любым объектом UserForm текущего проекта. FormName — имя формы в том виде, как оно отображается в Project Explorer. Например, если у вас есть форма frminsert Figure, вывести ее на экран можно с помощью оператора: frmlnsertFigure.Show
Если форма в данный момент не загружена в память, метод Show загрузит ее и выведет на экран. Если форма уже загружена, метод Show просто выведет ее на экран. В любом случае метод Show выводит форму и затем передает ей управление. Форма будет оставаться на экране до тех пор, пока или не будет выполнен метод Hide объекта UserForm, или форма не будет выгружена при помощи оператора Unload.
Все формы VBA являются модальными (modal) приложениями, это означает, что вы не сможете выполнить какое-либо другое действие в приложении до тех пор, пока форма диалога не будет закрыта или скрыта.
Когда VBA выполняет метод Show для отображения формы диалогового окна, процедура, содержащая вызов метода Show, приостанавливается до тех пор, пока выведенная форма не будет закрыта пользователем. Однако VBA будет выполнять программу для любых событийных процедур в модуле класса формы.
338
Глава 14
События и событийные процедуры
Событие (event) — это что-то, что может произойти с диалоговым окном или элементом управления диалогового окна. Типичные примеры событий: щелчок на кнопке, переключателе и т.д. Другие примеры событий: изменение содержимого окна редактирования или выбор элемента списка. Щелчок мышью, нажатие клавиши и действия внутренние для вашего компьютера, — все они запускают или, иными словами, влекут за собой события.
Использование событий позволяет создавать действительно диалоговые приложения. В таких приложениях все действия пользователя приводят к определенной реакции приложения, если эти действия предусмотрены и не заблокированы. Если вы хотите, чтобы ваши пользователи чувствовали себя комфортно при работе с вашими программами, начинайте создавать свои диалоговые окна с разработки событийных процедур.
Такие объекты, как формы и элементы управления приводят в действие, то есть делают доступными, некоторые события. Вы можете написать собственные VBA-процедуры, реагирующие на события. Такие процедуры, называются событийными процедурами (event procedures) или процедурами обработки событий.
Событийные процедуры следует записывать в модуль класса, который является частью UserForm. При этом такие процедуры должны иметь имена в виде ObjectName_EventName, где ObjectName — имя формы или элемента управления, a EventName — имя события, с которым вы хотите работать. Такой формат имени, позволяет VBA сопоставлять заданному событию требуемую процедуру.
Большая часть программы, которую вы записываете в модуль класса формы, будет связана с обработкой событий. В таблице 14.3 перечислены события, для которых вы можете написать процедуры обработки.
Таблица 14.3. События объектов UserForm
Событие	Синтаксис заголовка процедуры обработки события	Описание
Activate	Private Sub object _Activate()	Инициируется всякий раз, когда окно формы становится активным. Используйте это событие для обновления содержимого диалоговых элементов управления, чтобы отразить любые изменения, которые произошли, пока окно формы было неактивным.
Click	Private Sub object_C].ick(index As Long)	Инициируется всякий раз, когда по форме (любой ее части, не занятой элементами управления) щелкают мышью.
DblClick	Private Sub ofeject_DblClick(index As Long, By Vai Cancel As MSForms.ReturnBoolean)	Инициируется всякий раз, когда по форме (любой ее части, не занятой элементами управления) дважды щелкают мышью. *
Deactivate	Private Sub ob/ect_Deactivate()	Инициируется всякий раз, когда форма перестает быть активной.
Элементы диалоговых окон
339
Событие	Синтаксис заголовка процедуры обработки события	Описание
Initialize	Private Sub ofe/ect_Initialize() »	Инициируется всякий раз, когда форма впервые загружается в память посредством выполнения оператора Load или с помощью метода Show. Используйте это событие для инициализации элементов управления формы при ее появлении на экране.
Resize	Private Sub U serForm_Resiz e()	Инициируется при изменении размеров формы.
Terminate	Private Sub ofe/ect_Terminate()	Инициируется всякий раз, когда форма выгружается из памяти. Используйте это событие для осуществления любых специальных служебных задач, которые необходимо выполнить прежде, чем переменные формы будут выгружены.
В дополнение к методам, свойствам и событиям, встроенным в объект User-Form, VBA предоставляет два оператора, которые особенно полезны при работе с объектами форм: Load и Unload. Вы можете использовать эти операторы для того, чтобы или загрузить форму в память, или же удалить ее оттуда.
Синтаксис Load/Unload
Синтаксические конструкции для использования операторов Load и Unload выглядят следующим образом:
СИНТАКСИС
Load Object
Unload Object
Здесь Object представляет любую допустимую ссылку на объект UserForm.
Оператор Load загружает в память объект UserForm и запускает метод формы Initialize, но не выводит форму на экран. Когда форма загружена, вы можете использовать написанную на VBA программу для работы с объектом UserForm. Оператор Unload удаляет из памяти UserForm, а также все переменные формы. После того как форма выгружена, она перестает быть доступной для VBA-кода.
Примеры программ модуля класса формы
Рассмотрим несколько простых примеров использования свойств и методов формы с помощью процедур обработки событий. Будем инициировать события, описанные в табл. 14.3, а в ответ на них с помощью окна функции MsgBox будем сообщать о типе события или менять видимые свойства формы. Начнем с события Click, так как процедуру обработки этого события легче всего создать: достаточно дважды щелкнуть на форме (используем созданную в начале главы форму) в режиме разработки, и вам будет предоставлен шаблон процедуры в виде:
Private Sub UserForm_Click()
End Sub
340
Глава 14
Запишите после заголовка процедуры следующий оператор
MsgBox("Событие: Click")
Запустите форму на выполнение командой Run | Run Sub/UserForm. После появления формы на экране щелкните на ней мышью, на экране появится сообщение, подобное приведенному на рис. 14.2.
Рис. 14.2
Выполнение процедуры обработки события Click
Если даже вам не часто будет нужно использовать подобное событие для формы, не забывайте о такой возможности. А еще лучше поступайте следующим образом. Всегда используйте это событие на случай, когда пользователь ваших форм при попытке щелкнуть на каком либо элементе управления не совсем точно позиционирует курсор мыши. Если при этом будет выполняться процедура обработки события Click для формы с выводом шутливого сообщения о недостаточной уверенности в действиях пользователя, с вашим приложением станет приятно работать. Вы также никогда не забудете о возможности использовать это событие, когда для этого появятся серьезные причины.
Продолжим рассмотрение событий и протестируем событие Activate. Запишите в модуле рассматриваемой формы следующую процедуру:
Private Sub UserForm_Activate()
MsgBox ("Событие: Activate") End Sub
Снова запустите форму на выполнение командой Run | Run Sub/UserForm. После появления формы на экране вы увидите сообщение о том, что произошло событие Activate (рис. 14.3).
Рис. 14.3
Сразу после загрузки формы произошло событие Activate
Рассмотрим события Deactivate и Terminate. Первое из них инициируется всякий раз, когда форма перестает быть активной, а второе — когда форма выгружается из памяти. Процедура обработки события Terminate просто добавляется
Элементы диалоговых окон
341
к имеющейся коллекции программ формы UserForml и выполняется при завершении работы с формой. Для демонстрации же события Deactivate необходимо, не выходя из приложения, сделать форму UserForml неактивной. Это можно осуществить, если активной станет другая форма. И ее надо создать.
Создайте новую форму либо при помощи кнопки Insert UserForm, либо — командой Insert | UserForm. Пусть она имеет имя, которое ей присваивается по умолчанию: UserForm2. Помните, что следует всегда переименовывать формы для удобства сопровождения разработки, но для нашего тестирования событий мы этого делать не будем. Наметим план тестирования:
1.	Загружаем форму UserForml.
2.	Событие Click формы UserForml вызывает метод Show для загрузки формы UserForm2.
3.	Загрузка/выгрузка формы UserForm2 не сопровождаются никакими событиями.
4.	Форма UserForml имеет процедуры обработки событий: Click, Activate, Deactivate, Terminate.
Для выполнения поставленной задачи в модуль формы UserForml необходимо поместить код листинга 14.1.
Листинг 14.1. Процедуры событий UserForml
1	' Обработчик события Click формы UserForml
2	Private Sub UserForm_Click()
3	' Вывод окна сообщения на экран:
4	MsgBox ("Событие: Click. Выводим UserForm2")
5	1 Загрузка формы UserForm2:
6	UserForm2.Show
7	End Sub
8
9	' Обработчик события Activate формы UserForml
10 Private Sub UserForm Activated	
11	1 Вывод окна сообщения на экран:
12	MsgBox ("Событие: Activate для формы UserForml")
13	End Sub
14	
15	Private Sub UserForm Deactivated
16	' Вывод окна сообщения на экран:
17	MsgBox ("Событие: Deactivate для формы UserForml")
18	End Sub
19	
20	Private Sub UserForm Terminate()
21	' Вывод окна сообщения на экран:
22	MsgBox ("Событие: Terminate для формы UserForml")
23	End Sub
Следует отметить, что после создания новой формы, вы не сразу можете найти модуль формы UserForml. Ваш экран может быть похожим на тот, который приведен на рис. 14.4.
Выберите команду Run | Run Sub/UserForm. Теперь вы имеете возможность проследить за инициализацией всех четырех событий. Сразу после загрузки UserForml выдается сообщение "Событие: Activate для формы UserForml" (процедура User-Form_Activate). Щелчок на форме приводит к выводу сообщения "Событие: Click. Выводим UserForm2" (процедура UserForm_Click), загрузке формы UserForm2 (процедура UserForm_Click) и выводу сообщения "Событие: Deactivate для формы UserForml" (процедура UserForm_Deactivate) в результате того, что форма UserForml становится неактивной. Если бы мы описали процедуру события Activate
342
Глава 14
и для формы UserForm2, то один щелчок мыши вызвал бы инициализацию трех событий. И, наконец, не забудьте обратить внимание на то, что при выгрузке из памяти формы UserForml на экран выдается сообщение процедуры UserForm_Ter-minate.
Рис. 14.4
После создания новой формы очень легко «потерять» предыдущую
Событие Initialize инициализируется при загрузке формы при помощи оператора Load или метода Show. При выполнении команды Run | Run Sub/UserForm это событие не инициализируется. Это событие следует использовать при первой загрузке формы для установки каких-либо свойств формы и ее элементов управления. В следующем примере (листинг 14.2) для этого события устанавливается свойство формы BackColor.
Листинг 14.2. Процедуры событий UserForm2
1 Dim sRED, sGREEN, sBLUE 'переменные для задания цвета формы
2
3 ' Процедура обработки события Initialize
4 ' Инициализируется один раз: при загрузке
5 Private Sub UserForm_Initialize()
6	' задаем начальный	цвет	формы
7	sRED = 100
8	sGREEN = 100
9	sBLUE = 200
10	UserForm2.BackColor	=	RGB(sRED, sGREEN, sBLUE)
11 End Sub
12
13 ' Процедура обработки события Click
14 ' При каждой инициализации меняет цвет формы. При недопустимых
15 1 11 значениях sRED, sGREEN, sBLUE выдает ошибку времени исполнения
16 Private Sub UserForm_Click()
17	Dim I
18	-	‘
19	1 Меняем цвет	формы:	<
20	sRED = sRED +	20
21 sGREEN = sGREEN +10	'	,
22	SBLUE = SBLUE - 20
23	1 = RGB(SRED, SGREEN, SBLUE)
24	UserForm2.BackColor = I
25
Элементы диалоговых окон
343
26	' Изменить заголовок формы:
27 UserForm2.Caption = "Цвет: " & Str(i)
28 End Sub
Для загрузки формы UserForm2 используйте форму UserForml с программами обработки событий из листинга 14.1.
В листинге 14.2 для установки свойства формы BackColor используется функция RGB, которая возвращает RGB-значение типа Long, используемое далее для присвоения свойству UserForm2.BackColor. Синтаксис функции RGB:'
СИНТАКСИС
RGB(red, green, blue)
Именованные аргументы:
Аргумент	Описание
Red	Обязательный; тип: Variant (Integer). Число в диапазоне 0-255; представляет красный компонент цвета.
Green	Обязательный; тип: Variant (Integer). Число в диапазоне 0-255; представляет зеленый компонент цвета.
Blue	Обязательный; тип: Variant (Integer). Число в диапазоне 0-255; представляет синий компонент цвета.
После вывода формы с именем UserForm2 на экран событие Click будет приводить к изменению цвета и заголовка формы.
Мы не рассмотрели еще два события, связанные с формой: DblClick, которое является аналогом Click, и Resize — событие, которое инициализируется при изменении размеров формы.
Рассмотрим последнее событие, так как первое должно быть понятным и в реализации похожим на ранее рассмотренные.
Размеры формы могут изменяться как во время диалога (если это предусмотрено разработчиком формы), так и программным способом. Для иллюстрации программы обработки события изменения формы удобнее использовать программный способ. Листинг 14.3 содержит две процедуры: первая обрабатывает событие Click (при этом изменяется свойство формы Width), вторая — событие Resize.
Листинг 14.3. Обработка событий Click и Resize
1	Private Sub UserForm_Click() 1 Можно UserForm_DblClick
2	MsgBox ("Событие:	Click")
3	' Меняем размер	формы:
4	UserForml.Width	=	400
5	End Sub
6
7	Private Sub UserForm_Resize()
8	MsgBox ("Событие: Resize")
9	End Sub
Элементы управления
Объект UserForm может содержать те же элементы управления, что и находящиеся в диалоговых окнах Word, Excel или других приложений Windows. Элементы управления (controls) — это элементы диалогового окна, которые дают возмож
344
Глава 14
ность пользователю взаимодействовать с программой. Они включают в себя кнопки-переключатели, текстовые поля, линейки прокрутки, командные кнопки и так далее. В этом разделе вы познакомитесь со стандартными элементами управления, включенными в VBA, которые сможете добавлять в свои формы.
Многие производители программного обеспечения сделали доступными пакеты, расширяющие набор элементов управления. Вы можете добавлять элементы управления (известные как объекты ActiveX и Automation) к панели Toolbox (панели элементов), предварительно создавая ссылку из вашего проекта на библиотеку, содержащую расширенный набор элементов управления. После этого можно добавлять данные элементы управления на панель Toolbox.
Каждый элемент управления — это объект с определенными свойствами, методами и событиями. Как и для формы, их содержащей, вы можете устанавливать свойства элементов управления программным путем или посредством Properties Window редактора VB. В программе вы можете присваивать или восстанавливать значения свойств элементов управления так же, как для любых других объектов.
В табл. 14.4 перечислены стандартные элементы управления, включенные в VBA, и описано назначение каждого элемента. Как видно из этой таблицы, к стандартным относятся, практически, все элементы управления, которые вам встречались в приложениях Windows. (В зависимости от host-приложения VBA, в котором вы работаете, на панели Toolbox могут появляться дополнительные элементы управления, не перечисленные в табл. 14.4. Эти дополнительные элементы доступны через библиотеки элементов управления, поставляемые с каждым из host-приложений.)
Таблица 14.4. Стандартные элементы управления, включенные в VBA
Элемент управления	Назначенне
Label (надпись, метка)	Позволяет создавать заголовки элементов управления, которые не имеют собственных встроенных заголовков. Используйте этот элемент для того, чтобы поместить на форму статический текст, например, инструкции, советы по заполнению других диалоговых элементов управления.
TextBox (текстовое поле)	Окно редактируемого текста свободной формы для ввода данных. Может быть одно- или многострочным.
ComboBox (поле со списком)	Этот элемент управления объединяет окно редактирования и окно списка. Используйте, когда хотите предложить пользователю выбрать значение, но при этом дать ему возможность ввести данные, отсутствующие в списке. Вы можете также ограничить выбор только теми значениями, которые появляются в ComboBox для эмуляции ниспадающего списка.
ListBox (список)	Отображает список значений, из которых пользователь может сделать выбор. Окна списка можно использовать, чтобы дать возможность пользователю выбрать только одно значение или же несколько.
CheckBox (флажок)	Стандартный флажок (квадратное окно, содержащее, если элемент выбран, «галочку»). Используйте флажки для выбора вариантов, которые не являются взаимоисключающими.
OptionButton (переключатель)	Стандартная кнопка-переключатель (круглое окно, при выборе в центре него находится черная точка). Используйте OptionButton, когда пользователю необходимо сделать выбор между «включено/выключено», «истина/ложь». Кнопки-переключатели, как правило, объединяются вместе при помощи рамки для создания группы переключателей.
Элементы диалоговых окон
345
Элемент управления	Назначение
ToggleButton (выключатель)	Выключатели служат для той же цели, что и флажки, но выводят установки в виде кнопки находящейся в «нажатом» или «отжатом» состоянии.
Frame (рамка)	Визуально и логически объединяет некоторые элементы управления (особенно флажки, переключатели и выключатели). Используйте Frame, чтобы показать пользователю, какие элементы управления в диалоговом окне связаны между собой, или чтобы выделить группу элементов управления, отделяя ее от остальных элементов управления, находящих-
	ся в диалоговом окне.
CommandButton (кнопка)	Используйте кнопки для выполнения таких действий, как Cancel (Отмена), Save (Сохранить), ОК и так далее. Когда пользователь щелкает по кнопке, выполняется VBA-процедура, закрепленная за данным элементом управления.
TabStrip (набор вкладок)	Этот элемент управления состоит из области, в которую следует помещать другие элементы управления (такие как текстовые поля, флажки и так далее) и полосы кнопок табуляции. Используйте элемент управления TabStrip для создания диалоговых вкладок, отображающих одни и те же данные в различных категориях.
MultiPage (набор страниц)	Этот элемент управления состоит из нескольких страниц. Вы можете выбрать любую из них, щелкнув по соответствующей-вкладке. Используйте элемент управления MultiPage для создания диалоговых окон с вкладками, такими, например, как диалоговое окно, появляющееся при выборе команды Tools | Options (панели инструментов | настройка).
ScrollBar (полоса прокрутки)	Элемент управления ScrollBar позволяет выбирать линейное значение, аналогично тому, как это можно сделать при помощи счетчика.
SpinButton (счетчик)	Элемент управления SpinButton является специальной разновидностью текстового поля. Обычно счетчики используются для того, чтобы ввести число, дату или какие-либо иные последовательные величины, которые заведомо находятся в определенном интервале значений. Щелчок по указывающей вверх стрелке счетчика увеличивает значение в окошке, а щелчок по стрелке, направленной вниз, соответственно, уменьшает его.
Image (рисунок)	Элемент управления Image позволяет вывести на форме графическое изображение. Используйте Image для вывода графических изображений в любом из следующих форматов: *.bmp, *.cur, *.gif, *.ico, *.jpg, или *.wmf. Вы можете обрезать и масштабировать графическое изображение, чтобы подобрать размер элемента Image, но только не редактировать графическое изображение. Можно даже написать специальную VBA-процедуру, выполняющуюся, если пользователь щелкнет по элементу управления Image.
Обращение к элементам управления происходит, в основном, через их свойства и с помощью процедур обработки событий, написанных для каждого элемента. В табл. 14.5 перечислены наиболее часто используемые свойства элементов управле
346
Глава 14
ния, которые могут понадобиться для работы с вашими VBA-программами — свойства, которые позволяют изменять заголовок, определять состояние элемента управления (то есть обнаруживать установки, выполненные пользователем) и так далее.
Таблица 14.5. Наиболее часто используемые свойства стандартных элементов управления
Свойство	Где применяется	Описание
Accelerator	CheckBox, Tab, CommandButton, Label, Page, OptionButton, ToggleButton	Содержит символ, используемый, в качестве быстрой клавиши вызова, элемента управления. При нажатии АИ+<клавиша быстрого вызова> происходит выбор элемента управления.
BackColor	Все элементы	Число, представляющее определенный цвет фона элемента управления.
Caption	CheckBox, CommandButton, Frame, Label, OptionButton, ToggleButton, Page, Tab, UserForm	Для надписи — текст, отображаемый, элементом управления. Для других элементов управления — надпись, которая появляется на кнопке или вкладке или рядом с рамкой, флажком или переключателем.
Cancel	CommandButton	Задает кнопку отмены диалогового окна. При нажатии на эту кнопку или клавишу Esc диалоговое окно исчезает. Только одна кнопка формы может иметь данное свойство.
ControlTipText	Все элементы управления	Устанавливает текст, который отображается в виде всплывающей подсказки (ControlTip, называемой также ToolTip), когда указатель мыши помещается на элемент управления.
Default	CommandButton	Определяет заданную по умолчанию кнопку. Когда пользователь нажимает в процессе диалога клавишу Enter, эта кнопка ведет себя так, как если бы по ней щелкнули мышью.
Enabled	Все элементы управления	Хранит значение типа Boolean, определяющее доступен или нет элемент управления. Если Enabled имеет значение False, то элемент управления продолжает отображаться в диалоговом окне, но не может быть выбран.
ForeColor	Все элементы управления	То же самое, что и BackColor, но устанавливает цвет для переднего плана элемента управления, как правило, символов текста.
Элементы диалоговых окон
347
Свойство	Где применяется	Описание
List	ComboBox * * 1	Массив типа Variant (одно- или многомерный), представляет список содержащийся в элементе управления. Используйте индекс Value как нижний индекс в коллекции List, чтобы получить текст для выбранного пункта списка. Используйте методы элемента управления Additem и Removeitem для добавления или удаления пунктов списка.
Мах	ScrollBar, SpinButton	Переменная типа Long, определяющая максимальное значение счетчика или значение, при котором полоса прокрутки находится в самом верху (для вертикальной полосы) или справа (для горизонтальной).
Min	ScrollBar, SpinButton	Переменная типа Long, определяющая минимальное значение счетчика или значение, при котором полоса прокрутки находится в самом низу (для вертикальной полосы) или слева (для горизонтальной).
Name	Все элементы управления	Содержит имя элемента управления. Вы можете установить данное свойство толь- ко с помощью Properties Window.
RowSource	ComboBox	Задает источник, из которого ListBox берет список объекта. В Excel VBA RowSource обычно использует диапазон рабочего листа.
Selected	ListBox	Возвращает массив значений типа Boolean для списка, который допускает множественный выбор. Каждый элемент массива содержит по одному элементу, соответствующему каждому пункту списка. Если значение элемента в массиве Selected равно True, то соответствующий пункт списка выбран.
Tabindex	Все элементы управления	Число, указывающее положение элемента управления в порядке табуляции (может иметь значение от 0 до значения, равного количеству элементов управления на форме).
TabStop 1	Все элементы управления	Значение типа Boolean, указывающее может ли элемент управления быть выбран клавишей Tab. Если значение TabStop равно False вы, тем не менее, можете щелкнуть на элементе и таким образом его выбрать.
348
Глава 14
Свойство	Где применяется	Описание
Value	Все элементы управления	Значение текущих установок элемента управления: текст в текстовом поле, какие выбраны флажки и переключатели, индекс выбранного раздела списка или число, указывающеедекущее положение полосы прокрутки или счетчика.
Visible	Все элементы управления	Значение типа Boolean, указывающее, является ли элемент управления видимым.
В табл. 14.6 перечислены события элементов управления, для которых вы можете написать собственные процедуры обработки событий. Каждый элемент управления, который вы добавите в свою форму, будет иметь доступ к этим событиям. В частности, для кнопок используется событие Click, а для того, чтобы проверить данные или обновить другие элементы управления, — AfterUpdate или Change.
Таблица 14.6. Наиболее часто используемые события объектов управления
Событие	Синтаксис процедуры обработки	Описание
AddControl	См. Приложение А	Инициируется всякий раз, когда к форме (или элементам Frame, Page, MultiPage) добавляется какой-либо элемент управления.
AfterUpdate	Private Sub object_AfterUpdate()	Инициируется после обновления значения элемента управления.
BeforeUpdate	Private Sub object_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)	Инициируется после того, как было изменено значение элемента управления, но перед тем, как был обновлен сам элемент управления.
Change	Private Sub object_Change()	Инициируется всякий раз, когда изменяется значение элемента управления.
Click	Private Sub object_Click()	Инициируется всякий раз, когда по элементу управления щелкают мышью. Используйте данное событие для того, чтобы выполнить действие при помощи кнопки.
DblClick	Private Sub ob j ect_DblClick(By V al Cancel As MSForms.ReturnBoolean)	Инициируется всякий раз, когда по элементу управления дважды щелкают мышью. Используйте данное событие для вывода дополнительных форм.
Enter	Private Sub object_Enter()	Инициируется всякий раз, когда выделяется элемент управления.
Exit	Private Sub object_Exit(ByVal Cancel As MSForms.ReturnBoolean)	Инициируется всякий раз, когда с элемента управления снимается выделение.
Элементы диалоговых окон
349
Событие	Синтаксис процедуры обработки	Описание
Error	Private Sub object_Error(Index As Long, ByVai Number As integer, ByVai Description As MSForms.ReturnS tring)	Инициируется всякий раз, когда элемент управления обнаруживает ошибку и не может возвратить информацию об ошибке в вызывающую программу.
KeyDown	Private Sub ob ject_KeyD own(By V al KeyCode As MSForms.Returninteger, ByVai Shift As fmShiftState)	Инициируется при нажатии пользователем какой-либо клавиши в тот момент, когда форма выполняется и имеет фокус.
KeyPress	Private Sub object_Key-Press(ByVal KeyANSI As MSForms.Returninteger)	Инициируется, когда пользователь нажимает алфавитно-цифровую клавишу.
KeyUp	Private Sub object_KeyUp(By V al KeyCode As MSForms.Returnlnteger, ByVai Shift As fmShiftState)	Инициируется, когда пользователь отпускает клавишу.
Layout	Private Sub object_Layout()	Инициируется, когда изменяются размеры элемента Frame (или MultiPage).
MouseDown, MouseUp	См. Приложение A	Инициируются при щелчке мышью. MouseDown: когда пользователь нажимает на клавишу мыши; MouseUp: когда пользователь отпускает клавишу мыши.
MouseMove	См. Приложение A	Инициируется, когда пользователь перемещает мышь.
SpinDown, SpinUp	Private Sub object_SpinDown() Private Sub object_SpinUp()	Событие SpinDown инициируется, когда пользователь щелкает стрелку «вниз» (или «влево») кнопки счетчика. Событие SpinUp инициируется, когда пользователь щелкает стрелку «вверх» (или «вправо») кнопки счетчика.
' Zoom	Private Sub object_Zoom(index As Long, Percent As Integer)	Инициируется при изменении свойства Zoom.
В приложении А приведено описание параметров, используемых в табл. 14.6.
350
Глава 14
Использование Toolbox (панели элементов)
Прежде чем мы рассмотрим примеры обработки событий, связанных с элементами управления, вам следует научиться помещать элементы управления на форму и задавать им необходимые свойства.
Редактор VB в режиме разработки вместе с формой выводит на экран Toolbox (панель элементов) (если вывод этой панели не отключен при помощи меню View | Toolbox). На рис. 14.5 Toolbox показана в виде плавающего окна. Кнопки на панели Toolbox активизируют различные инструменты, которые позволяют помещать на форму элементы управления.
Toolbox (подобно всем другим панелям инструментов) можно настраивать. Если вы или другой пользователь установили дополнительные элементы управления независимых производителей или произвели настройку панели, она может выглядеть иначе, чем та, что показана на рис. 14.5. На рис. 14.5 присутствуют только стандартные элементы управления, поставляемые вместе с VBA.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Рис. 14.5. Используйте Toolbox для размещения на форме элементов управления
1 - Select Objects (выбор объектов), 2 - Label (надпись), 3 - TextBox (поле), 4 - ComboBox (поле со списком), 5 - ListBox (список), 6 - CheckBox (флажок), 7 - OptionButton (переключатель), 8 - ToggleButton (выключатель), 9 - Frame (рамка), 10 - CommandButton (кнопка), 11 - Tabstrip (набор вкладок), 12 - MultiPage (набор страниц), 13 - ScrollBar (полоса прокрутки), 14 - SpinButton (счетчик), 15 - Image (рисунок)
Чтобы воспользоваться панелью Toolbox для добавления элементов управления к вашей форме, выполните следующие действия:
1.	Щелкните на Toolbox по кнопке, соответствующей элементу управления, который вы хотите добавить к форме. Указатель мыши изменит форму на перекрестие, когда будет находиться на форме.
2.	Установите перекрестие в то место формы, в котором хотите поместить верхний левый угол нового элемента управления.
3.	Нажмите и удерживайте левую кнопку мыши.
4.	Перемещайте мышь вниз и вправо, пока элемент управления не примет нужный размер, после чего отпустите кнопку мыши. Редактор VB вставит в форму элемент управления, и указатель мыши вновь примет форму стрелки.
Вы можете изменить размер самой формы. Щелкните по строке заголовка формы для ее выделения и затем, перемещая один из маркеров изменения размеров, увеличьте или уменьшите размер формы до желаемого. Маркеры изменения размеров (sizing handles) — это маленькие квадратики, которые появляются в углах и на серединах сторон графического объекта (наряду с толстой серой границей) при выделении объекта.
Добавление к форме элементов управления
Когда вы создаете новую форму, редактор VB предоставляет чистую (без элементов управления) форму (смотри рис. 14.1). Вы можете добавить к форме элементы управления с использованием различных инструментов панели Toolbox.
Элементы диалоговых окон
351
Чтобы добавить к форме элемент управления, используйте панель Toolbox, как описано в предыдущем параграфе этой главы. В качестве примера добавления к форме конкретного элемента добавьте на новую форму кнопку, выполнив следующие действия:
1.	Выберите команду Insert | UserForm (Вставка | UserForm). Редактор VB добавит новую форму, отображая ее в режиме разработки, и, кроме того, на экране появится Toolbox.
2.	Щелкните на элементе CommandButton панели Toolbox. Кнопка перейдет в «утопленное» состояние, указывая выбранный вами элемент.
3.	Поместите курсор мыши на форму. Курсор при этом изменит свою форму на перекрестие с прикрепленным к нему символом выбранного элемента.
4.	Поместите перекрестие в ту точку формы, в которой должен быть верхний левый угол кнопки.
5.	Переместите курсор мыши вниз и вправо, чтобы нарисовать элемент управления CommandButton. В процессе перемещения курсора мыши редактор VB отображает прямоугольный контур, показывающий размер кнопки.
6.	Отпустите кнопку мыши, когда решите, что CommandButton имеет необходимый размер. Редактор VB создаст элемент управления CommandButton и поместит его на форму. На рис. 14.6 показано, как выглядит кнопка, сразу же после того, как была помещена на форму.
Рис. 14.6
UserForml сразу же после добавления элемента
CommandButton
Добавив к форме кнопку, вы можете заметить, что верхний левый угол кнопки (также как и сама граница кнопки) автоматически выравнивается по шаблону сетки на форме. Это действие, называемое привязка к сетке (snap to grid), поможет вам выровнять размещенные на форме элементы управления и текст. Вы можете включать и отключать привязку к сетке, настраивать шаг сетки или скрывать ее, изменяя установки в диалоговом окне Option (Параметры) редактора VB. Выберите Tools | Options (Сервис | Параметры) и щелкните по вкладке General (общие), чтобы вывести Form Grid Settings (Параметры сетки в форме). Выберите или сбросьте необходимые опции.
Все элементы управления формы должны иметь уникальные имена. Эти имена следует использовать при ссылках на элемент управления в своей программе. Всякий раз, когда вы добавляете к форме новый элемент управления, VBA присваивает ему имя по умолчанию, состоящее из имени типа элемента и номера. VBA обеспечивает уникальность имени включением в имя элемента управления числа. Число в имени больше, чем число любого другого подобного элемента управления. Если кнопка, которую вы добавили в начале этого раздела, Является первой кнопкой, она получит имя CommandButtonl. Следующая добавленная вами кнопка будет CommandButton2 и так далее. Если после этого вы добавите поле, оно получит имя TextBoxl.
352
Глава 14
Перед тем как продолжить работу с формами, давайте договоримся о несложных правилах, которые помогут вам с первых шагов создавать диалоговые окна, почти похожие на профессиональные. Если вы до сих пор не обращали внимания на то, что все окна «солидных» разработчиков имеют общие черты, то сейчас как раз то время, когда это нужно сделать. На рис. 14.7 приведена схема, которой можно придерживаться при разработке своих первых форм.
Рис. 14.7
Схема типичного диалогового Windows-окна
Наименование окна, как вы уже знаете, задается свойством Caption формы. Кнопка закрытия окна, если ничего специально не предпринимать, по умолчанию всегда будет в окне приложения. Если она вам не нужна, то лучше от нее избавиться.
В «полезной» части окна помещаются функционально необходимые элементы управления, которые определяются назначением окна. Здесь могут быть, например, элементы для ввода некоторой информации или изменения настроек приложения.
С кнопкой ОК обычно связывают событие, которое подводит некоторый итог. Обычно в профессиональных приложениях все, что вводится в диалоговом окне, не сразу вступает в действие, а только после того, как пользователь щелкнет кнопку ОК. Это дает возможность отказаться от недостаточно обдуманных действий. Разработчику таких окон не очень трудно скопировать данные из диалогового окна в несколько переменных прежде, чем присвоить их каким-либо свойствам элементов управления, а пользователю удобнее работать с окном, из которого всегда можно выйти без последствий.
Из предыдущего абзаца, видимо, понятно назначение кнопки Отмена. Дополнительной ее функцией является и выход из процедуры обработки событий формы. Кнопка же ОК может разрешить пользователю продолжить путешествие «внутрь» приложения, которое открылось данным окном (иногда говорят «панелью» или «диалогом»).
Кнопка Справка знакома всем «с детства». К сожалению, не так просто организовать помощь, подобную обычной Windows-справке, но можно сначала использовать эту кнопку для простых подсказок, которые создаются простым помещением на пустую форму элемента Label с текстом подсказки. В дальнейшем, изучив способы построения сложных систем подсказок, можно создавать почти профессиональные диалоговые окна.
Этих нехитрых правил, конечно же, вам хватит при проектировании несложных форм. При создании «хороших» форм следует ознакомиться с рекомендациями фирмы Microsoft. Эти рекомендации имеют отношение к следующим аспектам:
	Размещение элементов управления на форме (в том числе и установка интервалов между элементами).
	Выравнивание меток (метки должны быть хорошими путеводителями формы).
Элементы диалоговых окон
353
	Использование стандартных шрифтов (часто пользователи собирают по всему свету интересные шрифты и забывают о том, что такие шрифты могут отсутствовать у других).
	Использование цвета.
При размещении на форме нескольких элементов управления, которые можно условно разделить на отдельные группы, следует использовать элемент frame (рамка). При этом желательно пользоваться свойством, определяющим заголовок рамки.
Для более легкого чтения полей, расположенных друг под другом, необходимо выравнивать их по левому краю.
Старайтесь поддерживать стандартными высоту и ширину элементов управления, а также расстояния между ними. Интервалы между элементами измеряются в твипах (один пиксел равен 15 твипам). Microsoft рекомендует для высоты элемента управления 300 твипов, для ширины командной кнопки — 1200 твипов, для расстояния по вертикали между элементами — 60 твипов между связанными (по смыслу) и 90 твипов между несвязанными элементами.
Для всех элементов управления используйте в качестве шрифта нормальный Sans Serif 8-пунктов. Конечно, следует учитывать и запросы потенциального пользователя вашего продукта, но при подготовке тестового варианта для обсуждения сначала необходимо придерживаться рекомендаций Microsoft.
Самые обычные серые цвета, которые вы можете видеть во всех известных продуктах Windows, рекомендуются и для ваших приложений. Хотя в вашем распоряжении имеется большое количество цветов, все равно без особой нужды не следует изменять цвета по умолчанию. Если же вы можете предоставить пользователю работающего приложения самому изменять цвета формы и элементов управления на ней, это будет опимальным вариантом.
Итак, если вы согласны с предлагаемыми правилами, создайте свою первую форму в соответствии со схемой рис. 14.7.
Рис. 14.8
Форма с самыми необходимыми кнопками
В следующей таблице приведены значения свойств элементов управления, которые были изменены. Для своих приложений в качестве документации вы тоже можете создавать такие таблицы для облегчения сопровождения своего программного продукта.
Тип элемента	Свойство, которое изменено	Значение	Примечание
UserForm	Name	Frmfirst	Имя формы, на которое можно ссылаться в коде.
	Caption	Тестирование кнопок	Заголовок окна (формы) в верхней части.
!2 Программирование на VBA 2002
354
Глава 14
Тип элемента	Свойство, которое изменено	Значение	Примечание
CommandButton	Name	CmdOK	Имя кнопки, на которое можно ссылаться в коде.
	Caption	OK	Текст на кнопке.
	Default	True	При нажатии на клавишу Enter инициируется событие Click кнопки.
CommandButton	Name	CmdCancel	Имя кнопки, на которое можно ссылаться в коде.
	Caption	Отмена	Текст на кнопке.
	Cancel	True	При нажатии на клавишу Esc инициируется событие Click кнопки.
CommandButton	Name	CmdHelp	Имя кнопки, на которое можно ссылаться в коде.
	Caption	Справка	Текст на кнопке.
В VBA (как и в Microsoft Visual Basic) кнопки (элементы CommandButton) имеют специальное свойство Cancel, которое определяет кнопку Отмена (независимо от того, называется ли эта кнопка Отмена). Только одна кнопка формы может иметь свойство Cancel, установленное равным True. Если задать это свойство для одной из кнопок, аналогичное свойство для всех остальных кнопок формы будет установлено равным False. Если форма содержит кнопку с установленным свойством Cancel, то нажатие клавиши Esc приводит к тому же результату, что и щелчок по кнопке.
Если вы запустите форму на выполнение (командой Run | Run Sub/UserForm), то ни щелчок на кнопке, ни нажатие клавиши Esc не приведут ни к какому результату, так как с кнопкой не связано никакого события. Но диалоговое окно появится на экране в режиме выполнения и будет создавать впечатление чего-то работающего (рис. 14.9).
Рис. 14.9
Такое окно тоже «имеет право» называться «диалоговым»
Если вы будете щелкать кнопки этого окна, то убедитесь в том, что окно совершенно «нечувствительно» к вашим манипуляциям. Единственная кнопка, которая будет реагировать на ваши действия, находится вверху справа (с изображением перекрестия). Эта кнопка закроет окно.
Чтобы кнопки, помещенные вами на диалоговой панели, «ожили», необходимо для каждой из них написать процедуры обработки событий Click (щелчок на
Элементы диалоговых окон
355
кнопке). Начнем с кнопки Отмена, чтобы всегда иметь возможность выйти из приложения. Свяжем с щелчком на кнопке Отмена программу, которая выгрузит форму, что приведет к окончанию работы с диалоговым окном. Для создания процедуры обработки события дважды щелкните на кнопке Отмена в режиме разработки и в появившемся шаблоне процедуры обработки события введите оператор выгрузки формы, как это представлено в листинге 14.4.
Листинг 14.4. Процедура обработки события - щелчок на кнопке Отмена
1	Private Sub CmdCancel _Click()
2	Unload Me ' Выгружаем форму, заканчивая приложение
3	End Sub
Снова запустите форму на выполнение. Вы увидите то же диалоговое окно, что и на рис. 14.6, но теперь это окно — «настоящее» диалоговое, потому что при щелчке на кнопке Отмена выполняется программа обработки события и окно закрывается. Более того, при нажатии на клавишу Esc вы получаете точно тот же результат! Понятно, что процедура обработки события Click (именно это событие и связано с кнопкой) может выполнить и более серьезную работу, чем простая выгрузка формы. Чтобы это было действительно понятно, добавим к процедуре вывод сообщения о том, что возможен выход из диалога (см. листинг 14.5).
Листинг 14.5. Более «продвинутая» процедура обработки события - щелчок на кнопке Отмена
1	Private Sub CmdCancel _Click()
2	' объявление переменных
3	Dim Msg, Title, Response As String
4
5	' выдаваемое в окне MsgBox сообщение	-x
6	Msg = "Хотите закончить работу"’"
7
8	1 состав кнопок и	тип значка
9	Style = vbYesNo +	vbCritical + vbDefaultButton2
10
11	' заголовок окна
12	Title = "Выход из	программы"
13
14	' вызов функции MsgBox с возвращаемым значением	-
15	Response	= MsgBox(Msg,	Style,	Title)
16	' анализ	возвращаемого	значения
17	If Response = vbYes Then
18	Unload Me 'выгрузка формы
19	End If
20
21	End Sub
Если вы запустите форму с такой процедурой обработки события Click и щелкните на кнопке Отмена или нажмете клавишу Esc, то на экран будет выдано сообщение, подобное приведенному на рис. 14.10. Эта процедура стала более дружественной, поскольку не сразу заканчивает работу окна диалога. Случайный щелчок на кнопке Отмена или нажатие на клавишу Esc не приведут к окончанию работы с диалогом.
Теперь, когда у нас имеется возможность покинуть диалоговое окно, можно написать простые процедуры обработки событий для кнопок ОК и Справка. Кнопка ОК в начале разработки приложения может быть связана с процедурой, выдающей сообщение о том, что приложение пока не готово к эксплуатации. С кнопкой Справка
12*
356
Глава 14
Рис. 14.10
Процедура обработки сообщения от кнопки Отмена стала более дружественной
для ваших первых приложений можно поступить по-разному: например, одним из решений может быть выдача длинного сообщения посредством функции MsgBox, а можно создать новое диалоговое окно с элементом Label, свойством Caption которого будет также длинное сообщение о полезности приложения. Далее будет рассмотрено создание и вызов дополнительного диалогового окна приложения.
Очень полезной может оказаться процедура обработки события Change — при любом изменении свойств элементов управления (в конечном итоге, все, что происходит в диалоговом окне — это изменение тех или иных свойств) выполнять некоторые проверки на допустимость изменений и сообщать пользователю о возможных проблемах. Можно также использовать событие Change для подсказки пользователю о происходящих изменениях со свойствами элементов управления. В качестве примера создайте форму UserForml так, чтобы она была похожа на представленную на рис. 14.11. Чтобы соответствующее форме диалоговое окно позволило продолжить работу с приложением, в этом окне необходимо в одном из текстовых полей ввести либо фамилию, либо имя пользователя. При изменении со держимого любого поля (свойство Text) инициируется процедура обработки события Change, в которой свойству Enable кнопки OK_button (с заголовком ОК) присваивается значение True. Кнопка OK_button предназначена для изменения свойства Caption формы UserForm2 и вывода этой формы на экран. Кнопка с заголовком Отмена всегда доступна и предназначена для выхода из программы. Свойство Cancel этой кнопки имеет значение True.
Рис. 14.11
Форма для тестирования события
Change для TextBox
Тестирование события Change
Данные о пользователе
Фамилия
Имя
i
Для создания такой формы выполните следующее:
1.	Создайте новую форму с именем по умолчанию UserForml. В Properties Window измените свойство Caption этого элемента на Тестирование события Change.
2.	Поместите на форму UserForml элемент Frame. По умолчанию его имя будет Framel. Измените свойство Caption этого элемента на Данные о пользователе. (Размеры элемента не важны.)
Элементы диалоговых окон
357
3.	Поместите на форму в область Framel элемент TextBox (с именем по умолчанию TextBoxl) и элемент Label с заголовком (свойство Caption) Фамилия. Имя метки для данного случая не имеет значения.
4.	Поместите на форму в область Framel элемент TextBox (с именем по умолчанию TextBox2) и элемент Label с заголовком Имя.
5.	Поместите на форму (см. рис. 14.11) элемент CommandButton и измените его свойство Name на Cancel_button, а свойство Caption на Отмена. Установите свойство Cancel в True, чтобы при нажатии на клавишу Esc программа выполняла ту же процедуру, что и при щелчке на кнопку Отмена.
6.	Поместите на форму элемент CommandButton и измените его свойство Name на OK_button, а свойство Caption на ОК. Измените свойство Enabled этой кнопки на False. Этим вы сделаете кнопку ОК недоступной для пользователя после выдачи диалогового окна на экран в режиме выполнения. Чтобы кнопка стала доступной и приложение могло выполнить какую-либо работу с использованием кнопки ОК, пользователь должен будет изменить содержимое одного из текстовых окон.
7.	Откройте модуль класса формы UserForml и запишите в него код, представленный в листинге 14.6.
8.	Создайте форму UserForm2 (без элементов управления) и запишите в модуль класса этой формы код из листинга 14.2.
Тип элемента	Свойство, которое изменено	Значение	Примечание
UserForm	Name	UserForml	Имя главной формы, на которое можно ссылаться в коде.
	Caption	Тестирование события Change	Заголовок окна (формы) в верхней части.
Frame	Name	Framel	Имя, на которое можно ссылаться в коде.
	Caption	Данные о пользователе	
TextBox	Name	TextBoxl	Имя, на которое можно ссылаться в коде.
Label	Name	Label 1	
	Caption	Фамилия	Заголовок для текстового окна TextBoxl.
TextBox	Name	TextBox2	Имя, на которое можно ссылаться в коде.
Label	Name	LabeI2	
	Caption	Имя	Заголовок для текстового окна TextBox2.
CommandButton	Name	Cancel_button	Имя кнопки, на которое можно ссылаться в коде.
	Caption	Отмена	Текст на кнопке: кнопка для окончания работы приложения.
CommandButton	Name	OK_button	
358
Глава 14
Тип элемента	Свойство, которое изменено	Значение	Примечание
	Caption	OK	Текст на кнопке: кнопка для продолжения работы приложения.
	Enabled	False	Кнопка недоступна для пользователя сразу после выдачи диалогового окна на экран.
			
UserForm	Name	UserForm2	Имя формы, загружаемой из главной при щелчке на кнопке ОК.
Выполните команду Run | Run Sub/UserForm. Если вы не будете редактировать (изменять) содержимое текстовых окон, вам будет доступна только кнопка Выход. Как только вы измените содержимое какого-либо текстового окна (Фамилия или Имя), инициируется событие Change и свойству Enabled кнопки ОК будет присвоено значения True (строка 17 Листинга 14.6). Так как с кнопкой ОК связана процедура обработки события Click, которая загружает форму UserForm2, пользователь получает возможность дальнейшей работы. При этом свойству Caption формы присваивается сумма содержимого полей TextBoxl и TextBox2.
Листинг 14.6. Обработка события Change
1	' Обработка события Click кнопки Выход
2	Private Sub Cancel_button_Click()
3	MsgBox ("Заканчиваем программу!")
4	Unload Me
5	End Sub
6
7	' Обработка события Click кнопки OK
8	Private Sub OK. button.. Click ()
9 10	' Изменить заголовок диалогового <	окна I	JserForm2
11	UserForm2.Caption = TextBoxl.Text	+ TextBox2.Text	
12 13 14	UserForm2.Show	' загрузка End Sub	окна	UserForm2
15 16	' Обработка события Change текстового Private Sub TextBoxl Change ()	окна	с меткой Фамилия
17 18 19	Next_button.Enabled = True End Sub		
20 21 22	' Обработка события Change текстового Private Sub TextBox2_Change() Next button.Enabled = True	окна	с меткой Имя
23	End Sub		
В следующей главе будут использованы и другие события, для которых вы можете сами написать код обработки.
Редактирование элементов управления на форме
Поместив на форму элемент управления, вы имеете возможность изменять его размеры, двигать, копировать, удалять, форматировать (изменять размер, стиль, гарнитуру шрифта) или изменять его свойства (такие как имя, заголовок и так далее).
Элементы диалоговых окон
359
Чтобы открыть существующую форму для редактирования, щелкните по ней два раза в Project Explorer (Окне проекта). Кроме того, вы можете выбрать в Project Explorer форму, которую хотите отредактировать, и затем щелкнуть кнопкой Show Object (Просмотр объектов).
Выбор элементов управления
Чтобы отредактировать элемент управления, вы должны сначала выделить его щелчком мыши. Выделенный элемент имеет серую границу с маркерами изменения размеров, как показано для кнопки на рис. 14.5. Чтобы выделить несколько элементов управления сразу, удерживайте нажатой клавишу Shift, когда щелкаете по элементам управления, которые хотите выделить. Выделять сразу несколько элементов управления имеет смысл, если вы хотите выполнить форматирование, которое будет распространяться на все элементы формы. Это может быть, например, изменение размера шрифта, стиля или гарнитуры. Выбор нескольких элементов управления может также оказаться полезным, если вы хотите переместить эти элементы одновременно.
Вы можете временно сгруппировать несколько элементов управления, воспользовавшись командой Format | Group (Формат | Группировать). Если элементы управления сгруппированы, они ведут себя как один объект, когда вы их выбираете, перемещаете, копируете или редактируете. Элементы управления остаются сгруппированными до тех пор, пока вы не примените к выделенной группе команду Format | Ungroup (Формат | Разделить).
Перемещение элементов управления
Чтобы переместить элемент управления на новое место в форме, сначала выделите его. После этого поместите указатель мыши поверх любой части серой границы, окружающей выбранный элемент управления, за исключением маркеров изменения размеров. Теперь щелкните и перетащите этот элемент на новое место.
Изменение размеров элементов управления
Чтобы изменить размер элемента управления, сначала выделите этот элемент. После этого поместите курсор мыши поверх любого из маркеров изменения размеров. Когда курсор находится на маркере изменения размера, он меняет свою форму на двойную стрелку, показывающую направление, в котором вы можете изменять размер выбранного элемента управления. Теперь нажмите (не отпуская) кнопку мыши и передвиньте маркер изменения размера на нужное место. В процессе перемещения редактор VB будет отображать контур, показывающий новые границы элемента управления. Когда элемент управления станет требуемого размера, отпустите кнопку мыши, редактор VB перерисует элемент управления в соответствии с вновь заданным размером.
Копирование, вставка и удаление элементов управления
Один из самых простых способов создать несколько одинаковых элементов управления, таких как несколько флажков или кнопок, состоит в том, чтобы сначала создать один элемент управления, скопировать его, после чего поместить скопированный элемент в форму столько раз, сколько необходимо. Чтобы скопировать элемент управления, просто выберите его и затем воспользуйтесь командой Edit | Сору (Правка | Копировать) или нажмите Ctrl+C.
360
Глава 14
После того как элемент управления скопирован, вы можете вставить его в ту же или другую форму, используя команду Edit | Paste (Правка | Вставить) или нажав Ctrl+V. После выполнения операции вставки переместите элемент управления в предназначенное для него место.
Чтобы удалить элемент(ы) управления, выделите его (их), после чего нажмите клавишу Delete. Редактор VB удалит выделенный(-ные) элемент(-ы) управления.
Редактирование или форматирование заголовков элементов управления
Для редактирования текста заголовков таких элементов управления, как кнопка, переключатель или флажок, просто щелкните по этому тексту. Редактор VB поместит в текст заголовка курсор вставки. Теперь можно редактировать текст, используя любые стандартные команды редактирования текста Windows, с которыми вы уже знакомы. Однако для того, чтобы изменить гарнитуру, стиль или размер шрифта, необходимо вывести для соответствующего элемента управления Properties Window (окно свойств) и изменить свойство Font.
Чтобы отредактировать текст заголовка формы, отредактируйте свойство формы Caption в Properties Window. А для форматирования текста заголовка формы воспользуйтесь свойством формы Font.
Некоторые элементы управления, такие как поля (TextBox), списки (ListBox) и поля со списком (ComboBox) не имеют встроенной надписи (или заголовка). Чтобы пометить такие элементы на форме, используйте элемент Label.
Управление последовательностью перехода
В активном состоянии ваша форма будет вести себя подобно другим диалоговым окнам Windows. Пользователь вашего диалогового окна может переходить от одного элемента управления к другому вперед и назад, используя соответственно клавиши Tab или Shif+Tab. Порядок, в котором будут активизироваться элементы управления в ответ на нажатие пользователем клавиш Tab или Shif+Tab, называется последовательностью перехода (tab order) элементов управления. Обычно последовательность перехода для элементов управления выбирают так, чтобы она соответствовала (приблизительно) перемещению слева направо и сверху вниз. Вообще говоря, вы должны постараться так расположить элементы управления, чтобы последовательность перехода обеспечивала логическое перемещение от одного элемента управления диалогового окна к другому.
Редактор VB по умолчанию устанавливает для элементов управления последовательность перехода, определяемую порядком, в котором они были добавлены на форму. Очень часто, после того, как вы разместили на форме все элементы управления и несколько раз их передвинули, чтобы добиться приемлемого вида формы, установленная по умолчанию последовательность перехода уже больше не обеспечивает логической последовательности перемещения по элементам управления диалогового окна.
Для изменения последовательности перехода, выполните следующие действия: 1. Выберите команду View | Tab Order (Вид | Последовательность перехода); редактор VB отображает диалоговое окно Tab Order (Последовательность перехода), показанное на рис. 14.12. Список Tab Order выводит все элементы управления формы в существующей на данный момент последовательности.
2.	В списке Tab Order выберите элементы, положение которых хотите изменить. (На рис. 14.12 выбран элемент управления с именем TextBoxl.)
3.	Используя кнопки Move Up (вверх) и Move Down (вниз) измените положение выбранного элемента управления в последовательности перехода. Щелчок по
Элементы диалоговых окон
361
Рис. 14.12
Использование диалогового окна Tab Order для изменения последовательности перехода к элементам управления формы
t
кнопке Move Up переместит элемент управления вверх по списку (то есть он будет активизироваться раньше), а щелчок по кнопке Move Down переместит этот элемент вниз по списку (то есть он будет активизироваться позже).
4.	Повторите пункты 2 и 3 для каждого элемента управления, пока не получите удовлетворяющую вас последовательность перехода для элементов управления формы.
5.	Выберите в диалоговом окне Tab Order кнопку ОК, чтобы подтвердить сделанные вами изменения, после чего закройте окно.
Хотя элементы Label тоже появляются в диалоговом окне Tab Order и вы можете поменять их положение в списке, в VBA нельзя выбрать элемент управления Label. Этот элемент предназначен исключительно для вывода текста.
Задание свойств формы и элементов управления в режиме разработки
Каждая форма и каждый элемент управления формы имеют собственный набор свойств точно так же, как и другие объекты VBA или host-приложения. Некоторые свойства формы и элемента управления проще и практичнее задать в режиме разработки, а не в коде VBA. Установленные вами свойства формы или элемента управления становятся для них новыми свойствами по умолчанию.
Например, хотя вы можете задать шрифт, цвет фона и цвет текста элемента управления с помощью VBA-кода, обычно нет необходимости изменять эти свойства в процессе выполнения кода. Вместо этого, гораздо проще установить данные свойства в процессе разработки. Вы также можете задать для формы значения по умолчанию, задавая свойство Value элемента управления. Например, чтобы создать на форме флажок, который установлен по умолчанию, вы должны в режиме разработки, установить свойство Value для этого флажка равным True. Каждый раз, когда в процессе выполнения программы форма будет загружаться в память, флажок будет уже установлен.
Аналогично в процессе разработки, можно заполнить списки элементов управления, установив свойство RowSource списка элемента управления. В Excel вы можете с помощью свойства RowSource связать список с диапазоном ячеек листа и связать поле с ячейкой листа, установив свойство ControlSource.
Вы также можете задать значение по умолчанию для поля, введя текст непосредственно в элемент управления TextBox на форме. После этого каждый раз при выводе формы поле будет содержать введенный вами текст.
В режиме разработки свойства формы или элемента управления устанавливаются в Properties Window, где перечислены все свойства объекта, которые вы можете установить в этом режиме. Конкретные свойства, появляющиеся в этом окне, зависят от выбранного вами элемента управления. На рис. 14.13 показано Properties
362
Глава 14
Window для кнопки с именем (свойством Name) CmdOK и заголовком (Caption) Вычислить для некоторой формы.
Properties Window имеет две страницы (вкладки). Первая — показана на рис. 14.13 и содержит список свойств объекта в алфавитном порядке. Вторая страница, показанная на рис. 14.14, содержит список свойств, разделенных на категории. Заметьте, что различные категории выделены в Properties Window жирным шрифтом: Appearance (Вид), Behavior (Поведение), Font (Шрифт) и так далее. Вы можете свернуть или развернуть список свойств конкретной категории, щелкнув по квадратику слева от заголовка каждой из категорий.
Рис. 14.13
Properties Window для кнопки, показывающее список свойств в алфавитном порядке
tef Properties	- CmdOK
CmdOK CommandButton	jJ	
Alphabetic Categorized t	
I (Na me)	CmdOK	a
^Accelerator	
|AutoSize	False
If BadcCoiw	О анвоооооога
iBackStyle	1 - fmBackStyleOpaque
Cancel	False
Caption	Вычислить
ControlTipText	
Default	False
Enabled	True
Font	Tahoma
ForeColor	 8HB00000128
Height	18
HelpContextlD	0
Left	180
Locked	False
Mouseicon	(None)
iMousePomter	0 fmMousePointerDefau
Picture	(None)
jPicturePosition	7 - fmPicturePositionAbov v
la Properties - CmdOK Г„
I
Рис. 14.14
Properties Window для кнопки, показывающее список свойств по категориям
|CmdOK CommandButton
Alphabetic 5 Categorized
S Appearance	
(Name)	CmdOK
Bad-Cotor	(□ 8H8000000F& *
BackStyle Caption ControlTipText ForeColor	1 - fmBackStyleOpaqu Вычислить  84800000128
Visible	True
S Behavior	
AutoSize	False
Cancel	False
Default	False
Enabled	True
Locked	Falsfi
TakeFocusOnClick True	
Wordwrap S Font	False
Font	Tahoma
Misc	
Accelerator	
Элементы диалоговых окон
363
Чтобы задать свойство формы или элемента управления, щелкните в поле, соответствующем свойству, которое хотите изменить. Для большинства свойств появится раскрывающийся список. Щелкните по кнопке списка и выберите из списка нужное значение свойства. Другие свойства (такие как Name и Caption) дают возможность ввести любой необходимый текст. Некоторые свойства при их выборе выводят кнопку с многоточием (...). Щелчок по такой кнопке открывает дополнительные диалоговые окна, помогающие задать это свойство.
Чтобы изменить свойства формы или элемента управления, выполните следующие действия:
1.	Выберите элемент управления, свойства которого хотите изменить. Чтобы выделить форму, щелкните где-нибудь на поверхности формы, не занятой элементами управления.
2.	Выберите команду View | Properties Window (Вид | Окно свойств) для отображения Properties Window. (Вы можете сделать это и щелчком на кнопке Properties Window на панели инструментов редактора VB или, нажав F4.)
3.	Установите необходимое свойство для выбранного элемента управления.
4.	Щелкните по кнопке Close (закрыть) в верхнем левом углу окна Properties Window, чтобы его закрыть.
Итак, вы познакомились с основными положениями создания и управления диалоговыми окнами и их элементами. Более полную информацию о каждом элементе управления можно получить из справочной системы VBA.
Пример разработки приложения с диалоговой формой
У нас имеется файл некоторой базы данных в DBase-формате (dbf-файл). Этот файл содержит данные о кодах товаров, наименований и цен (оптовых, розничных, закупочных). Система, использующая базу данных с этим файлом, работает под DOS (таких систем пока еще очень много, и нет особых причин, по которым они должны были бы прекратить свое существование). Как известно, под DOS практически нет графических редакторов, с помощью которых можно было бы красиво подготовить прейскурант (или прайс-лист). Поэтому предлагается загрузить dbf-файл в Excel и напечатать прейскурант с минимальным участием пользователя. Если кому-то исходные посылки кажутся слишком искусственными, не обращайте на это внимания, сосредоточьтесь на самом процессе.
Интерфейс
Сначала следует продумать действия пользователя и будущего макроса от начала работы до получения результата.
Что должен уметь пользователь?
Пользователь должен уметь загружать Excel с рабочей книгой Прейскурант (это достаточно просто, если пользователь способен в Windows найти файл ПРЕЙСКУРАНТ.XLS и щелкнуть на нем мышью). Далее действия пользователя зависят от того, какой интерфейс для работы с макросом мы ему предложим. Чтобы максимально облегчить работу пользователя, будем при загрузке книги выдавать на экран диалоговое окно для работы с прейскурантом. Поместим также в меню Tools опцию Прейскурант, чтобы после того, как пользователь по тем или иным причинам уберет это диалоговое окно, его можно было бы снова выводить на экран. Тогда пользователь должен еще уметь работать с меню в Excel и с простым диалоговым окном.
364
Глава 14
Что поместить в диалоговое окно?
В диалоговом окне будем помещать все необходимые для получения прейскуранта элементы управления:
	элементы настройки распечатываемых страниц;
	элементы выбора различных видов товара;
	кнопки запуска и выхода.	*
Данные для макроса
Для работы макроса при построении прейскуранта необходимы числовые данные, которые будут использоваться по умолчанию и которые пользователь может изменять для своих нужд. Это могут быть такие параметры, как количество распечатываемых на листе строк (в зависимости от шрифта и параметров принтера), признак печати в одну/две колонки, признак вывода того или иного вида цен и т.д. Эти параметры необходимо где-то хранить, поэтому нам потребуется в Excel отдельный рабочий лист, который не очень часто будет изменяться и для макроса станет его источником данных.
I
Разработка приложения
Создайте в Excel новую рабочую книгу. Сохраните эту книгу под именем Прейскурант в диалоговом окне SaveAs. Для работы нам нужны два рабочих листа. Если нужно, вставьте новый рабочий лист, выбирая Insert | Worksheet. (На самом деле, вам, скорее всего, придется избавиться от лишних листов.)
Переименуйте рабочие листы: первый назовите Прейскурант, второй (здесь будет база данных макроса) — Настройки.	(
Разработка диалогового окна
Войдите в Visual Basic Editor и добавьте к проекту с помощью кнопки Insert UserForm новую форму и по своему вкусу (или по требованию потенциального пользователя) расположите на новой форме необходимые элементы управления, что на данном этапе чтения этой книги сделать не трудно. На рис. 14.15 представлен один из возможных вариантов такого окна в режиме разработки, а в следующей таблице приведены расположенные на форме элементы управления с измененными свойствами. Не указаны только размеры и шрифты. Не указаны также элементы управления типа Label, поскольку они не используются в коде модуля формы.
Тип элемента	Наименование свойства	Значение свойства
Frame	Name	Framel
	Caption	Настройки прейскуранта
TextBox	Name	НачальнаяСтрока
	Enable	False
TextBox	Name	ДлннаСтраницы
	Enable	False
SpinButton	Name	8р1п_НачСтр
SpinButton	Name	S рш_Д линаСтр
Frame	Name	Frame2
	Caption	Колонки
Элементы диалоговых окон
365
Тип элемента	Наименование свойства	Значение свойства
OptionButton	Name	Кол_Одна
	Caption	Одна
OptionButton	Name	Кол_Две
	Caption	Две
Frame	Name	Frame3
	Caption	Цена
OptionButton	Name	Цена_Опт
	Caption	Оптовая
OptionButton	Name	Цена_Розн
	Caption	Розничная
ComboBox	Name	Группа
CommandButton	Name	Кн_Обновить
	Caption	Обновить
CommandButton	Name	Кн_Выход
	Caption	Выход
Рис. 14.15
Расположенные на форме элементы управления
В листинге 14.15 приведен код, который обрабатывает события, связанные со всеми элементами управления, кроме кнопки Обновить. Некоторые из элементов этой формы только считывают данные листа Настройки (который представлен на рис. 14.16), а некоторые также изменяют эти данные.
Листинг 14.7. Первичный код модуля формы Прейскурант 1 2 3 4 5 6 7
1 Public НачСтрокаЗнач As Integer
2 Public ДлинаСтраницыЗнач As Integer
3 Public dir_file As String ' путь файла с данными о товарах
4 Public ЧислоКолонок As Integer
5 Public ТипЦены As Integer ' оптовая/розничная
6 Public CustSheet As String 1 наименование листа настроек
7 Public ГруппаТовара As String
366
Глава 14
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Public ИндексТекущейГруппы As Integer
Private Sub UserForm_Initialize()	,
1 процедура инициализации формы
Dim КолГрупп As Integer 1 количество групп товаров
CustSheet = "Настройки" 1 имя листа с настройками ' считывание параметров настройки из листа Настройки: НачСтрокаЗнач = _
Activeworkbook.Worksheets(CustSheet).Cells(2, 3)
ДлинаСтраницыЗнач = _
Activeworkbook.Worksheets(CustSheet) .Cells (2, 4)
ЧислоКолонок = _
Activeworkbook.Worksheets(CustSheet) .Cells(1, 4)
ТипЦены = _
Activeworkbook.Worksheets(CustSheet) .Cells (3, 4) ' подготовка окна списка Группа КолГрупп = _
ActiveWorkbook.Worksheets(CustSheet).Cells(3, 3)
For i = 1 To КолГрупп
Группа.Additem _
(ActiveWorkbook.Worksheets(CustSheet) .Cells (i, 1) .Value)
Next
' текущая группа:
ИндексТекущейГруппы = _
ActiveWorkbook.Worksheets(CustSheet) .Cells (1, 3) ГруппаТовара = _
ActiveWorkbook.Worksheets(CustSheet) .Cells ( _ ИндексТекущейГруппы, 1)
' настройка элементов управления диалогового окна ' согласно листа Настройки
НачальнаяСтрока.Value = НачСтрокаЗнач ДлинаСтраницы.Value = ДлинаСтраницыЗнач
If ЧислоКолонок = 1 Then	i
Кол_Одна.Value = True Кол_Две.Value = False
Else
Кол_Одна.Value = False
Кол_Две.Value = True
End If
If ТипЦены = 1 Then Цена_Опт.Value = True 'цена оптовая	'
Цена_Розн.Value = False
Else
Цена_Опт.Value = False 'цена розничная Цена_Розн.Value = True
End I f
Группа.Value = ГруппаТовара
Элементы диалоговых окон
367
71	1
72 End Sub
73
74
75	Private Sub Кн_Выход_С11ск()
76	' выход из программы с подтверждением
77
78	Dim	Msg, Title,* Response As String
79	Dim	Style
80
81	Msg	= "Хотите закончить работу?"
82	Style = vbYesNo + vbCritical + vbDefaultButton2
83	Title = "Выход из программы"
84	Responce = MsgBox(Msg, Style, Title)
85
86	If Responce = vbYes Then
87	Unload Me
88	End If
89	End Sub
90
91	Private Sub Кн_Обновить_С11ск()
92	' событие - выбор кнопки Обновить
93
94 MsgBox ("Эта кнопка не работает")
95
96 End Sub
97
98
99 Private Sub Кол_Одна_С11ск()
100 ' событие - выбор переключателя Одна (колонка)
101
102	ЧислоКолонок = 1	,
103
104	' запись в лист Настройка
105	ActiveWorkbook.Worksheets(CustSheet) .Cells (1, 4) = _
106	ЧислоКолонок
107 End Sub
108
109
110 Private Sub Кол_две_СИск ()
111 1 событие - выбор переключателя Две (колонки)
112
113	ЧислоКолонок = 2
114
115	' запись в лист Настройка
116 ActiveWorkbook.Worksheets(CustSheet).Cells(1, 4) = ЧислоКолонок
117 End Sub
118
119
120 Private Sub Цена_Опт_С11ск()
121 ' событие - выбор переключателя Оптовая (цена)
122
123	ТипЦены = 1
124
125	' запись в лист Настройка
126 ActiveWorkbook.Worksheets(CustSheet) .Cells (3, 4) = _
127	ТипЦены
128 End Sub
129
130
131 Private Sub Цена_Розн_С11ск()
132 1 событие - выбор переключателя Розничная (цена)
133
368
Глава 14
134	ТипЦены = 2
135
136	' запись в лист Настройка
137 ActiveWorkbook.Worksheets(CustSheet) .Cells (3, 4) = _
138	ТипЦены
139 End Sub
140
141	•
142 Private Sub Framel_Click()
143 ' событие - неправильно выбран элемент управления
144
145 MsgBox ("У Вас сегодня не очень твердая рука1")
146
147 End Sub
148
149
150 Private Sub Зр1п_ДлинаСтр_Зр1пОс’л’п ()
151 ' событие - выбор стрелки "Вниз" элемента управления SpinButton
152
153	ДлинаСтраницыЗнач = ДлинаСтраницыЗнач -	1
154	ДлинаСтраницы.Value = ДлинаСтраницыЗнач
155
156	' запись в лист Настройки
157 ActiveWorkbook.Worksheets(CustSheet).Cells(2, 4) = _
158	ДлинаСтраницыЗнач
159 End Sub
160
161
162 Private Sub Зр1п_ДлинаСтр_ЗргпОр()
163 ' событие - выбор стрелки "Вверх" элемента управления SpinButton
164
165	ДлинаСтраницыЗнач = ДлинаСтраницыЗнач +	1
166	ДлинаСтраницы.Value = ДлинаСтраницыЗнач
167
168	' запись в лист Настройки
169 ActiveWorkbook.Worksheets(CustSheet) .Cells (2, 4) = _
170	ДлинаСтраницыЗнач
171 End Sub
172
173
174 Private Sub Spin__Ha4CTp_SpinDown()
175 ' событие - выбор стрелки "Вниз” элемента управления SpinButton
176
177	НачСтрокаЗнач = НачСтрокаЗнач - 1
178	НачальнаяСтрока.Value = НачСтрокаЗнач
179
180	' запись в лист Настройки
181 ActiveWorkbook.Worksheets(CustSheet).Cells(2, 3) = _
182	НачСтрокаЗнач
183 End Sub
184
185
186 Private Sub Spin_Ha4CTp_SpinUp()
187 ' событие - выбор стрелки "Вверх" элемента управления SpinButton
188
189	НачСтрокаЗнач = НачСтрокаЗнач + 1
190	НачальнаяСтрока.Value = НачСтрокаЗнач
191
192	' запись в лист Настройки
193 ActiveWorkbook.Worksheets(CustSheet).Cells(2, 3) = _
194	НачСтрокаЗнач
195 End Sub
196
Элементы диалоговых окон
369
197
198 Private Sub rpynna_Change()
199 ' работа окна комбинированного списка
200
201	ГруппаТовара = Группа.Value
202	ИндексТекущейГруппы = Группа.Listindex
203
204	' запись в лист» Настройки
205 ActiveWorkbook.Worksheets (CustSheet).Cells (1, 3) =
206	ИндексТекущейГруппы + 1
207
208 End Sub
Рис. 14.16
Код, управляющий работой диалогового окна (рис 14 15), использует и изменяет данные листа Настройки
Если вы введете в модуль формы представленный код и запустите форму на выполнение (Run | Run Macro), то увидите, что диалоговое окно выполняет все операции, предоставляемые элементами управления, кроме операции кнопки Обновить. Рассмотрим код подробно.
В строках 10-72 записан код процедуры, которая выполняется при первой загрузке формы в память. Здесь из листа Прейскурант активной рабочей книги считываются данные из определенных ячеек (строки 20-44) и присваиваются свойству Value некоторых элементов управления (строки 51-68).
Обратите внимание на подготовку данных для окна комбинированного списка Группа товара (строки 32-45). Здесь из ячейки СЗ листа Настройки считывается количество групп товаров (перечисленных в колонке А того же листа). Далее (строки 36-39) в цикле в коллекцию Группа комбинированного списка заносятся наименования групп из листа Настройки. В строках 42-43 из листа Настройки считывается индекс текущей группы, в строках 44-45 определяется текущая группа товара. В результате работы событийной процедуры UserForm_Initialize диалоговое окно появляется перед вами не с пустыми текстовыми окнами и переключателями.
В строках 75-89 находится код событийной процедуры Кн_Выход_СИск, которая, как нетрудно догадаться, выполняется при нажатии на кнопку Выход. Процедура выполнена в «лучших интерфейсных традициях» и перед окончанием сеанса требует подтверждения об окончании работы с приложением.
Далее по тексту (строки 91-96) следует «заглушка» процедуры Кн_Обно-вить_СИск, которая является единственной процедурой, выполняющей полезную работу, но пока не разработана. Прием использования программных «заглушек» пришел к нам из нисходящего проектирования при использовании идеологии структурного программирования. Идея нисходящего проектирования заключается в том, что сначала следует разработать код общей управляющей части про
370
Глава 14
граммного комплекса, без учета работы отдельных его элементов. Для отладки общего кода отдельные его элементы (подпрограммы) заменяются «заглушками», которые, например, только принимают данные и каким-либо образом сообщают о том, что им передано управление и данные. Когда верхний уровень программного комплекса отлажен, приступают разрабатывать код нижнего уровня, заменяя «заглушки» (которые, быть может, также вызывают «заглушки» более нижнего уровня) полезным кодом. При этом «заглушки», имеющие отлаженный с верхним уровнем комплекса интерфейс, могут кодировать разные группы программистов.
Подобным образом вы можете разрабатывать код событийных процедур — сначала детально отладить работу с диалоговым окном, а затем — полезную часть кода. В нашем случае, конечно, единственная полезная кнопка — это Обновить. Она обновляет лист с прейскурантом. Все остальные элементы управления только настраивают параметры прейскуранта, взаимодействуя с листом настроек.
Процедура Кол_Одна_СИск (строки 99-107) обрабатывает событие выбора переключателя Одна группы Колонки. При этом переменной ЧислоКолонок присваивается значение 1, которое также заносится в ячейку D1 листа Прейскурант. Процедура Кол_две_СПск (строки 111-119) обрабатывает событие выбора переключателя Две группы Колонки. При этом переменной ЧислоКолонок присваивается значение 1, которое также заносится в ячейку D1 листа Настройки.
Аналогично предыдущим устроены процедуры Цена_Опт_СИск и Це-на_Розн_СИск (строки 120-139). Результат выбора переключателей Оптовая и Розничная записывается в ячейку D3 листа Настройки.
Процедуры 8рш_ДлинаСтр_8ршВо\уп (строки 150-159) и 8рш_ДлинаСтр_ SpinUp (162-171) устроены одинаково и предназначены для уменьшения и увеличения, соответственно, значений переменной ДлинаСтраницыЗнач и записываются в текстовое поле ДлинаСтраницы диалогового окна и ячейку D2 листа Настройки.
Процедуры Spin_Ha4CTp_SpinDown (строки 174-183) и Spin_Ha4CTp_Spin-Up (186-195) устроены одинаково и предназначены для уменьшения и увеличения, соответственно, значений переменной НачСтрокаЗнач и записываются в текстовое поле НачальнаяСтрока диалогового окна и ячейку С2 листа Настройки.
И, наконец, завершает (строки 198-208) приведенный код процедура Груп-na_Change, обслуживающая окно комбинированного списка. Здесь переменной ГруппаТовара присваивается свойство Value, а переменной ИндексТекущейГруп-пы — свойство Listindex объекта Группа. Значение (ИндексТекущейГруппы + 1) сохраняется в листе Настройки.
Для проверки работы рассматриваемого диалогового окна расположите окно в режиме выполнения так, как показано на рис. 14.17, и, манипулируя элементами управления, наблюдайте за изменениями, происходящими с данными на листе Настройки.
Таким образом, предварительные действия, связанные с построением диалога, завершены. Остается написать программу, связанную с кнопкой Обновить и использующую всю вводимую в диалог информацию. Перед первым выводом диалогового окна на экран можно, используя лист Настройки, записать в лист Прейскурант данные из DBF-файла, Вывод диалогового окна на экран можно выполнять при помощи панели инструментов (добавив перед этим на панель новую кнопку) или посредством меню.
Немного о способах попадания данных в лист Настройки. Их несколько. Начинающий программист-разработчик приложения может записать данные один раз вручную и объяснить пользователю важность правильного хранения этого листа. Можно при этом снабдить лист комментариями подобно тому, как показано на рис. 14.16. Достаточно подготовленный программист может предусмотреть кнопку настройки листа Настройки в режиме диалога с пользователем. В этом случае лист можно скрыть от пользователя и пользователь даже не будет знать о существовании листа.
Элементы диалоговых окон
371
Рис. 14.17
Работу диалогового окна Прейскурант можно проверить без написания кода для кнопки Обновить
'Sp*] файл Правка Вид Вставка Формат Сервис Данные Окно Справка Щ 100% -	7 Arial Суг	’ 10 •» ж к ч — =g
8
9
10
(ЗХВ) Диски для X Box
(DVS) Другие DVD
(GA) Картриджи для GB
(GBA) Картриджи для GB Advanc
(MP4) Диски MP4
(R)
(REK) Рекламные
(TV) Телевизоры
АМС
РМ
SRC
(ЗХВ) (DVS) (GA)
20
9
40
Ндстроики npeitcKvp-»irra
Начать со строки
ДлинаСтраницы
2
53
12	Аккустика (АС)
13	Аксессуары (А)
14	Аксессуары к PC (PC)
15	Диски PC (PC CD)
16	ЗИП(З)
17	Игровые приставки (К)
18	Картридж Game boy (G)
19	Картридж Game boy (цвет)(ОС)
20	Картридж Nintendo 64 b t (N64)
► н\ Прейскурант \Настройки
Цена	Колонки
• Оптовая	Одна
Розничная	• Две
Грута товара
Обновить J
Картридж Nintendo 64-bit (N64)
Выход ।
2
5
6
Стиль предыдущего абзаца, по крайней мере, должен был навести читателя на мысль о том, что работу над оставшейся частью программы ему предлагается выполнить самому. Это связано с тем, что далее решается очень специфическая задача, а знаний у читателя для ее решения уже должно хватать.
15
Отладка VB-кода.
Поиск и устранение ошибок
К сожалению, начинающие программировать недостаточно серьезно подходят к вопросам, о которых пойдет речь в этой главе. Даже некоторые опытные программисты утверждают, что в методах отладки нет необходимости — «нужно просто писать код без ошибок». На практике же получается, что отсутствие навыков в вопросах отладки приводит к большим потерям времени.
Как бы вы ни старались, кода без ошибок не бывает. Каждая последняя найденная вами ошибка должна всего лишь придавать вам уверенности в том, что скоро вы найдете еще одну (снова «последнюю») ошибку.
Процесс нахождения ошибок (bugs) в приложении называется отладкой (debugging). В этой главе рассматриваются средства отладки Visual Basic и вопросы «управления» ошибками времени исполнения.
Типы ошибок
Все ошибки, которые могут возникать при создании и эксплуатации приложения, можно разделить на: синтаксические ошибки (syntax errors), ошибки компи ляции (compile errors), ошибки времени исполнения или runtime-ошибки (runtime errors). Иногда говорят еще и о логических ошибках, которые связывают с тем, что программа выполняет не то, что хотел разработчик, но для системы программирования это не является ошибкой.
Синтаксические ошибки возникают в результате неправильного ввода кода. Это самые простые ошибки: они обнаруживаются редактором кода Visual Basic сразу и являются результатом несоблюдения разработчиком синтаксиса языка или просто невнимательности при вводе кода. Например, можно случайно написать идентификатор для какой-либо переменной, совпадающий с ключевым словом, или неправильно указать аргументы для встроенной функции. К синтаксическим, например, относятся орфографические ошибки при вводе ключевого слова VBA, имени переменной или подпрограммы. Редактор VB «способен» распознавать большинство синтаксических ошибок по мере того, как вы редактируете или вводите текст программы. (VBA выполняет проверку синтаксиса, когда вы перемещаете курсор вставки с вновь отредактированной или набранной строки). Другие синтаксические ошибки могут проявляться как ошибки при трансляции. В общем, все, на что редактор кода Visual Basic (во время ввода кода) реагирует выводом окна сообщения (рис. 15.1), сопровождаемым звуковым сигналом, — это синтаксические ошибки. Обратите внимание на то, что сам редактор VB называет синтаксическую ошибку ошибкой компиляции (Compile error) — редактор VB проверяет синтаксис запуском компилятора, и ошибка происходит во время компиляции, хотя это не означает, что ошибка не синтаксическая.
Ошибки компиляции возникают при попытке запустить подпрограмму, содержащую оператор, который VBA не в состоянии правильно откомпилировать. Если у VBA возникают какие-либо трудности в процессе компиляции написанного вами кода, то он выдает сообщение об ошибке и не создает оттранслированного кода. Например, если в вашем модуле содержится оператор Option Explicit и используется переменная без ее предварительного объявления (с помощью оператора Dim), VBA перемещает курсор вставки в точку, где обнаружена переменная, которую забыли
Отладка VB-кода. Поиск и устранение ошибок
373
Рис. 15.1
Обычно так редактор
VB сообщает об ошибках синтаксиса
* ' «». cl ».
[T FHe gdt View insert f й .у й * ем
Pun look &dd-Ins Window Цф i 	4.4 Й? Ч’ Л © Ln 15 Cd 26
”3 !т«яР"1
Sub
TestPut () ~ ip иле. I
Din MyRecord As
Record Rej
End
Sub
Kill TESTFILE”
Open "TESTFILE"
Microsoft Visual Basic
For
Rardom
a
Compile error
Expected var able
Put #1 1 MyRecord
Close #1 Sub
TestTestPut ()
Help
MyRecord FirstName
'Петр

объявить, и выдает сообщение об ошибке компиляции (рис. 15.2) Заметьте, что в отличие от синтаксической ошибки эта ошибка обнаруживается при попытке вы полнить код процедуры.
Рис 15.2
Эта ошибка была обнаружена при попытке выполнить код процедуры
[j| Bte f-dtt tfew [nsert Format Debug Rin Tods Add-Ins ® J-И M ^ueneial)
iyndow
Ln 45 Col 4
I esi jet
Close #1 End Sub
sub TestGetO
Mfcrasmft Visual Basie
law - Tjima (гмппгэд] -
Din MyRecord As Open "TESTFILE
Rec For LOF(l) \
|\^ Compile error
vanable not defined
MyRecord)
Help
For RecordNumber -See) #1 Record Cet #1 MyRec Debug Print MyRecord FirstName i Next RecordNumber
&. MyRecord ID
Close #1
Ошибки времени исполнения или runtime-ошибки возникают, когда VBA встречает выражения или операторы, которые не удается вычислить или выполнить, например, содержащие недопустимые команды, недопустимые аргументы в процедурах и функциях, или недопустимые математические операции. Эти ошибки проявляются в процессе выполнения программного кода. Вот типичные примеры, приводящие к появлению runtime-ошибок:
	выражения, в результате которых происходит математическое переполнение,
	несоответствие типов переменных в выражениях присваивания или в аргументах подпрограммы;
	попытка открыть несуществующие файлы;
	попытка выполнить деление на ноль.
На рис. 15.3 в строке кода для вызова процедуры записи массивов nFirst-Name, nLastName и nID в файл с произвольным доступом
Call TestPut(nFirstName, nLastName, , nID)
374
Глава 15
оказалась лишняя запятая. VBA, как «мог», проанализировал строку и «решил», что мы хотели вызвать процедуру с пропущенным аргументом. На самом деле, никакая система не в состоянии абсолютно точно указать причину ошибки, поэтому не всегда можно понять из диагностики, какая же ошибка произошла в действительности.
Рис. 15.3
Ошибка в вызове процедуры
End sub
* сдав» ti - р
Bit tfew Insert Format Qebug Bun loots fcdd-lns « t *
й Д/й	‘	> и «М	Ln 3 Cd 25
pGiiiieral)
sub
TestPut (mFirstName, mLastName mID)
Dim MyRecord As Record, RecordNumber, i Kill "TESTFILE" Open "TESTFILE' For Raroom As #1 Len = Len(MyRecord) RecordNumber = UBound(mFirstName) For i = 0 To RecordNumber - 1
MyRecord.FirgtN MyRecord LastNa MyRecord ID = m Put #1, i+l, Next Close #1 Sub TestTestPut () Dim nFirstName(2),
nFirstName(0) = "Петр" nLastName(O) = 'Петров' nID(0) = 333 nFirstName(0) - "Сидор" nLastName(O) = "Сидоров nID(0) = 222

Конечно же, «классическим» примером ошибки времени исполнения является попытка деления на ноль, при возникновении которой выдается диалоговое окно, представленное на рис. 15.4. Следует отметить, что попытка разделить на ноль необязательно связана с невнимательным делением чего-либо на число ноль. Это может произойти (и чаще всего так и бывает) в результате того, что некоторая переменная (или выражение), являющаяся делителем, непосредственно перед делением будет оценена как нулевое значение.
Рис. 15.4
Ошибка деления на ноль
Средства отладки
Рассмотрим средства отладки кода, предоставляемые системой VBA. Как и все современные системы, VBA имеет функции интерактивной отладки кода. Во-первых, это — панель Debug, которая представлена на рис. 15.5. Панель инструментов Debug не выводится на экран автоматически. Чтобы ее вывести, выберите в меню команду View | Toolbars | Debug (Вид | Панели инструментов | Отладка). (Когда панель инструментов выведена на экран, в меню слева от опции Debug появляется «галоч-
Отладка VB-кода. Поиск и устранение ошибок
375
ка».) Панель инструментов Debug можно перемещать так же, как и любую другую панель инструментов и настраивать ее подобно панелям инструментов Windows-приложений.
9	11	13
Рис. 15.5. Панель Debug
1 - Exit Design Mode, 2 - Run Sub/UserForm, 3 - Break, 4 - Reset, 5 - Toggle Breakpoint,
6 - Step Into, 7 - Step Over, 8 - Step Out, 9 - Locals Window, 10 - Immediate Window,
11 - Watch Window, 12 - Quick Window, 13 - Call Stack
Наименования кнопок, указанных на рисунке, появляются на экране рядом с панелью, когда курсор мыши на несколько секунд остается на соответствующей кнопке. Назначение кнопок приведено в следующей таблице.
Кнопка	Назначение
Exit Design Mode	Переводит design-режим в состояние off или on.
Run Sub/UserForm	Служит для переключения из режима разработки в режим выполнения (Run) или из режима прерывания в режим выполнения (Continue). В режиме прерывания название кнопки меняется на Continue.
Break	Останавливает выполнение приложения и переключает систему отладки в режим прерывания.
Reset	Очищает стек выполнения и переменные модульного уровня. Завершает выполнение кода.
Toggle Breakpoint	Устанавливает или отменяет в текущей строке точку останова. Здесь можно прервать программу, просмотреть некоторые данные и после продолжить выполнение кода.
Step Into	Выполняет следующую строку кода с заходом в процедуры. Код процедуры выполняется по шагам, как и до входа в процедуру.
Step Over	Выполняет следующую строку кода без захода в процедуры. Код процедуры выполняется как одна команда.
Step Out	Выполняет оставшуюся часть текущей процедуры и останавливает работу прРграммы на следующей строке вызывающей процедуры.
Locals Window	Отображает текущие значения локальных переменных в отдельном окне.
Immediate Window	Позволяет выполнить нужные операторы или просмотреть значения переменных в режиме прерывания.
Watch Window	Открывает окно с текущими значениями выбранных выражений.
Quick Watch	Отображает текущее значение выражения в режиме прерывания.
Call Stack	Отображает в режиме прерывания окно со списком вызванных, но еще не выполненных процедур (стек вызовов).
376
Глава 15
Замечание'. Эта панель по умолчанию не появляется на экране. Вы сами можете вызвать ее, выполнив команды: View, Toolbars, Debug.
Режимы отладки
Чтобы тестировать и отлаживать (находить ошибки) приложение, вам необходимо понять, какие режимы работы используются при создании нового приложения. Основная часть работы происходит в режиме разработки {design time). После того как разработчик приложения выбирает команды Run, Start, редактор VB переходит в режим исполнения {run time). Этот режим еще не является «боевым», поскольку поддерживается средой редактора VB и разработчик имеет возможность тем или иным способом приостановить выполнение кода в определенном месте для выполнения отладочных операций, т.е. перейти в режим прерывания. В режиме прерывания {break mode) программа не выполняется, но занимает память; здесь вы можете просматривать и изменять значения переменных и выражений и даже перемещаться по коду, выполняя один или группу операторов.
Основное время при создании приложения занимает режим разработки. Здесь к приложению добавляются формы, элементы управления на формах, модули кода и так далее. В этом режиме используется только одно средство отладки — редактор кода, но, кроме того, вы можете расставить точки останова и определить контрольные выражения.
В заголовке главного окна Visual Basic всегда отображается режим, в котором в данный момент времени находится система: в заголовке окна приложения после имени документа в квадратных скобках помещаются слова design, running, break. Для переключения режимов можно, кроме меню, использовать кнопки Start, Break и End панели Debug.
Режим останова
В процессе отладки программы у вас часто будет возникать потребность, проследить за тем, как именно VBA выполняет операторы вашей программы и какие значения принимают некоторые переменные на разных этапах ее выполнения. Режим останова редактора VB предоставляет возможность более близкого «взаимодействия» с написанным вами VBA-кодом по сравнению с обычным его выполнением (когда код выполняется от начала до конца с максимальной скоростью, которую может обеспечить VBA, и вы не в состоянии уследить ни за тем, какие части кода исполняются в данный конкретный момент, ни за тем, чему в этот момент равны значения интересующих вас переменных). В режиме же останова вы получаете возможность исполнения кода вашей программы или отдельных его частей построчно или по одной подпрограмме за шаг, как в замедленной съемке. Пооператорное выполнение программы называется пошаговым {single-stepping) проходом.
В VBA перевести редактор VB в режим останова можно следующими способами:
	Щелчком на кнопке Debug (Отладка) в диалоговом окне runtime-ошибки.
	Задав одну или несколько точек останова.
	Вставив в текст программы оператор Stop.
	Воспользовавшись командой Debug | Step Into (Отладка | Шаг с заходом), кнопкой Break или Step Into на панели Debug (или нажав F8).
	Нажав Esc или Ctrl+Break, чтобы прервать выполнение программы.
Переход в режим останова из окна сообщения об ошибке
Всякий раз, когда в процессе выполнения одной из ваших VBA процедур или функций происходит runtime-ошибка, появляется диалоговое окно ошибки, подобное тому, что показано на рис. 15.4 (конкретное сообщение об ошибке может
Отладка VB-кода. Поиск и устранение ошибок
377
быть другим, в зависимости от того, какая именно ошибка произошла). В диалоговом окне выводится номер ошибки и дается краткое пояснение характера ошибки. Кроме того, оно имеет несколько кнопок.
В диалоговом окне, появляющемся при возникновении runtime-ошибки, имеются следующие кнопки:
	Continue (Продолжить) — продолжить выполнение прерванного VBA-кода.
В случае возникновения runtime-ошибки управляющая кнопка Continue, как правило, отключена (см. рис. 15.4).
	End (Завершить) — завершить выполнение VBA-кода и выйти из режима останова.
	Debug (Отладка) — вывести оператор VBA, который привел к возникновению runtime-ошибки; в случае необходимости открываются соответствующие проект и модуль. VBA остается в режиме останова, позволяя разработчику VBA-приложения проверить значения переменных, проследить цепочку подпрограмм, приведшую к подпрограмме, исполняемой в данный момент, и ряд других параметров связанных с отладкой. Используйте кнопку Debug для быстрого перехода к оператору, выполнение которого привело к появлению ошибки.
	Help (Справка) — вывести диалоговое окно со справочной информацией, относящейся к возникшей runtime-ошибке.
Для того чтобы перейти в режим останова из диалогового окна сообщения о runtime-ошибке, просто нажмите на кнопку Debug. Редактор VB откроет Code Window (окно кода), в котором появится выделенный желтым цветом оператор, приведший к появлению runtime-ошибки.
Точки останова
Для того чтобы обнаружить причину появления runtime- и логических ошибок, в большинстве случаев приходится прибегать к пошаговому выполнению операторов разрабатываемой программы. Пошаговый проход программы, позволяет либо точно узнать, какой оператор выполнялся в момент возникновения runtime-ошибки, либо дает возможность проконтролировать выполнение группы операторов, в корректности исполнения которых разработчик сомневается.
Пошаговый проход всех операторов подпрограммы, а тем более программы в целом, может оказаться занятием довольно утомительным и требующим больших затрат времени. Желание или возможность выполнить пошаговый проход всех операторов программы возникает нечасто. Редактор VB позволяет выполнить большую часть кода с максимальной скоростью, переходя в режим останова только тогда, когда это необходимо для выполнения отдельных операторов кода. (Помните, чтобы выполнить пошаговый проход кода, необходимо находиться в режиме останова.)
Точка останова (breakpoint) — это специально помеченная строка программы. Когда VBA доходит до точки останова, происходит его переключение из режима обычного выполнения программы в режим останова. Использование точек останова позволяет выполнить большую часть программы с полной скоростью с переходом в режим останова, только когда VBA достигает определенных операторов, выполнение которых вы хотите проверить более тщательно. Точка останова «действует» до тех пор, пока вы ее не удалите или не закроете проект, содержащий модуль, в котором она установлена.
Точку останова можно поместить в любой строке исходного кода, содержащей исполняемый оператор. Обычно точка останова задается перед оператором, который, как вы знаете (или предполагаете), является причиной возникновения проблем. Для того чтобы задать точку останова, необходимо выполнить следующие шаги:
378
Глава 15
1.	Выведите на экран VBA модуль и подпрограмму, содержащие операторы, для которых вы хотите задать пошаговое выполнение.
2.	В Code Window (окне программы), поместите курсор вставки на строке, начиная с которой нужно, чтобы VBA переключился из обычного выполнения программы в режим останова. Эта строка станет новой точкой останова и должна содержать выполняемый оператор VBA.
3.	Выберите команду Debug | Toggle Breakpoint (Отладка | Точка останова), чтобы вставить точку останова. [Вы также можете нажать клавишу F9 или воспользоваться кнопкой Toggle Breakpoint (Точка останова) на панели инструментов Debug (Отладка) редактора VB.] VBA выделяет выбранную в качестве точки останова строку (темно красным цветом), как показано на рис. 15.6; а рядом со строкой у левой границы Code Window появляется (темно-красная) точка.
Рис. 15.6
VBA выделяет выбранную в качестве точки останова строку, а рядом со строкой у левой границы окна Code Window появляется точка
Чтобы удалить точку останова, необходимо проделать те же самые действия, что и для ее вставки. Если применить команду Toggle Breakpoint к строке, содержащей точку останова, VBA удалит эту точку. Для того чтобы удалить все точки останова в модуле, необходимо выбрать команду Debug | Clear All Breakpoints (Отладка | Снять все точки останова) или нажать клавиши Ctrl+Shift+F9.
Использование оператора Stop
Точки останова, заданные при помощи команды Toggle Breakpoint, «действуют» только в течение текущего рабочего сеанса. Иногда, особенно в случае сложных программ, отладка может потребовать нескольких рабочих сеансов. Поэтому вы, возможно, захотите установить «многоразовые» точки останова. Именно для этой цели целесообразно использовать ключевое слово Stop.
Когда VBA встречает оператор Stop, выполнение программы приостанавливается, отображаются модуль и процедура, содержащие выполняемый в данный момент оператор, и происходит переключение в режим останова. При использовании оператора Stop создается постоянная точка останова, то есть она, фактически, становится частью VBA-кода. Единственный способ удалить точку останова, созданную при помощи оператора Stop, — это удалить сам оператор Stop из исходного кода.
Как правило, оператор Stop вставляют в текст программы в случаях, когда нужна постоянная точка останова. После завершения отладки программы необходимо отредактировать текст программы, удалив из него операторы Stop.
Отладка VB-кода. Поиск и устранение ошибок
379
Переход в режим останова с помощью команды Step Into
Вы уже знаете, что можете запустить выполнение процедуры непосредственно из исходного кода, используя команду Run | Run Sub/UserForm или нажав с помощью мыши кнопку Run Sub/UserForm на панели инструментов Debug. Подобным же образом можно запустить на выполнение любую процедуру в режиме останова. Просто поместите курсор вставки внутрь процедуры, которую хотите выполнить в режиме останова, и выберите команду Debug | Step Into (Отладка | Шаг с заходом). (Вы также можете нажать F8 или щелкнуть мышью по расположенной на панели инструментов Debug кнопке команды Step Into.) VBA перейдет в режим останова и покажет текущий исполняемый оператор подпрограммы. Как упоминалось выше, в режиме останова текущий исполняемый оператор выделяется в Code Window желтым цветом и стрелкой у левой границы текста кода (как показано на рис. 15.7).
Рис. 15.7
В режиме останова текущий исполняемый оператор выделяется в Code Window желтым цветом и стрелкой у левой границы текста кода
Переход в режим останова прерыванием исполнения кода
Как вы уже знаете, VBA прерывает выполнение кода, когда пользователь нажимает клавишу Esc (или комбинацию Ctrl+Break). Когда вы прерываете исполнение кода, VBA выдает диалоговое окно ошибки с сообщением, что выполнение кода было прервано, и предлагает те же самые возможности выбора, что и диалоговое окно, появляющееся при возникновении runtime-ошибки: Continue, End, Debug и Help. Чтобы перейти к выполнению программы в режиме останова, нажмите на кнопку Debug. VBA перейдет в режим останова и укажет оператор, выполнявшийся в тот момент, когда вы прервали процедуру.
Выход из режима останова
Часто возникает необходимость «пройти» часть программы в пошаговом режиме, после чего завершить выполнение оставшейся части в обычном режиме. Возможно, в некоторых случаях вы также захотите как выйти из режима останова, так и завершить выполнение программы, чтобы получить возможность, внести исправления в текст программы для устранения выявленных в режиме останова ошибок.
Для того чтобы выйти из режима останова и продолжить выполнение программы в обычном режиме, воспользуйтесь командой Run | Continue (Запуск | Продолжить). VBA выйдет из режима останова и продолжит выполнение программы до тех пор, пока не произойдет ее нормальное завершение. Если VBA встретится с точкой останова или оператором Stop, прежде чем достигнет конца программы,
380
Глава 15
то произойдет переход в режим останова. (Выйти из режима останова и продолжить выполнение программы, можно также нажатием F5 или щелчком мышы по кнопке Continue на панели инструментов Debug.)
Для того чтобы выйти из режима останова и одновременно завершить выполнение всех программ, выберите команду Run | Reset (Запуск | Сброс). VBA выйдет из режима останова и прервет дальнейшее выполнение программы, все переменные потеряют свои значения, а все процедуры будут удалены из памяти. (Вы можете также выйти из режима останова и завершить выполнение программы, щелкнув мышью по кнопке Reset на панели Debug.)
Использование команды Step Into
Теперь, вы знаете, как перейти в режим останова и как из него выйти, поэтому можно приступить к изучению использования команды Step Into (шаг с заходом) г я я пошагового выполнения программы в режиме останова. Пошаговое выполне-ие операторов позволяет в процессе отладки проследить за исполнением отдельных процедур, функций или программы в целом. При пошаговом проходе исходного кода с использованием команды Step Into VBA входит в тело каждой вызываемой процедуры или функции, давая возможность выполнить в пошаговом режиме и их операторы тоже. Пошаговое выполнение программы с использованием команды Step Into позволяет проследить за выполнением всех операторов главной процедуры и всех операторов каждой функции или процедуры, вызываемых из основной программы.
В Code Window операторы, которые будут выполняться следующими, выделены желтым цветом. Если код не такой простой, как в процедуре TestTestPut, име,-ет условные операторы или операторы циклов, то пошаговый проход программы, выполняемый таким образом, может в некоторых случаях помочь понять, правильно ли работают используемые разработчиком приложения программные структуры. Перед выполнением следующей команды можно, помещая курсор вставки на переменные или выражения, в окне ToolTip просмотреть значение переменной или выражения.
Режим подсказки значений данных (позволяющий просматривать значения выражений в окне типа ToolTip) по умолчанию включен. Если по каким-то причинам на вашем компьютере подсказки не работают, выберите команду Tools | Options и на вкладке Editor окна Options выберите флажок Auto Data Tips.
Наблюдение за значениями выражений
Если в процессе пошагового выполнения операторов кода вас интересует не только последовательность выполнения операторов, но и изменение значений переменных, то вас вряд ли удовлетворит возможность просматривать значения переменных (и даже выражений) в окне ToolTip. Редактор VB имеет окно Watches, в котором можно просматривать значения выражений по мере пошагового выполнения кода. Например, на рис. 15.8 приведено окно Watches, в котором отображается значение переменной nFirstName(O) процедуры TestTestPut модуля Modulel.
Рис. 15.8
В режиме пошагового выполнения кода в Watch Window можно наблюдать за изменением значений выражений (переменных)
3 Watches			ИИ
| Expression 		j Value		|Type	Jcpntext
1® nF'r	’’Петр’  /	VananfzSinng	Moduhl.lr.*:
«и
Отладка VB-кода. Поиск и устранение ошибок
381
Для просмотра значений выражений (переменных) процедуры необходимо занести (добавить) эти выражения в окно Watches. Это можно выполнить двумя способами, предварительно выделив выражение (для переменной можно просто поместить на ней курсор вставки):
 Из контекстного меню (правой кнопки мыши) выбрать опцию Add Watch.
* Из меню Debug выбрать опцию Add Watch.
В любом случае на экране появляется диалоговое окно (рис. 15.9) Add Watch, в котором в самом простом случае можно просто щелкнуть на кнопке ОК, после чего в окне Watches (если ранее его не было на экране, то оно выводится) появляется строка, содержимое которой соответствует содержимому окна Add Watch (рис. 15.10): совпадают поля Expression и Context. В поле Value окна Watches либо отображается значение выражения, либо указывается, что выражение находится «вне контекста» (<Out of context>), либо (для массивов) выводится сообщение о том, что ходит за пределы допустимого диапазона» (<subscript out of range>).
«индекс вы-
Рис. 15.9
диалоговое окно Add Watch, в котором в самом простом случае можно просто щелкнуть на кнопке ОК
Add Watch
Expression
Context
Procedure
Cancel
Module
|TestTeslPut
। Modulel
Help
Project
Project
Watch Type
Watch Expression
Break When Value Is True
? Break When Value Changes
Рис. 15.10
В режиме пошагового выполнения кода
• окне Watch можно наблюдать за изменением значений выражений (переменных)
ДЗ Watches
tression _ _ nFtrstNameflO)
Value ................*Туре ______________ 1 Context^
<Out of context> Variant/Empty	Modulel TestTestPut
Вернемся к окну Add Watch. Как уже можно понять, в секции Expression указывается выражение (переменная), в секции Context — наименование процедуры и модуля, где находится выражение. Если перед вызовом окна Add Watch добавляемое выражение уже указано (выделено), то в секции Context ничего изменять не нужно. Если в момент вывода диалогового окна Add Watch курсор вставки не указывал ни на какую переменную, то в текстовом окне Expression необходимо будет ввести выражение (переменную). В любом случае окна комбинированных списков Procedure и Module в секции Context будут содержать имена текущих процедуры и модуля, на коде которых находится курсор вставки. Конечно, можно воспользоваться этими списками для выбора других доступных модулей и процедур.
Секция Watch Туре окна Add Watch предоставляет дополнительные возможности для отладки. При помощи переключателя Break When Value Is True (останов, если значение выражения истинно) этой секции можно использовать окно Add Watch не в пошаговом режиме выполнения кода, а в обычном. Для подобной же цели можно
382
Глава 15
использовать и переключатель Break When Value Changes (останов при изменении значения выражения). Как уже должно быть понятно, режимом выполнения кода в этих случаях может быть обычный режим. При соответствующих изменениях указанных выражений произойдет переход в режим останова.
Таким образом, если задать в окне интересующие разработчика выражения, можно попеременно задавая то пошаговый, то обычный режим выполнения приложения, просматривать изменения значений выражений.
На рис. 15.11 показаны Code Window и окно Watches при пошаговом выполнении кода приведенного ниже листинга. Наблюдаемыми переменными являются два массива: nFirstName и nID. Оба массива уже получили значения для первых элементов, но nFirstName получил также значение для второго элемента, a nID — нет.
Рис. 15.11
Окно Code и Watches при пошаговом выполнении кода приведенного ниже листинга
Ibeneia!)
End
Sub
▼j sTe«iTesfPut
Sub
TestTestPut()
Dim nFirstName(2), nLastName(2), nID(2) nFirstName(0) = "Петр" nLastName(Q) = "Петров" nID(0) = 333 nFirstName(1) = "Сидор" nLastName(1) = "Сидоров" nlD(l) = 222
Call TestPut(nFirstName, nLastName, nID)
End Sub
#1 Watches

Expression
[Value
64 R nFirstName
T— nFir$lName(O)
1- nFirstName(l)
L nFirstName(2)
"Петр"
'Сидор
Empty
.ГТуре,,, .........___
VanantA/ariant(O to 2)
Vanant/Stnng
Vanant/Stnng
Vanant/Empty
I.Contgxt
Modulel TestTestPut Modulel TestTestPut Modulel TestTestPut Modulel TestTestPut
333 Empty Empty
Vanant/lnteger Vanant/Empty
Vanant/Empty
Modulel TestTestPut
Modulet TestTestPut
Modulel TestTestPut
Листинг 15.1. Код для изучения работы с окном Watches
1	Option Explicit
2	Type Record ' Определенный пользователем тип
3	ID As Integer
4	FirstName As String * 20
5	LastName As String * 20
6	End Type
7
8	Sub TestPut(mFirstName, mLastName, mID)
9	' Тестирование Put
10	Dim MyRecord As Record, RecordNumber, i
11	Kill "TESTFILE"
12	Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
13	RecordNumber	=	UBound(mFirstName)
14	For i	= 0	To	RecordNumber	-	1
15	MyRecord.FirstName = mFirstName(i)
16	MyRecord.LastName = mLastName(i)
17	MyRecord.ID = mID(i)
18	Put #1, i+l, MyRecord
19	Next
20	Close	#1
21	Lnd Sub
22 Sub TestTestPut()
23 Dim nFirstName(2), nLastName(2), nID(2)
24 nFirstName(0) = "Петр"
Отладка VB-кода. Поиск и устранение ошибок
383
25	nLastName(O)	= "Петров"
26	nID(0) = 333
27	nFirstName(1) = "Сидор"
28	nLastName(l)	= "Сидоров"
29	nID(l) = 222
30	Call TestPut(nFirstName, nLastName, nID)
Редактирование наблюдаемого выражения
Наблюдаемые в окне Watches выражения можно редактировать после того, как они уже добавлены в это окно. Чтобы отредактировать контрольное выражение, можно выполнить следующее:
1.	В окне Watches выделите выражение, которое хотите отредактировать.
2.	Выберите команду Debug | Edit Watch (Отладка | Изменить контрольное значение). Эта команда активизирует диалоговое окно Edit Watch, которое отличается от окна Add Watch только заголовком и дополнительной кнопкой Delete (Удалить).
3.	Выполните необходимые исправления в выражении, а также, если необходимо, внесите изменения в разделы Context и Watch Туре. Заметьте, что выражение для контроля может вообще не встречаться в отлаживаемом коде. Важно только, чтобы оно содержало выражения, входящие в код. Например, вы можете остановить выполнение цикла за несколько итераций до указанной в качестве последней или наблюдать изменения не самой переменной некоторой программы, а результат ее деления по модулю на какое-либо число.
4.	Нажав кнопку ОК, закройте диалоговое окно Edit Watch. VBA внесет в окно Watches соответствующие исправления.
Рис. 15.12
Окно Edit Watch отличается от окна Add
Watch только заголовком
и дополнительной кнопкой Delete
Edit Watch
Expression
Context
Procedure
^TestTestPut
Module
Modulel
Project
Project
Delete
Cancel
Help
Watch Type
(• Watch Expression
Break When Value Is True
( Break When Value Changes
Удаление наблюдаемого выражения
По мере работы с наблюдаемыми переменными и выражениями вы можете обнаружить, что список в окне Watches имеет тенденцию разрастаться, и в какой-то момент поймете, что значения далеко не всех находящихся в нем выражений, действительно, необходимо контролировать. Поэтому вам может понадобиться удалить их из окна Watches. Удалить контрольное выражение можно одним из двух способов:
1. Выделите выражение, которое хотите удалить из окна Watches, и нажмите клавишу Del. VBA удалит выделенное выражение из окна без предупреждения.
2. Выделите выражение, которое хотите удалить, затем выберите команду Debug | Edit Watch. В появившемся окне Edit Watch щелкните кнопку Delete. VBA удалит выделенное выражение из окна Watches.
384
Глава 15
Использование команды Step Over
Если код вашего приложения состоит из большого количества процедур, а предполагаемый характер ошибки — неправильный алгоритм вызова этих процедур, то пошаговое выполнение каждой вызываемой процедуры может оказаться достаточно утомительным. Во всяком случае, нет необходимости выполнять по шагам код процедуры, в которой вы абсолютно уверены (хотя, конечно, программист должен быть абсолютно уверен только в том, что в любой процедуре в любой момент времени содержится, по крайней мере, одна ошибка). Но даже, если вы «правильно» не уверены во всех процедурах, на каком-то этапе разработки приложения многие процедуры выполняют то, что от них требуется, и их пошаговое выполнение имеет мало смысла.
Отладчик VBA предоставляет в дополнение к команде Step Into (шаг с заходом) команду Step Over (шаг с обходом). При использовании команды отладки Step Over, если встречается оператор, вызывающий процедуру или определенную пользователем функцию, VBA не переходит к пошаговому выполнению кода вызванной подпрограммы. Вместо этого он выполняет код вызванной подпрограммы с обычной скоростью и продолжает пошаговое выполнение с первого оператора, следующего за вызовом подпрограммы.
Если вы уверены в нормальной работе процедур, вызываемых из некоторой управляющей процедуры, возможность избежать пошагового выполнения подпрограмм помогает сосредоточиться на отладке операторов текущей процедуры. Кроме того, за счет отказа от пошагового выполнения там, где в этом нет необходимости, можно сэкономить затрачиваемое на отладку время.
Использование окна Locals
Окно Locals (Локальные переменные), хотя и не связано с окном Watches, но выполняет похожую функцию (по умолчанию не появляется на экране и вызывается командой View | Locals Window). Оно выводит все локальные (или находящиеся в активной области видимости) переменные выполняемой в данный момент процедуры или функции. На рис. 15.14, например, показаны значения локальных переменных процедуры TestTestPut приведенного ранее листинга.
Окно Locals содержит три колонки: Expression (Выражение) (имя переменной или объекта), Value (Значение) (текущее значение переменной или свойство объекта) и Туре (Тип) (тип данных или объекта). Обратите внимание на прямоугольники слева от элементов mFirstName, mLastName и mID в окне Locals на рис. 15.13. Они аналогичны прямоугольникам в других раскрывающихся древовидных списках Windows. Если в прямоугольнике содержится знак «плюс», это означает, что, щелкнув по нему мышью, можно открыть древовидную диаграмму со свойствами и значениями объекта. Значок «минус» показывает, что диаграмма уже раскрыта и, щелкнув по нему, вы можете ее свернуть. Если щелкнуть по значку «плюс» слева от элемента mFirstName, появится список всех элементов массива и значения, которые каждый из них имеет в настоящий момент. Окно Locals удобно использовать для наблюдения за текущими значениями и структурой переменных и объектов выполняемой в данный момент процедуры, функции или модуля.
Трассировка вызовов процедур
При отладке программ довольно часто возникает необходимость определить точную цепочку или последовательность процедур, приведшую к выполнению конкретного оператора, который порождает ошибки. Знание цепочки вызовов процедур может оказаться полезным, поскольку часто играет важную роль в определении причины ошибки. Например, вы можете обнаружить оператор, приводящий
Отладка VB-кода. Поиск и устранение ошибок
385
Рис. 15.13
Окно Locals при пошаговом выполнении кода приведенного ранее листинга
Sub TestPut(mFirstName, mLastName, mID)	T*
Up ~ > Г	-~J
Dim MyRecord As Record, RecordNumber, i Kill "TESTFILE"
Open "TESTFILE" For Random As #1 Len = Len(MyRecorc___.
RecordNumber = UBound(mFirstName)
For i = 0 To RecordNumber - 1
MyRecord.FirstName = mFirstName(1)
MyRecord.LastName = mLastName(i)
MyRecord.ID = mID(i)
Put #1, i+l, MyRecord
fproject: Modutel TestPut Expression................... i	Value[Type
Щ Module!
Щ mFirstName
Modulet/Module!
Щ mLastName
ПВВВИ k- mlD(D)
U mlD(1)
! L mID(2)
Щ MyRecord RecordNumber
333 222 Empty
2
Vanant/Vanant(O to 2)
Vanant/Vanant(D to 2)
Vanant/lnteger
Vanant/lnteger Vanant/Empty Record Vanant/Long Vanant/Long
к ошибке деления на ноль, но не знаете, почему одна из переменных в операторе содержит ноль. Знание точной цепочки вызовов процедур поможет вам определить, что процедура была вызвана, например, с пропущенным необязательным параметром или просто с неверным значением требуемого аргумента.
VBA позволяет просматривать цепочку вызовов процедур посредством диалогового окна Call Stack (Стек вызова). Чтобы вывести окно Call Stack на экран (в режиме останова), либо выберите команду View | Call Stack (Вид | Стек вызова), либо щелкните мышью по кнопке Call Stack на панели инструментов Debug, либо нажмите Ctrl+L. На экране появится диалоговое окно Call Stack, пример которого показан на рис. 15.14 (последовательность вызовов процедур может быть иной). Как видно из рис. 15.14, диалоговое окно Call Stack выводит список последовательности вызовов процедур, приводящей к выполняемой в данный момент процедуре или функции.
Рис. 15.14
Окно Call Stack и код, посредством которого можно получить такое окно
Sub b_sub(var As String) Call c_sub(var)
End Sub
String)
13 Программирование на VBA 2002
386
Глава 15
Вы, наверное, уже заметили, что диалоговое окно Call Stack содержит две кнопки — Show (Показать) и Close (Закрыть). Кнопка Close просто закрывает диалоговое окно. Кнопка Show выполняет очень полезную функцию и служит для того, чтобы можно было найти оператор, вызвавший исполняемую в данный момент подпрограмму. Кнопкой Show можно воспользоваться для проверки значений аргументов, переданных выполняемой процедуре. Для этого откройте диалоговое окно Call Stack, выберите имя процедуры, которая вызвала текущую процедуру, и щелкните командную кнопку Show. VBA закроет диалоговое окно Call Stack и отметит в окне Code оператор, содержащий вызов текущей процедуры. Используя кнопку Show и диалоговое окно Call Stack, можно пройти в обратном направлении вдоль всей цепочки вызовов подпрограмм.
Использование окна Immediate
Иногда даже сочетания пошагового выполнения программы с использованием наблюдаемых переменных и трассировки вызовов подпрограмм бывает недостаточно, чтобы найти содержащуюся в программе ошибку. В редакторе VB предусмотрено еще одно средство для нахождения ошибок в вашей программе — окно Immediate (Проверка) редактора VB является редактором свободного формата, позволяющим контролировать значения переменных и выражений, производить вычисления, изменять значения переменных и проверять результаты выполнения функций. Все эти функции поддерживаются, когда программа находится в режиме останова. Для того чтобы воспользоваться окном Immediate, выберите View | Immediate Window или введите с клавиатуры комбинацию Ctrl+G, или щелкните на кнопке Immediate Window на панели инструментов Debug. VBA выведет диалоговое окно Immediate.
Чтобы вывести в окне Immediate интересующую вас информацию, используйте оператор Print (или ?). Оператор Print вводится в окне Immediate вместе со списком переменных или выражений. Достаточно набрать команду Print, перечислить интересующие вас переменные и выражения, а затем нажать клавишу Enter. VBA вычислит значения переменных, перечисленных после команды Print, и выведет результаты в строке следующей за командой Print. На рис. 15.15 показан пример работы в окне Immediate.
Рис. 15.15
Просмотр данных в окне
Immediate
| (General)
Next
Close #1
1$ - (С<и
End Sub
sub TestTestPut ()
Dim nFicstName(2), nLastName(2) , nFirstName(0) = "Петр" nLastName(O) = "Петров"
nlD(O) = 333
nFirstName(1) - "Сидор")
nLastName(1) = "Сидоров" nID(l) = 222
Отладка VB-кода. Поиск и устранение ошибок
387
Оператор Debug.Print
Объект VBA Debug имеет метод Print, позволяющий вывести информацию в окно Immediate в процессе выполнения программы. Для этого необходимо добавить в программу VBA операторы, вызывающие метод Debug.Print.
Метод Debug.Print используется, как правило, в сочетании с уже изученным в этой главе оператором Stop. Сочетание этих двух элементов позволяет выполнять программы в обычном (неотладочном) режиме, получая при этом отладочную информацию аналогичную той, которую дает использование наблюдаемых переменных или выражений. Как правило, вы добавляете один или несколько операторов, вызывающих метод Debug.Print, выводящих значения определенных переменных или выражений в окно Immediate. Хотя при выполнении программы в нормальном режиме окно Immediate невидимо, как только VBA встретит оператор Stop и переключится в режим останова, оно сразу станет доступным и позволит вам просмотреть всю информацию, выведенную включенными в программу операторами Debug.Print. Используя этот технический прием, можно сэкономить массу отладочного времени за счет отказа от пошагового выполнения кода. Просмотрев информацию, содержащуюся в окне Immediate, вы можете возобновить выполнение программы в обычном режиме.
Оператор Debug. Assert
Объект VBA Debug имеет метод Assert, приостанавливающий выполнение кода на строке, содержащей этот метод, при выполнении некоторого условия. Синтаксис метода следующий:
СИНТАКСИС
Debug.Assert Bocleanexpression
Аргумент Booleanexpression — логическое выражение, имеющее результатом значение True или False.
Этот метод, практически, выполняет функции оператора Stop, но выполняется, когда его аргумент принимает значение False.
Обработчик ошибок
Обработчик ошибок — это код для перехвата и обработки ошибок в вашем приложении. Создание своего собственного обработчика ошибок состоит из следующих шагов:
	Установки ловушки прерываний (error trap) сообщением места кода, куда следует перейти при возникновении ошибки (адрес обработчика). Этот шаг осуществляется посредством оператора On Error, который делает доступным перехват прерываний и указывает метку, за которой начинается обработчик прерываний.
	Написания процедуры обработки прерываний, связанных с ошибками вашего приложения.
	Обеспечения выхода из процедуры обработки прерывания.
Установка ловушки прерываний осуществляется при помощи оператора On Error, который при этом указывает на обработчик прерывания. Ловушка остается активной на время работы процедуры (функции), в которой она установлена, т.е. до того, как выполнится один из операторов Exit Sub, Exit Function, Exit Property, End Sub, End Function или End Property этой процедуры (функции). В любой момент времени может быть доступна только одна ловушка в данной процеду
13*
388
Глава 15
ре. Но вы можете создавать много ловушек и активизировать их в разное время. Ловушку можно сделать неактивной применением специального типа команды On Error — On Error GoTo 0.
Простой синтаксис оператора On Error GoTo имеет следующий вид:
СИНТАКСИС
On Error GoTo label
Здесь label — метка (отмечаемая в коде двоеточием за ней), за которой начинается обработчик.
Итак, первым оператором блока кода обработки прерывания по ошибке является метка с двоеточием за ней. Далее без всяких ограничивающих блоки операторов следует писать код, который, кстати, необязательно должен обрабатывать ошибки: вы можете просто констатировать факт наличия ошибки. Во-первых, не всегда можно идентифицировать ошибку, а во-вторых, не всякую ошибку можно исправить. Вы можете, например, только предположить, что произошло, и попытаться дать рекомендации пользователю, как избежать повторения какой-либо ошибки. Для кодов-примеров мы, конечно, будем точно знать типы ошибок, потому что сами будем их инициировать.
Перед меткой, задающей начало обработчика, должен находиться оператор выхода из процедуры (функции). Иначе даже при отсутствии ошибки код обработчика будет выполняться. В листинге 15.2 приведен пример обработчика, который выполняется в том случае, если пользователь введет в текстовом окне не число, а что-либо отличное от числа.
Листинг 15.2. Пример обработчика ошибок
1	Private Sub Commandl_Click()
2	Dim z, у As Integer
3	On Error GoTo err
4	у - InputBox("Введите число")
5	z = у + 10
6
7	MsgBox	z
8	MsgBox	"Спасибо!"
9	Exit Sub
10
11	err:
12	MsgBox	("Просили же Вас ввести число!")
13	End Sub
Как видно из этого примера, здесь никто не собирался идентифицировать ошибку: в таком простом коде можно было только предположить, что всему виной будет пользователь, который не может пользоваться окном ввода целого числа. Тем не менее, в Visual Basic есть возможность узнать тип ошибки (как ее «для себя» определяет Visual Basic) посредством объекта Err с несколькими свойствами, из которых для нас наиболее полезны Number — номер ошибки, и Description — описание ошибки. При этом в документации MSDN есть замечание с рекомендацией не очень доверять свойству Description, а использовать только свойство Number. Например, код листинга 15.2 можно дополнить анализом произошедшей ошибки (см. листинг 15.3).	i
Листинг 15.3. Анализ ошибки в обработчике
1	Private Sub Commandl_Click()
2	Dim z, у As Integer
3	On Error GoTo err
Отладка VB-кода. Поиск и устранение ошибок
389
4	у = InputBox("Введите число")
5	z = у + 10	4
6
7	MsgBox z
8	MsgBox "Спасибо!"
9	Exit Sub
10
11	err:
12	If err.Number = 13 Then
13	MsgBox ("Просили же Вас ввести число!")
14	End	If
15	End Sub
Если вы предполагаете, что в течение работы с процедурой могут произойти самые разные ошибки, можно в коде обработчика использовать оператор Select Case для возможных действий, исправляющих ситуацию.
Как вы могли уже заметить, в листингах 15.2-15.3 сразу после выполнения кода обработчика вся процедура завершается. Такой обработчик хорош только в качестве примера того, как не нужно поступать. Если мы по всяким пустякам будем завершать процедуры, то с таким приложением будет трудно работать.
Итак, нам нужен способ обработать ошибку или, в крайнем случае, сообщить о ней, но обязательно как-то продолжить выполнение процедуры.
Выход из блока обработки прерывания по ошибке
Для выхода из блока обработки ошибки можно ничего не предпринимать, и работа функции будет завершена. Но поскольку с таким образом завершившей свою работу процедурой (или функцией) могут быть связаны другие части кода, видимо, не всегда будет правильно просто отказаться от дальнейшего выполнения процедуры. По крайней мере, надо как-то сообщить о том, что процедура завершилась из-за ошибки. Например, если функция должна была возвратить результат некоторых вычислений, используемый в дальнейших расчетах, то аварийный выход по ошибке дает мало пользы. Ошибка может произойти и при открытии файла. Если не сообщить об этом при выходе из блока обработки ошибки, то найдется такая функция, которая попытается считывать данные из неоткрытого файла. И так далее.
Для выхода из блока обработки ошибок предназначен оператор Resume, функции которого приведены в следующей таблице.
Оператор	Описание
Resume [0]	Выполнение кода возобновляется с того оператора, который вызвал ошибку. Используйте этот оператор для повторения кода после исправления ошибки.
Resume Next	Возобновляет выполнение кода с оператора, следующего непосредственно за оператором, вызвавшим ошибку. Если ошибка произошла вне процедуры, содержащей блок обработки ошибок, выполнение кода возобновляется с оператора, находящегося за вызовом процедуры, вызвавшей ошибку, если в этой процедуре нет своего обработчика.
Resume line	Возобновляет выполнение кода с указанной метки line. Метка должна находиться в процедуре, содержащей обработчик ошибок.
Err.Raise Number:= number	Эмулирует ошибку времени исполнения. Когда этот оператор выполняется внутри блока обработки ошибок, Visual Basic обращается к списку вызовов (последовательность вызова процедур) для поиска другого обработчика.
390
Глава 15
Пример использования оператора Resume приведен в листинге 15.4. Это самая простая форма оператора, при которой происходит возврат к строке кода, где произошла ошибка. По крайней мере, в данном случае этого вполне достаточно, поскольку после правильного ввода числа программа будет работать нормально.
Листинг 15.4. Использование в обработчике оператора Resume
1	Private Sub Commandl_Click()
2	Dim z, у As Integer
3	On Error GoTo err
4	у = InputBox("Введите число")
5	z = у + 10
6
7	MsgBox z
8	MsgBox "Спасибо!"	t
9	Exit Sub
10
11	err:
12	If err.Number =13 Then
13	MsgBox ("Просили же Вас ввести число1")
14	Resume
15	End If
16	End Sub
В листингах 15.5 и 15.6 приведены примеры использования оператора Resume Next. Причем в первом из них выполняется присвоение переменной числа 9999, если пользователь «забыл», как вводятся числа. Затем код продолжается со следующей строки (за оператором InputBox).
В листинге 15.6 обработчик более «лоялен» к пользователю, давая ему три попытки для ввода числа. Поэтому здесь используется и оператор Resume, и Resume Next. Для этого в код введен счетчик со, который при загрузке формы (процедура Form_Load) инициализируется значением 1. В блоке обработки ошибок значение счетчика увеличивается на единицу. Как только пользователь использует три попытки ввода числа, но не введет число, оператор Resume Next прекратит пользовательские «мучения», как это делается (только гораздо раньше) в предыдущем листинге.
	Листинг 15.5. Использование в обработчике оператора Resume Next
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17	Private Sub Commandl_Click() Dim z, у As Integer On Error GoTo err у = InputBox("Введите число") z = у + 10	' MsgBox z MsgBox "Спасибо!" Exit Sub err: If err.Number = 13 Then MsgBox ("С Вашего разрешения введем 9999")	, у = 9999 Resume Next End I f End Sub
Отладка VB-кода. Поиск и устранение ошибок
391
Листинг 15.6. Использование в обработчике оператора Resume Next
1	Public со As Integer
2	Private Sub Commandl_Click()
3	Dim z, у As Integer
4	On Error GoTo err
5	у = InputBox("Введите число")	
6	z = у + 10	*
7
8	MsgBox z	‘
9	MsgBox "Спасибо1"
10	Exit Sub
11
12 err:
13 If err.Number = 13 Then
14	If co = 2 Then
15	MsgBox ("С Вашего разрешения введем 9999")
16	у = 9999
17	Resume Next
18	Else
19	co = co + 1
20	MsgBox ("У Вас осталось " & _
21	(3 - co) & " попытки")
22	Resume
23	End If
24 End If
25 End Sub
26
27 Private Sub Form_Load()
28 co = 0
29 End Sub
Очень простой пример использования оператора Resume line приведен в следующем листинге.
	Листинг 15.7. Использование в обработчике оператора Resume line
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25	Public со As Integer Private Sub Commandl_Clrck() Dim z, у As Integer On Error GoTo err у = InputBox("Введите число") z = у + 10 MsgBox z MsgBox "Спасибо!"	,	. Exit Sub err_exit: MsgBox ("Что-то у Вас не получается") Exit Sub err: If err.Number = 13 Then If co = 2 Then Resume err_exit Else co = co + 1 MsgBox ("У Вас осталось " & _ (3 - co) & " попытки") Resume End If
392
Глава 15
26 End If
27 End Sub
28
29 Private Sub Form_Load()
30 co = 0
31 End Sub
В листинге 15.8 блок кода обработки ошибок находится не в той процедуре, где происходит ошибка при делении числа на ноль. Visual Basic при помощи списка вызовов возвращается в процедуру А, поскольку именно там был активизирован обработчик ошибок. Оператор Resume Next инициировал переход к строке кода, которая находится за оператором вызова процедуры В.
'	Листинг 15.8. Обработчик ошибок в одной из процедур
1	Private Sub Commandl_Click()
2	Call A
3	End Sub
4
5	Sub	A()
6	On Error GoTo err
7	Call В
8	MsgBox ("В любом случае	процедура	а завершается")
9	Exit Sub
10	err:
11	MsgBox ("Где-то произошла	ошибка!")
12	Resume Next
13	End	Sub
14
15	Sub B()
16	Call C
17	End Sub	*'
18
19	Sub C()
20	Dim d As Integer
21	d = 1 / 0	’
22	End Sub
Программная обработка ошибок при помощи оператора On Error
Оператор On Error позволяет обрабатывать ошибки, возникающие во время выполнения кода, программно. Синтаксис оператора On Error следующий:
СИНТАКСИС
On Error GoTo line
On Error Resume Next
On Error GoTo 0
Синтаксис оператора On Error имеет следующие формы:
On Error GoTo line	Делает доступным обработчик ошибок, который начинается со строки, определенной аргументом line. Аргумент line может быть меткой или числом. При возникновении ошибки управление выполнением программы передается на строку кода с меткой line.Таким образом происходит активизация обработчика ошибок. Метка line должна находиться в той же процедуре, что и оператор On Error.
Отладка VB-кода. Поиск и устранение ошибок
393
On Error Resume Next	Указывает на то, что при возникновении ошибки управление выполнением программы передается на оператор, следующий непосредственно за тем, в котором произошла ошибка. Этот оператор позволяет продолжить выполнение программы, несмотря на возникновение runtime-ошибки. Оператор On Error Resume Next становится неактивным при вызове другой процедуры.
On Error GoTo 0	Отключает пользовательский обработчик ошибок в данной процедуре. Этот оператор не указывает метку 0 в качестве начала обработчика ошибки, даже если в процедуре действительно имеется такая метка. Без этого оператора обработчик ошибок «отключается» автоматически после окончания работы процедуры.
Пользовательские обработчики ошибок являются составной частью «дружественного» интерфейса. Если во время работы пользователя с вашим приложением возникает не предусмотренная вами ситуация, то в любом случае не стоит оставлять пользователя «наедине» с системой VBA, не настолько дружественной, как хороший разработчик приложений. VBA «знает» очень мало о том, в каких местах вашего программного кода и какие могут возникать ошибки. Разработчик же приложения должен знать все «тонкие» места в коде и ожидать те или иные ошибки. Даже если приложение просто пытается открыть файл, который нечаянно «убили», VBA-сообщение об отсутствии файла не так информативно, как могло бы быть сообщение разработчика, которое не только должно сообщить об отсутствии файла, но и предложить возможные пути его восстановления или замены старой копией.
Следует различать состояния «доступность» («enabled») и «активность» («active») обработчика ошибок. Обработчик доступен, если оператор On Error выполнен, но ошибка еще не возникла. Обработчик активен, когда им выполняется обработка некоторой возникшей ошибки. Если ошибка возникает, когда обработчик активен (обрабатывает ранее возникшую ошибку), эта ошибка не обрабатывается и управление передается в вызывающую процедуру. Если вызывающая процедура имеет обработчик ошибок, находящийся в состоянии «enabled», обработчик переходит в состояние «active» (т.е. обработки ошибки). Если обработчик вызывающей процедуры находится в состоянии «active», то управление передается предыдущей вызывающей процедуре с обработчиком в состоянии «enabled», но не «active». Т.е. в цепочке вызывающих процедур ищется обработчик ошибок в состоянии «enabled», готовый обработать ошибку.
Обычно в процедурах обработки ошибок для определения причины ошибки используется свойство Number объекта Err. Сообщение об ошибке (довольно «скупое»), связанное с Err.Number, содержится в Err.Description. Поэтому обычно на стадии отладки после метки, на которую передается управление выполнением программы в случае возникновения (ожидаемой) ошибки, помещается следующий оператор:
MsgBox "Error " & Err &	& Err.Description
В процедуре листинга 15.9 используется On Error Resume Next для того, чтобы при обнаружении отсутствия в системе экземпляра приложения Excel программа не завершалась с ошибкой.
Листинг 15.9. Обработчик ошибок для защиты программы от прерывания
1	Sub TestErrorQ
2	Dim xlApp As Object
3	Dim xlSheet As Object
394
Глава 15
4
5
6
7
8
9
10
11
12
13
14
15
On Error Resume Next
Set xlApp = Nothing
Set xlApp = GetObject(, "Excel Application")
If Err.Number 0 Then
Set xlApp = CreateObject("Excel.Application") End If Err.Clear
*
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook Worksheets(1) xlSheet.Application.Visible = True End Sub
Управление другими приложениями
ЕЪсизсз 16
Управление host-приложениями VBA
Вы уже знаете, что Visual Basic for Applications — язык программирования, предназначенный в основном для работы с имеющимся программным обеспечением и для расширения его возможностей. Приложения Microsoft Office имеют множество различных объектов, доступных VBA. Свойства и методы этих объектов позволяют посредством VBA-кода управлять, практически, любым аспектом работы приложений Microsoft Office. Из этой главы вы узнаете, как посредством VBA-кода управлять основными операциями в Word и Excel, а именно:
	Как работать с объектами Excel: Workbook и Worksheet.
	Как использовать методы объекта Excel, возвращающие объекты Range, включая то, как задать и выделить диапазоны ячеек в листе Excel.
	Как ввести в ячейки листа Excel значения и формулы.
	Как работать с объектами Word: Document и Template.
	Как использовать методы объекта Word, возвращающие разделы документов^ включая объекты Paragraphs, Characters и Range.
	Как добавить, вырезать, скопировать или вставить данные в лист Excel или документ Word.
Работа с Excel
В первой части главы вы узнаете, как управлять наиболее важными и основными объектами Excel. Во-первых, вы узнаете об объектах Workbook и Worksheet, а затем научитесь управлять информацией, содержащейся в объекте Worksheet. Далее из этой же главы вы узнаете, как управлять аналогичными объектами в Word.
Возвращение объекта книга
В Excel каждая книга является объектом Workbook, a Workbooks — коллекцией всех открытых книг в текущем рабочем сеансе Excel. Для ссылок на конкретную книгу следует использовать коллекцию Workbook объекта Application:
СИНТАКСИС
Workbooks(Index)
Index может быть:
	Численным выражением, представляющим книгу, которую необходимо использовать. Число 1 означает первую книгу, открытую в текущем рабочем сеансе, 2 — вторую и так далее.
	Строковым выражением, представляющим имя открытой книги, которую вы хотите использовать.
Управление host-приложениями VBA
397
Более распространенный и обычно наиболее удобочитаемый способ — использование в качестве Index текстовой строки. Листинг 16.1 содержит соответствующий пример.
Листинг 16.1. Использование коллекции Workbooks
1	Sub SetWorkbookProte'ction ()
2	' Установка защиты книги	>		,	«
3
4	Workbooks("Книга17_01.XLS").Protect Structure:=True, Windows:=True
5	MsgBox "Защита для файла Книга17_01.XLS установлена", , _
6	"Установка защиты книги"
7	End Sub

Рис. 16.1
Результат выполнения кода листинга 16.1
Усыионна защит ы киши
Защита для файла Книга 17_O1.XLS установлена
Выражение в строке 4, Workbooks("KHHral7_01.XLS"), возвращает объектную ссылку на объект книга с именем KHHral7_01.xls. Метод Protect устанавливает защиту книги. Оператор MsgBox (в строках 5-6) выводит сообщение, информирующее о том, что для данной книги защита была установлена. (Предполагается, что книга с именем KHHral7_01.xls в данный момент открыта. Если это — не так, то вы получите сообщение о runtime-ошибке.)
Как открыть книгу
Если необходимая вам книга еще не открыта, воспользуйтесь методом Open для загрузки ее в память.
СИНТАКСИС
Workbooks.Open(Filename)
Аргумент Filename — текстовая строка, представляющая полный путь к книге: диск, папка и имя файла. Если вы не зададите имя диска или папку, Excel будет искать файл на текущем диске и в той папке, которая открыта в данный момент.
Пример использования'метода Open представлен в листинге 16.2.
Листинг 16.2. Применение метода Open для открытия книги
1	Sub OpenWorkbook()
2	' Предлагает открыть и затем открывает ее
3
4	Dim Workbookname As String
5
6	Workbookname = _
7	InputBox("Введите полный путь к книге:")
8	If Workbookname О "" Then
9	Workbooks.Open FileName:=Workbookname
10	End If
11	End Sub
398
Глава 16
В этой процедуре переменная WorkbookName объявлена с типом .String (строка 4). Функция InputBox предлагает пользователю ввести имя файла книги (строки 6 и 7). Оператор If...Then (в строке 8) проверяет, не отменил ли пользователь диалог ввода. Если — нет, другими словами, если строка WorkbookName не пуста, метод Open использует WorkbookName для открытия файла (строка 9).
Как создать новую книгу
Если вашей процедуре требуется создать новую книгу, воспользуйтесь методом Add коллекции Workbooks.
СИНТАКСИС
Workbooks.Add([Template])
Необязательный аргумент Template определяет тип книги, создаваемой Excel. Если вы опустите Template, Excel создаст книгу, заданную по умолчанию и содержащую некоторое количество чистых листов. Количество чистых листов в новой книге задается на вкладке Общие (General) в диалоговом окне Параметры (Options) (вызвать данное диалоговое окно можно, выбрав команду Сервис | Параметры (Tools | Options)). Вы можете также задать количество чистых листов в новой книге при помощи свойства Application.SheetsInNewWorkBook.
Для того чтобы создать новую книгу, основываясь на существующем шаблоне, подставьте в качестве аргумента Template строковое значение, определяющее имя шаблона. Если необходимый вам шаблон расположен не в загрузочной или не в альтернативной загрузочной папке, включайте в аргумент Template полный путь: имя диска, папку и имя шаблона.
Чтобы создать книгу, содержащую только один лист, используйте одну из следующих встроенных констант аргумента Template (эти константы определены в классе xlWBATemplate): xlWBATWorksheet, xlWBATChart, x!WBATExce!4-MacroSheet или xlWBATExce!4IntlMacroSheet.
Листинг 16.3 демонстрирует пример процедуры, создающей новую книгу.
Листинг 16.3. Использование метода Add для создания новой книги
1	Sub CreateMonthlyReport()
2	' Создание новой книги на основе шаблона "Балансовый отчет"
3
4	Dim dPath As String
5
6	dPath = "E:\Program Files\Microsoft Office"
7	dPath = dPath S "\Templates\1049\"
8	Workbooks-Add Template:=dPath & "Балансовый отчет"
9	With ActiveWorkbook
10	.Title = "Отчет компании"
11	.Subject - "Отчет за ДЕКАБРЬ 2002"
12	.Author = "Иван Петров"
13	End With
14	End Sub
Код листинга 16.3 создает новую книгу на базе шаблона Балансовый отчет, поставляемого с Excel и Microsoft Office (строка 8). (Путь к шаблону книги, используемому в этом примере, дан из расчета, что установка Microsoft Office выполнялась в папку, предлагаемую по умолчанию; в вашем случае файл может находиться в другом месте.) Любая новая книга автоматически становится активной книгой. В строках с 9 по 13 для добавления в файл новой книги некоторой общей
Управление host-приложениями VBA
399
информации — Title, Subject и Author — используется объект ActiveWorkbook. Для просмотра результатов работы кода строк 9-13 используйте или всплывающую Explorer-подсказку (см. рис. 16.2), или вкладку Summary диалогового окна Properties для данного файла.
Рис. 16.2
Общую информацию о файле можно увидеть, если просто на некоторое время поместить на его значке курсор мыши
Книга!
г nt г Мт ’о > " е.
Управление host-приложениями УВД
JT \ Балансовый отчет 1202
ЙУ |Г 1СЛ ’
Туре Лист Microsoft Excel Author Иван Петров Title Отчет компании
Subject Отчет за ДЕКАБРЬ 2002 Date Modified' 1/5/2003 11'33 AM Size 28 О KB
Как сделать книгу активной
Если ваша VBA-программа работает с несколькими одновременно открытыми книгами, вам может понадобиться переключаться из одной книги в другую для вывода на экран, например, отчета или введенных данных.
Чтобы сделать открытый документ активным, используйте метод Activate:
СИНТАКСИС
Object.Activate
В данном случае Object представляет любую допустимую объектную ссылку на лист, который необходимо сделать активным.
В листинге 16.4 — пример процедуры, использующей метод Activate.
Листинг 16.4. Использование метода Activate для переключения к книге
1	Sub ActivateTest()
2	' Изменение активной книги без вывода на экран
3
4	Dim SaveBook As String
5
6	SaveBook = ActiveWorkbook.Name
7
8	Application.Screenupdating = False
9	Workbooks("Балансовый отчет 1202.XLS").Activate
10
11	' код, выполняющий заполнение	файла Балансовый отчет 1202.XLS
12	' . . .
13
14	Workbooks(SaveBook).Activate
15	Application.Screenupdating = True
16	End Sub
Эта простая процедура демонстрирует два принципа хорошего программирования. Во-первых, по возможности следует скрывать от пользователя промежуточные операции, выполняемые вашей программой. Например, если процедура содержит операторы, форматирующие диапазоны ячеек и введенные данные, выполняйте данные действия «за кулисами». Выводите для пользователя на экран лишь
400
Глава 16
конечный результат. Сделать это можно, задав свойство Screenupdating объекта Application равным False.
Во-вторых, если вы устанавливаете книгу активной, потому, что это требуется вашей программе, а не для того, чтобы пользователь мог увидеть другой файл, ваша процедура должна по завершении «возвращать» пользователя в то же самое место, где он находился при ее старте. Особенно это относится к малоопытным пользователям, которые приходят в замешательство, обнаружив, что по выполнении процедуры, они оказываются совсем в другой книге, не имея, при этом, никаких разумных предположений для объяснения этого факта.
Назначение представленной в листинге 16.4 процедуры — переключиться из текущей книги в другую книгу (Балансовый отчет 1202.XLS), произвести в ней программным образом некоторые изменения, а затем вернуться к первоначальной книге. Сначала (в строке 6) имя текущей активной книги сохраняется в строковой переменной SaveBook. Далее, чтобы избавить пользователя от наблюдения за деталями выполнения процедуры, в строке 8 свойство Screenupdating устанавливается равным False. В строке 9 книга Балансовый отчет 1202.XLS устанавливается активной. Строки, следующие далее, должны выполнять действия в книге Балансовый отчет 1202.XLS. Реальная программа, которая вносит изменения в Балансовый отчет 1202.XLS, в данном примере опущена. Для того чтобы «вернуть» пользователя в то же место, в котором он находился перед запуском процедуры, в строке 14 активной становится первоначальная книга. В строке 15 значение ScreenUpdating вновь устанавливается равным True.
I
Как сохранить книгу
Если ваша VBA-программа вносит в книгу изменения, вы должны предло- ' жить пользователю сохранить их. Сделать это довольно просто, или включив встроенную команду Сохранить в меню вашей программы, или добавив кнопку Сохранить на панель инструментов программы, если программа имеет меню или панели инструментов.
Хотя возможны случаи, когда у вас возникнет потребность сохранить книгу под управлением процедуры. Например, вы захотите создать собственную версию команды Файл | Сохранить. Более того, вы, возможно, попытаетесь предостеречь начинающего пользователя от выполнения неудачной последовательности команд, таких как закрытие книги, выход из программы или из Excel без сохранения результатов работы.
Для сохранения книги следует пользоваться методом Save.
СИНТАКСИС
Object.Save
В данном случае, Object — это объектная ссылка на открытый объект Workbook, который следует сохранить.
Существует также очень удобный метод SaveCopyAs. Этот метод сохраняет копию заданной книги на диск, никак не влияя на эту книгу в памяти.
Общий синтаксис метода SaveCopyAs выглядит следующим образом:
СИНТАКСИС
Object.SaveCopyAs(Filename)
Object — это объектная ссылка на объект Workbook, который будет сохранен, a Filename — строковое выражение для имени, которое следует использовать при сохранении копии книги.
Управление host-приложениями VBA
401
В листинге 16.5 приведен код, использующий методы Save и SaveCopyAs.
Листинг 16.5. Использование методов Save и SaveCopyAs
1	Sub BackUpToZIP()
2	' Сохраняет активную книгу и делает ее копию на ZIP-диске Н:
3
4	Const ZIPDrv = "Н:”
5
б	With ActiveWorkbook
7	If Not .Saved Then .Save
8	.SaveCopyAs Filename:=ZIPDrv & .Name
9	End With
10	End Sub
Эта процедура сохраняет активную книгу и создает резервную копию на ZIP-диске Н (рис. 16.3). Процедура начинается с объявления единственной константы для имени ZIP-диска. Оператор With выполняет несколько команд для объекта ActiveWorkbook.
Рис. 16.3
Копия активной книги на ZIP-диске -дополнительная гарантия сохранения результатов вашей работы
ZIP750 (Н:)
Elie Edit View Favorites Tools Help Q Back -	,	* > Search
«cdress Н \
„IMAC Format Options ©PC Users Click Here
Щкнига17_О1
Тест If...Then (строка 7) проверяет свойство Saved книги. Если оно равно False, в книге имеются изменения, которые еще не были сохранены, поэтому процедура вызывает метод Save.
Имя резервной копии файла создается конкатенацией значения константы ZIPDrv и свойства Name книги. Результат используется в качестве аргумента Name метода SaveCopyAs (строка 8), который сохраняет копию книги на гибком диске.
Метод Save не следует использовать для новой книги (которая прежде ни разу не сохранялась). Если вы все же сделаете это, Excel сохранит новую книгу под ее текущим именем, например, KHHFAl.XLS. Чтобы при сохранении присвоить книге имя используйте метод SaveAs:
СИНТАКСИС
Object.SaveAs([FileName] [, FileFormat] [, Password] [, WriteResPassword] [, ReadOnlyRecommended] [, CreateBackup] [, AccessMode] [, ConflictResolution] [, AddToMru])
Object — это объектная ссылка на объект Workbook, a Filename — строковое выражение для имени, которое следует использовать при сохранении копии книги.
FileFormat (тип Variant) — применяемый при сохранении файла формат. Для существующего на диске файла по умолчанию используется последний заданный формат, для нового файла — формат используемой версии Excel.
Password (тип Variant) — строка (не более 15-ти символов), которая используется в качестве пароля при открытии файла. Пароль вводится в диалоговом окне, представленном на рис. 16.4.
402
Глава 16
Рис. 16.4
При открытии защищенного паролем файла пароль вводится в диалоговом окне
Введите пароль
Книга17_01 xls4 xls' защищен
Пароль
OK j Отмена j
WriteResPassword (тип Variant) — строка, определяющая пароль, при помощи которого файл защищается от перезаписи.
Рис. 16.5
Использование в методе SaveAs аргумента WriteResPassword позволяет закрыть файл на запись для пользователей, не знающих соответствующего пароля
Пароль
'Книга17_01 xls4 xls зарезервирован
Владимир
Введите пароль разрешения записи или откроите файл в режиме Только для чтения'
Пароль
Отмена
Только для чтения
ReadOnlyRecommended (тип Variant) — аргумент, который при значении, равном True, приводит к появлению окна (рис. 16.6) с рекомендацией открывать файл только на чтение.
| ) 'Книга17_01 xls рекомендуется открывать только для чтения, если изменения, внесенные в
нГ'' этот файл, не обязательно должны быть записаны Открыть только для чтения’
Да
Отмена
Рис. 16.6. Использование в методе SaveAs аргумента ReadOnlyRecommended приводит к тому что при открытии файла пользователь уведомляется о том, что файл желательно не изменять
CreateBackup (тип Variant) — аргумент, который при значении, равном True, приводит к созданию резервной копии сохраняемой книги (рис. 16.7).
Рис. 16.7
Использование в методе SaveAs аргумента
CreateBackup приводит к созданию резервной копии сохраняемого файла
Управление host-приложениями VBA
403
AccessMode — значение одной из следующих констант:
	xlExclusive (монопольный доступ);
	xlNoChange (не менять режим доступа, действует по умолчанию);
	xlShared (многопользовательский доступ).
При использовании константы xlExclusive файл может быть открыт для записи только одним пользователем. Другой пользователь получит сообщение о том, что файл уже открыт, в диалоговом окне, представленном на рис. 16.8. С другой стороны, константа xlShared дает возможность сразу нескольким пользователям работать с одним файлом (рис. 16.9).

Редактирование 'Книга17_01 xls' запрещено
пользователем 'Владимир'
Откройте только для чтения или нажмите "Уведомить", чтобы открыть копию документа только для чтения и получить уведомление о его освобождении
Тольго чтение
Уведомить
Отмена
Рис. 16.9
Этот файл был сохранен с использованием константы
xlShared
Рис. 16.8. Если вы получите при открытии файла такое сообщение, значит, кто-то уже работает с файлом, сохраненным ранее с использованием константы xlExclusive
При одновременной работе нескольких пользователей с одним файлом в любой момент времени любой пользователь может сохранять свои изменения в файле. При этом, если какой-либо другой пользователь уже сохранял данные на диске, эти данные попадают в файл того, кто делает в данный момент сохранение своих данных. На рис. 16.10 показано сообщение, выдаваемое пользователю, который сохраняет данные.
Однако при такой совместной работе с одним файлом не всегда можно просто сохранить свои данные в файле на диске. На рис. 16.11 представлено окно Возник конфликт доступа, которое предупреждает о том, что вы пытаетесь одновременно с другим пользователем изменить содержимое одной и той же ячейки.
ConfhctResolution — одна из следующих констант:
	xlUserResolution (отображать диалоговое окно разрешения конфликтов);
	xlLocalSessionChanges (автоматически принимать пользовательские изменения);
	xlOtherSessionChanges (принимать другие изменения вместо локальных пользовательских).
404
Глава 16
©пил ]|_ ем f	। д.Би Дчнные < гнп Справка
В? ы 100% -г “ Anal Cyr	V 10 -г ж /с ч s£ s $ •-
АЗ ▼ А Изменения пользователя Владимир
4	„	_	_	..	__	_	____	.	-
1 Изменения пользователя Наталья	•

2
3
4
5
6
7
8
Q Н
Готово
[Изменен^ пользователя Владимир
н\л
NUM
Рис. 16.11
Если вы пытаетесь сохранить изменения в общем файле, с которым работает другой пользователь, то не всякие ваши изменения «легко» записать на диск
Рис. 16.10. Сообщение, выдаваемое пользователю, который сохраняет данные в файле, записанном с использованием константы xIShared и открытом одновременно несколькими пользователями
AddToMru (тип Variant) — аргумент, который (при равенстве значению True) указывает на то, что файл добавляется в список недавно используемых файлов. По умолчанию этот аргумент принимается равным значению False.
Метод SaveAs имеет и другие параметры, о которых вы можете узнать из справочной системы.
Как закрыть книгу
После завершения работы с книгой, следует ее закрыть, чтобы высвободить память и избежать «засорения» экрана. Закрыть книгу можно, воспользовавшись одной из форм метода Close.
СИНТАКСИС
Workbooks.Close
Object.Close(SaveChanges)
При использовании первой синтаксической формы можно просто закрыть все открытые книги. Excel предлагает сохранить изменения в книгах перед тем,
Управление host-приложениями VBA
405
как их закрыть, если это необходимо. Вторая синтаксическая форма позволяет закрыть конкретную книгу, на которую указывает Object. Аргумент SaveC-hanges используется следующим образом:
	Если SaveChanges равен True, Excel сохраняет книгу автоматически, перед тем как ее закрыть.
	Если SaveChanges равен False, Excel закрывает книгу без сохранения изменений.
	Если вы опустите аргумент SaveChanges, Excel предложит (в случае необходимости) выполнить сохранение.
Листинг 16.6 демонстрирует использование метода Close.
Листинг 16.6. Использование метода Close
1	Sub CloseAll()
2	' Закрывает все открытые книги и предлагает сохранить сделанные
3	' в них изменения
4	Const qButtons = vbYesNo + vbQuestion
5
6	Dim	Book As Workbook
1	Dim	Ans As Integer
8	Dim	MsgPrompt As String
9
10	For	Each Book In Workbooks
11	If Not (Book.Name = ThisWorkbook.Name) Then
12	If Not Book.Saved Then
13	MsgPrompt = "Сохранить изменения в " & Book.Name & "?"
14	, Ans = MsgBox(prompt:=MsgPrompt, Buttons:=qButtons)
15	If Ans = vbYes Then
16	*'	Book.Close SaveChanges:=True
17	•	' Else
18	Book.Close SaveChanges:=False
19	End If
20	.	’ Else
21	Book.Close
22	End If
23	End If
24	Next Book
25	End Sub
Данная процедура закрывает все открытые книги (за исключением книги, содержащей процедуру) и предлагает пользователю сохранить изменения для каждой книги, имеющей несохраненные изменения. Используйте процедуру, подобную этой, вместо метода Workbooks.Close, когда вам необходимо, чтобы пользователь не отменял операцию сохранения. Встроенная в Excel команда Сохранить имеет кнопку Отмена. После объявления константы и нескольких переменных (строки с 4 по 8) процедура начинает цикл For Each для обработки всех книг в коллекции Workbooks.
Поскольку закрытие книги, содержащей выполняемую в данный момент процедуру, приведет к ее остановке, строка 11 содержит оператор If ...Then, который проверяет, не имеет ли книга, обрабатываемая в данный момент, то же самое имя, что и книга, содержащая процедуру CloseAll. Если — да, то часть кода, выполняющая закрытие книги пропускается; строки с 12 по 22 выполняются только в том случае, если книга не содержит процедуры CloseAll. (Свойство ThisWorkbook возвращает ссылку на книгу, содержащую выполняемый в данный момент код.)
Если книга содержит изменения, которые не были сохранены (строка 12), функция MsgBox (строка 13) запрашивает пользователя, необходимо ли сохранять
406
Глава 16
изменения. Если пользователь выбирает Yes (то есть переменная Ans получит значение vbYes), процедура запускает метод Close с аргументом SaveChanges, равным True (строка 16). В противном случае процедура закрывает книгу с SaveChanges, равным значению False (строка 18). Если в книге отсутствуют несохраненные изменения, процедура запустит метод Close без аргументов (строка 21).
Работа с объектами Worksheet
Объекты Worksheet содержат набор свойств и методов, которые вы можете использовать в своей программе. Эти свойства и методы позволяют делать листы активными и скрывать их, добавлять в книгу новые листы, а также перемещать, копировать, переименовывать или удалять их. В следующих разделах описывается каждая из этих операций над листом.
Возвращение значения объекта Worksheet
Каждый лист является объектом Worksheet, а все листы данной книги образуют коллекцию Worksheets. Для ссылок на заданный лист используйте коллекцию Worksheets объекта Workbook:
СИНТАКСИС
Object.Worksheets(Index)
Object представляет ссылку на объект Workbook, содержащий лист. Index может быть:
	Числом, представляющим лист, который следует использовать. Число 1 означает первый лист в книге, 2 — второй лист и так далее.
	Имя листа, который следует использовать, в виде строки. Это имя, которое появляется на вкладке листа.
Листинг 16.7 представляет пример наиболее частого способа использования метода Worksheets — когда лист идентифицируется строкой текста.
Листинг 16.7. Использование коллекции Worksheets
1	Sub SetWorksheetProtection()
2	' Активизирует защиту листа
3
4	Workbooks("Балансовый отчет 1202.xls").Worksheets(
5	"Расходы").Protect Contents:=True, Scenarios:=True
6	MsgBox "Защита листа 'Расходы' активизирована."
7	End Sub	'
Объект Workbooksf'BaaaHcoBbih отчет 1202.XLS").Worksheetsf'Pacxoabi") возвращает ссылку на лист с именем Расходы в книге Балансовый отчет 1202.XLS.xls. Метод Protect задает защиту для содержимого и сценария. Процедура MsgBox информирует пользователя о том, что защита листа активизирована (рис. 16.12).
Рис. 16.12
Процедура MsgBox информирует пользователя о том, что защита листа активизирована
Защита листа 'Расходы' активизирована
Управление host-приложениями VBA
407
Для работы рассматриваемой программы необходимо, чтобы в коллекции Workbook имелась та книга, на которую выполняется ссылка — Балансовый отчет 1202.XLS.xls. Если это — не так, VBA выдаст сообщение об ошибке (рис. 16.13), которое вряд ли поможет вам сразу понять причину ошибки.
Хорошим правилом при программировании является проверка наличия объекта в коллекции перед попыткой его использования. В следующем листинге защита листа книги Балансовый отчет 1202.XLS.xls выполняется в том случае, если эта книга находится в коллекции Workbooks. Наличие самого листа в книге не проверяется, хотя можно было бы и проверить.
Рис. 16.13
Если в коллекции Workbook нет книги, на которую выполняется ссылка, VBA выдаст сообщение об ошибке, которое вряд ли поможет вам сразу понять причину ошибки
Листинг 16.8. Использование коллекции Worksheets
1	Sub SetWorksheetProtection()
2	' Активизирует защиту листа с проверкой
3	' наличия книги в коллекции Workbooks
4	Dim ProtYes As Boolean
5	ProtYes = False
6
7	For Each Book In Workbooks
8	If (Book.Name = "Балансовый отчет 1202.xls") Then
9	Book.Worksheets("Расходы").Protect	_
10	Contents:=True, Scenarios:=True
11	MsgBox "Защита листа 'Расходы' активизирована "
12	ProtYes = True
13	Exit For
14	End If
15	Next Book
16
17	If Not ProtYes Then MsgBox "Книга не найдена!"
18
19	End Sub	'
В строках 4 и 5 объявляется и инициализируется переменная ProtYes, которая используется в качестве индикатора наличия необходимой книги в коллекции Workbooks. В цикле For Each (строки 7-15) для каждой книги проверяется свойство Name. При совпадении этого свойства со строкой "Балансовый отчет 1202.xls” выполняется защита листа Расходы (строка 9), переменной ProtYes присваивается значение True (книга найдена), происходит выход из цикла при помощи оператора Exit For. В строке 17 выдается сообщение об отсутствии необходимой книги в коллекции Workbooks, если переменная ProtYes содержит значение False.
Если вам необходимо сослаться на активный лист, используйте свойство книги ActiveSheet. Если вам нужно сослаться на все страницы книги (или вы не уверены, какой тип листа необходимо выбрать), используйте вместо коллекции Worksheets коллекцию Sheets. Коллекция Sheets содержит не только листы, но и диаграммы.
408
Глава 16
Как сделать лист активным
Большинство книг содержат более одного листа, поэтому вашей программе может понадобиться переключаться с одного листа на другой. Например, отобразить один лист для ввода данных и затем переключиться на другой лист, чтобы просмотреть отчет или диаграмму. Выполнять переключение между листами можно при помощи метода Activate.
СИНТАКСИС
Object.Activate
Object представляет ссылку на объект Worksheet, который следует сделать активным.
Листинг 16.9 содержит пример использования метода Activate.
Листинг 16.9. Использование метода Activate для перехода на заданный лист
1	Sub Displaysheet ()
2	1 Устанавливает активным лист "Расходы"
3
4	Dim Ans As Integer, qBtns As Integer
5	Dim mPrompt As String
6
7	• mPrompt = "Хотите просмотреть ""Расходы""?"
8	qBtns = vbYesNo + vbQuestion + vbDefaultButton2	।
9	Ans = MsgBox(prompt:=mPrompt, Buttons:=qBtns)
10	If Ans = vbYes Then
11	Workbooks("Балансовый отчет 1202.xls").Worksheets( _
"Расходы").Activate
12	End If
13	End Sub
В данной процедуре пользователю задается вопрос, хочет ли он просмотреть определенный лист, в данном случае — Расходы (строки 7-9 программы). Если пользователь выбирает кнопку Yes, то лист с именем Расходы становится активным (строка 11).
Для выбора листа используйте метод Select:
СИНТАКСИС
Object.Select
Данный метод полезен для создания трехмерных ссылок и определения листов, которые следует вывести на печать. Трехмерная ссылка (three-dimensional reference) — это ссылка на диапазон ячеек более чем одного листа.
Не следует без необходимости делать лист активным. Для большинства свойств и методов объекта Worksheet вы можете просто воспользоваться методом Worksheets для ссылок на лист, который нужно использовать. Например, следующий оператор возвращает стандартную ширину листа График баланса, не делая его активным:
StdWidth = Worksheets("График баланса").Standardwidth
Как создать новый лист
Коллекция Worksheets имеет метод Add, который вы можете использовать для добавления в книгу новых листов. Синтаксическая конструкция применения данного метода следующая:
Управление host-приложениями VBA
409
СИНТАКСИС
Object.Worksheets.Add([Before] [, Count] [, Type])
Object представляет ссылку на объект Workbook, в который добавляется новый лист. Аргумент Before, задает лист, перед которым добавляется новый лист, а аргумент After — лист, после которого добавится новый лист. (Нельзя использовать аргументы Before и After одновременно в одном и том же операторе.) Если опустить оба аргумента, как Before, так и After, VBA добавит новый лист перед активным листом.
Count — количество вновь добавляемых листов. (Если опустить Count, метод Add добавит один лист.) Туре — тип добавляемого листа. Существуют следующие возможные варианты аргумента Туре (определенные в классе XlSheet-Туре): xlWorksheet (устанавливается по умолчанию), xlChart, х!Ехсе14Мас-roSheet или xlExce!4IntlMacroSheet.
Как переименовать лист
Имя листа — это текст, который появляется на закладке листа. В случае необходимости переименовать лист следует изменить свойство Name листа:
СИНТАКСИС
Object.Name
Object — это лист, который будет переименован.
Копирование и перемещение листа
Если вам необходимо расположить листы книги в определенном порядке, используйте методы Сору и Move. Оба метода имеют одинаковый синтаксис.
СИНТАКСИС
Object.Сору([Before] [, After])
Object.Move([Before] [, After])
Object — объектная ссылка на лист, который необходимо скопировать или переместить. Before задает лист, перед которым, a After — лист, после которого будет помещен копируемый или перемещаемый лист. (Нельзя использовать аргументы Before и After одновременно в одном операторе.) Если опустить как Before, так и After, VBA создаст для копируемого или перемещаемого листа новую книгу.
Листинг 16.10 содержит процедуру, использующую метод Move.
Листинг 16.10. Использование метода Move для перемещения листа
1	Sub CreateWorksheet ()
2	' Создание нового листа и перемещение
3	' его в конец книги
4
5	Dim NewSheet As String
6
7	Worksheets.Add before:“Worksheets(Worksheets.Count)
8	NewSheet = ActiveSheet.Name
9	With Worksheets(NewSheet)
10	.Move after:“Worksheets(Worksheets.Count)
11	.Activate
410 Глава 16,
I
12	End With
13 14 End Sub
С помощью метода Add в книгу добавляется лист (строка 7). В данном случае метод Add вызывается с необязательным аргументом Before для того, чтобы добавить новый лист непосредственно перед последним листом книги. Номер последнего листа книги определяется в строке 7 с помощью свойства Count, которое возвращает количество листов в книге. После чего новое название листа сохраняется в переменной NewSheet.
В строке 10 с помощью метода Move, новый лист помещается за последним листом книги. Для того чтобы получить количество листов в книге, вновь используется свойство Count. После этого новый лист устанавливается активным (строка 11).
Если вы разрабатываете приложение, в котором часто приходится создавать и перемещать листы, будет неплохой практикой устанавливать перед этими операциями команды отключения обновления экрана (Application.ScreenUpdating = False). При этом следует не забывать включать обновление экрана, если ваша процедура его отключала (Application.ScreenUpdating = True).
Помните, что вы можете добавить лист и после любого заданного листа. Процедура в листинге 16.10 добавляет лист перед последним листом и затем перемещает его, поскольку Excel не позволяет добавлять листы в конец книги. Использование аргумента After, совместно с методом Add позволяет добавить новый лист после любого существующего листа, за исключением последнего.
Как удалить лист
В целях поддержания управляемости книгами и экономии места на диске ненужные листы следует удалять. Это особенно актуально в случаях, когда созданные вами приложения используют для хранения промежуточных результатов временные листы. Для удаления листа используйте метод Delete.
СИНТАКСИС
Object.Delete
Object — ссылка на лист, который следует удалить.
Листинг 16.11 демонстрирует пример использования метода Delete.
Листинг 16.11. Использование метода Delete для удаления листа
1	Sub DeleteTemporarySheets()
2	' Удаление всех временных листов	*
3
4	Dim Sheet As Worksheet
5
6	Application.DisplayAlerts = False
7
8	For Each Sheet In Workbooks ( _
"Балансовый отчет 1202.XLS").Worksheets
9	If InStr(l, Sheet.Name, "Временный") Then
10	Sheet.Delete
11	End If
12	Next Sheet
13
14	Application.DisplayAlerts = True
15	End Sub
Управление host-приложениями VBA
411
Эта процедура проверяет каждый лист книги и удаляет все ранее созданные временные листы. Процедура «полагает», что временные листы должны называться Временный!, Временный2 и так далее.
Процедура объявляет объектную переменную Sheet (типа Worksheet) и задает свойство DisplayAlerts объекта Application равным False (строка 6). Таким образом подавляется обычное диалоговое Excel-окно подтверждения, которое появляется всякий раз, когда вы пытаетесь удалить лист. В строке 8 начинается цикл For Each, перебирающий все листы книги Балансовый отчет 1202.XLS. Функция InStr проверяет каждый лист на наличие в названии листа строки "Временный". Если такая строка обнаруживается, то (в строке 10 кода) этот лист удаляется. Когда данный процесс завершается, свойство DisplayAlerts вновь устанавливается равным True (строка 14).
Процедура в листинге 16.11 будет работать правильно, если Option Compare Text является текущей глобальной установкой сравнения.
Методы, возвращающие объекты Range
Наибольшую долю при работе с листом составляют: ввод информации, копирование данных, а также использование опций форматирования, включая работу с ячейками, диапазонами ячеек и их именами. Нет ничего удивительного в том, что так много методов объекта Excel в VBA, в конечном счете, выполняют какие-либо действия с диапазоном ячеек.
При обычной диалоговой работе с Excel прежде чем работать с диапазоном ячеек листа, диапазон необходимо выделить. Для процедуры VBA это означает, что вы должны сослаться на диапазон ячеек листа, перед тем как сможете что-нибудь с ним сделать. Наиболее распространенным из всех объектов Excel является объект Range. Объект Range может быть одной ячейкой, строкой, колонкой, набором ячеек и даже трехмерным диапазоном значений (то есть набором ячеек нескольких листов).
Использование Range метода
Наиболее легкий и прямой способ задать ячейку или диапазон ячеек состоит в использовании метода Range:
СИНТАКСИС
Object.Range(Name)
Object — ссылка на объект Worksheet, который содержит диапазон ячеек. Если вы опустите Object, VBA будет «считать», что метод применяется к объекту ActiveSheet. Аргумент Name — ссылка на диапазон ячеек или имя диапазона, введенное как текст. Метод Range работает также с именованными диапазонами ячеек.
Код листинга 16.12 демонстрирует пример использования метода Range.
Листинг 16.12. Использование метода Range 1 2 3 4 5 6 7 8 9
1 Sub FormatRangeFont()
2 1 С помощью метода Range задается шрифт для диапазона ячеек
3
4 With Worksheets("Лист1")
5	.Range("Al:LI").Font.Size = 24
6	.Range("Al:LI").Font.Bold = True
7	.Range("Al:LI").Font.Name = "Times New Roman"
8 End With
9 End Sub
412
Глава 16
В этом примере все три оператора (строки с 5 по 7) возвращают диапазон ячеек А1:Ы листа Лист1. (Обратите внимание на то, что диапазон ячеек следует заключать в кавычки.)
Процедура листинга 16.12 устанавливает некоторые атрибуты шрифта для заданного диапазона ячеек. Font — свойство объекта Range. Font возвращает ссылку на объект Font, связанный с заданным диапазоном значений. Свойства объекта Font — те же самые, что и атрибуты шрифта, которые можно задать при помощи диалогового окна Шрифт: полужирный, курсив, подчеркнутый и другие. Ниже, в качестве примера, представлено несколько1 свойств объекта Font (во всех случаях Object — объект типа Range):
	Object.Font.Bold: Устанавливает (или отменяет) полужирный стиль шрифта
(True или False).
	Ob/ect.Font.Italic: Устанавливает (или отменяет) курсив (True или False).
	Ob/ect.Font.Underline: Устанавливает эффект подчеркивания включенным или выключенным. Значение свойства Underline может быть равно одной из встроенных констант, определенных в классе xlUnderlineStyle: xlUnderline-StyleNone, xlUnderlineStyleSingle, xlUnderlineStyleDouble, xlUnderlineSty-leSingleAccounting или xlUnderlineStyleDoubleAccounting.
	Ob/ect.Font.Name: Устанавливает наименование шрифта. Значение свойства Name определяется, например, в виде строки "Arial".
	Obyect.Font.Size: Устанавливает размер шрифта (в пунктах).
В Excel имеется альтернативная синтаксическая конструкция для метода Range, применение которой требует двух аргументов:
СИНТАКСИС
Object.Range(Cell 1, Се112)
Как обычно, Object — является объектом типа Worksheet, содержащим диапазон значений ячеек. Аргумент Celli определяет верхний левый «угол» диапазона, а Се112 — правый нижний «угол». Каждый аргумент может быть текстовым адресом ячейки, объектом Range, состоящим из одной ячейки, или же целым столбцом или строкой.
Преимущество использования данной синтаксической конструкции заключается в разделении угловых значений в различных аргументах, что позволяет независимо изменять значение для каждого из «углов» под управлением процедуры. Например, вы можете задать имена переменных, таких как UpperLeft и Lower-Right, и возвращать объекты Range различных размеров в виде
Range(UpperLeft, LowerRight)
Не следует использовать в методе Range координаты диапазонов, если доступны их имена. Имена диапазонов облегчают восприятие и отладку программы.
Использование метода Cells
Хотя для того чтобы выполнить ссылку на одну ячейку, можно воспользоваться методом Range, такую же возможность дает и метод Cells, который является более гибким:
Для того чтобы просмотреть полный список свойств Font, используйте инструмент Object Browser.
Управление host-приложениями VBA
413
СИНТАКСИС
Object.Cells(Rowindex, Columnindex)
Object — ссылка или на Worksheet или на объект Range, содержащий ячейку, с которой необходимо работать. Если Object опущен, метод применяется к объекту ActiveSheet.
Rowindex — номер строки, в которой находится ячейка. Если Object — лист, то Rowindex, равный 1, ссылается на строку 1 листа. Если Object — диапазон значений, то Rowindex, равный 1, ссылается на первую строку диапазона. Columnindex — номер столбца, в котором расположена ячейка. Вы можете ввести или букву (как буквенную константу или как строковую переменную), или число, задающее столбец. Если Object — лист, то Columnindex, равный "А" или 1, ссылается на столбец А листа. Если Object — диапазон значений, то Columnindex, равный "А" или 1, ссылается на первый столбец диапазона.
В листинге 16.13 приведен пример использования метода Cells.
Листинг 16.13. Использование метода Cells
1	Sub CmdWrite_Click()
2	' Ввод данных из диалогового окна формы пользователя в лист
3
4	Dim	I As Integer
5	Dim	DBNewRow As Integer
6	Dim	NewRange As String
7
8	With Range("База_данных")
9	' находится новая строка данных
10	DBNewRow = .Row + .Rows.Count
11
12	' ввод данных из диалогового окна в ячейки новой строки
13	For I = 1 То .Columns.Count
14	Cells(DBNewRow, (I + .Column) - 1).Value = _
15	UserForml.Controls("TextBox" & CStr(I)).Text
16	Next I
17
18	' расширение диапазона базы данных
19	NewRange = "=" & .Parentt.Name & "!"
20	NewRange = NewRange & Cells(.Row, .Column).Address &
21	NewRange = NewRange & Cells(DBNewRow, _
22	(.Column + .Columns.Count) - 1).Address
23	Names("Базаданных").RefersTo = NewRange
24	End With
25	End Sub
Эта процедура — часть приложения поддержки базы данных. Пользователь вводит в «базу данных» информацию при помощи настраиваемого диалогового окна (подобного тому, что показано на рис. 16.1). Процедура CmdWrite_CHck вызывается при нажатии кнопки Записать новые данные диалогового окна. Процедура
Рис. 16.14
Диалоговое окно (в режиме разработки) для ввода данных
414
Глава 16
Cmd W rite_Click записывает новые данные в лист в конец диапазона ячеек базы данных и увеличивает диапазон ячеек базы данных для включения новой строки.
Описание элементов управления, на которые ссылается код процедуры листинга 16.13, приведено в следующей таблице:
Тип элемента	Свойство	Значение	Примечание k
UserForm	Name	UserForml	Имя формы, на которое можно Ссылаться в коде.
	Caption	Запись данных	Заголовок окна (формы) в верхней части.
Command-। Button	Name	Cmd Write	Имя кнопки, на которое можно ссылаться в коде.
	Caption	Запись	Текст на кнопке.
	Default	True	При нажатии на клавишу Enter инициируется событие Click кнопки.
Command-Button	Name	CmdExit	Имя кнопки, на которое можно ссылаться в коде.
	Caption	Выход	Текст на кнопке.
	Cancel	True	При нажатии на клавишу Esc инициируется событие Click кнопки.
Label	Name	Labell	Имя метки, на которое можно ссылаться в коде.
	Caption	Фамилия	Текст на метке.
Label	Name	Label2	Имя метки, на которое можно ссылаться в коде.
	Caption	Имя	Текст на метке.
Label	Name	Label3	Имя метки, на которое можно ссылаться в коде.
	Caption	Отчество	Текст на метке.
TextBox	Name	TextBoxl	Имя поля, на которое можно ссылаться в коде.
TextBox	Name	TextBox2	Имя поля, на которое можно ссылаться в коде.
TextBox	Name	TextBox3	Имя поля, на которое можно ссылаться в коде.
Пример работающего окна для ввода данных при помощи кода листинга 16.13 приведен на рис. 16.15.
Рис. 16.15
Процедура CmdWrite_Click листинга 16 13 работает с данными, вводимыми с использованием диалогового окна, подобного этому
Запись данных
Фамилия j Петров ’	Запись
Имя |~пётр~~
Отчество	ВЫХОД
Управление host-приложениями VBA
415
В строках с 4 по 6 объявляются переменные, используемые в процедуре. Строка 8 начинается оператором With, задающим диапазон ячеек, на которые ссылается имя База_данных. В строке 10 переменной DBNewRow присваивается значение, соответствующее строке, расположенной сразу же за диапазоном ячеек базы данных — это строка, в которой должны быть сохранены новые данные.
Цикл For...Next (в строках с 13 по 16) записывает значения из диалогового окна формы пользователя в лист. Счетчик цикла (I) «пробегает» значения от 1 до числа столбцов диапазона ячеек, полученного при нахождении свойства Count коллекции Columns для объекта Range. (Коллекция Columns содержит все столбцы объекта Range, а его свойство Count возвращает число столбцов.)
Внутри цикла метод Cells (строка 14) возвращает каждую ячейку в новой строке и свойство Value ячейки устанавливается равным соответствующему тексту в элементе управления окна редактирования. Предполагается, что каждый элемент управления окна редактирования в форме пользователя имеет имя (по умолчанию) TextBoxA, где N — номер текстового окна в последовательности помещения его на форму и соответствующего столбца в диапазоне ячеек базы данных. Таким образом, в строке 15 собирается имя элемента управления окна редактирования, из которого будет преобразовано значение данных посредством конкатенации строки, эквивалентной переменной текущего счетчика цикла, с буквенной константой "TextBox". [Вместо нескольких имен текстовых окон можно использовать один массив таких окон с одним именем и разными индексами. ]
Чтобы включить новую строку в «базу данных», необходимо изменить диапазон ячеек «базы данных». Переопределить диапазон, на который ссылается конкретное имя, можно, изменив свойство RefersTo этого имени. (Именованные диапазоны ячеек листа, являются объектами типа Name и доступны через коллекцию Names листа.) Свойство RefersTo должно содержать строку вида "=sheet\refe гепсе", где sheet — имя листа, содержащего именованный диапазон, a reference — адрес в виде R1C1.
В строках с 19 по 23 собирается соответствующим образом отформатированная строка, задающая новый диапазон «базы данных». В строке 19, чтобы получить имя листа, содержащего данный объект Range, к адресу диапазона с помощью свойства Parent объекта Range добавляется имя листа. Далее (в строке 20) с помощью свойства Address объекта Cells, возвращающего строку с адресом ячейки, на которую сделана ссылка, добавляются координаты верхнего левого «угла» нового диапазона ячеек (в данном случае это те же самые строка и столбец, на которые указывает текущая ссылка диапазона База_данных). В строках 21-22 вновь с использованием свойства Address (на этот раз — для ячейки, которая находится на пересечении новой строки и прежнего числа столбцов в диапазоне ячеек базы данных) добавляются координаты нижнего правого «угла» нового диапазона ячеек. Наконец, (в строке 23) свойству RefersTo присваивается новое значение диапазона База_данных, на который ссылаются посредством коллекции Names.
Использование метода Offset
При определении объектов Range конкретный диапазон адресов, который необходимо использовать, часто бывает неизвестен. Например, у вас может возникнуть необходимость сослаться на ячейку, которая расположена на две строки ниже и один столбец правее от активной ячейки. Хотя вы все-таки можете определить адрес активной ячейки и вычислить адрес ячейки, которая вам необходима, в Excel VBA предусмотрен более легкий и более гибкий путь — использование метода Offset. Offset возвращает объект типа Range, который смещен относительно заданного диапазона ячеек на заданное количество строк и столбцов.
416
Глава 16
СИНТАКСИС
Object.Offset(IRowOffset] [, ColumnOffsetl )
Object является ссылкой на исходный объект Range. RowOffset — число строк, на которое смещается Object. Вы можете использовать положительное число (для смещения вниз), отрицательное число (для смещения вверх), или О (для использования той же строки). Если вы опустите RowOffset, будет использовано значение по умолчанию — 0.
Листинг 16.14 демонстрирует процедуру, использующую метод Offset.
Листинг 16.14. Использование метода Offset для ссылки на диапазон ячеек
1	Sub SelectData()
2	' Выделяется область данных диапазона базы данных
3
4	Dim DBRows As Integer	'
5	'	,
6	Worksheets("Лист1").Select
7	With Range("База_данных")
8	DBRows = .Rows.Count
9	.Offset(l, 0).Resize(DBRows - 1, .Columns.Count).Select
10	End With
11	End Sub
Данная процедура выделяет область данных диапазона ячеек с именем База_данных, то есть диапазон, в который предполагается включать только данные (без заголовков столбцов), опуская для этого из текущего выбора первую строку именованного диапазона. Выполнение данной процедуры полезно, если необходимо выполнить над данными в таблице глобальные операции, такие как сортировка или форматирование.
В строке 6 выбирается лист с именем Лист1, а оператор With в строке 7 задает для этого листа объект Range с именем База^данных. В строке 8 с помощью свойства Rows.Count объект Range получает число строк диапазона ячеек, которое сохраняется в переменной DBRows.
В строке 9, метод Offset (с аргументами 1 и 0) возвращает диапазон, который является смещением диапазона База_данных на одну строку вниз. Поскольку этот диапазон включает (предположительно) пустую строку, находящуюся за диапазоном База_данных, вы должны эту дополнительную строку удалить. Чтобы выполнить данную операцию, можете воспользоваться свойством Resize, изменяющим размер диапазона:
СИНТАКСИС
Object.Resize([KowSize] [,ColumnSize})
Object — объектная ссылка на диапазон, размер которого изменяется. RowSi-ге — число строк в возвращаемом диапазоне. ColumnSize — число столбцов в возвращаемом диапазоне.
В строке 9 при помощи выражения Resize(DBRows—1, .Columns.Count) удаляется ненужная нижняя строка смещенного диапазона.
Метод Select (в строке 9) выделяет новый диапазон ячеек.
Другие методы и свойства, возвращающие диапазоны ячеек
Методы Range, Cells и Offset являются наиболее часто используемыми методами для возвращения объектов Range, но они далеко не единственные. На приме-
Управление host-приложениями VBA 417
ре кода листинга 16.14 вы познакомились с тем, как с помощью метода Resize можно возвратить диапазон заданного размера. Вот лишь некоторые методы и свойства, возвращающие объекты типа Range:
•	[cellRef]. Вы можете возвратить одну ячейку, поместив ссылку на нее в квадратные скобки. Например, [Al].Font.Size=16 устанавливает размер шрифта ячейки А1 равным 16 пунктам. Обратите внимание на то, что в данном случае для ссылки на ячейку не используется никаких кавычек.
•	Object .R<yws.(Index). Данный метод возвращает строку листа или диапазона ячеек, заданных при помощи Object. Если вы опустите Object, VBA использует ActiveSheet. Index — номер строки. Если Object является листом, Index, равный 1, ссылается на строку 1 листа. Если же Object является диапазоном, то Index, равный 1, ссылается на первую строку диапазона.
•	Object.EntireRow. Данное свойство возвращает целую строку или строки, содержащие диапазон ячеек, заданных при помощи Object.
	Object.Columns(/nciex). Данный метод возвращает столбец листа или диапазона ячеек, заданных при помощи Object. Если вы опускаете Object, VBA использует ActiveSheet. Index — буква или номер столбца. Если Object является листом, Index, равный "А" или 1, ссылается на столбец А листа. Если же Object является диапазоном ячеек, то Index, равный "А" или 1, ссылается на первый столбец диапазона.
	Object.EntireColumn. Данное свойство возвращает целый столбец или столбцы, содержащие диапазон ячеек, заданных при помощи Object.
•	Object.CurrentRegion. Данное свойство возвращает текущую область диапазона Object. Текущая область определяется как область, окружающая текущую ячейку или диапазон ячеек, ограниченный пустыми строками сверху и снизу и пустыми столбцами слева и справа.
Работа с Cells и Ranges
Теперь, когда вы знаете, как возвращать объект Range, вы можете использовать все преимущества применения многочисленных свойств и методов Range. В следующем разделе рассматриваются некоторые из этих свойств и методов. -Для того чтобы увидеть все методы и свойства объекта Range, пользуйтесь инструментом Object Browser и соответствующим данному объекту разделом справочной системы.
Выделение ячейки или диапазона ячеек
Для выделения ячейки или диапазона ячеек используйте метод Select:
СИНТАКСИС
Object.Select
Object — ссылка на объект типа Range, который выделяется.
Листинг 16.15 демонстрирует пример использования данного метода.
Листинг 16.15. Использование метода Select для выделения диапазона ячеек
1	Sub CreateChart()
2	' Создается диаграмма на основе данных диапазона Продажа
3
4	With Workbooks("Отчеты.XLS").Worksheets("Лист2")
5	.Activate
6	.Range("Продажа").Select
7	End With
4 Программирование на VBA 2002
f
418
Глава 16
8
9	Charts.Add
10	End Sub
Данная процедура создает из выбранного диапазона ячеек новую диаграмму. В строке 5 активизируется лист Workbooks(”OT4eTbi.XLS ”).Worksheets(JlHCT2). В строке 6 на листе выделяется диапазон ячеек с именем Продажа. В строке 9 для создания диаграммы выполняется метод Add объекта Charts.
Свойства Value и Formula
Если вам необходимо получить содержимое ячейки или ввести данные в диапазон ячеек, VBA предлагает два свойства объекта Range: Value и Formula. Синтаксис для использования этих свойств следующий:
СИНТАКСИС
Object.Value
Object.Formula
Object — объектная ссылка на объект типа Range, с которым необходимо работать. Для того чтобы получить содержимое ячейки, руководствуйтесь следующими правилами:
	Если вам необходимо значение, содержащееся в ячейке, используйте свойство Value. Например, если ячейка А1 содержит формулу =2*2, то выражение Range("Al").Value возвращает значение 4.
	Если вам необходима формула, содержащаяся в ячейке, используйте свойство Formula. Например, если ячейка А1 содержит формулу =2*2, то выражение Range("Al").Formula возвращает текстовую строку "=2*2".
Для того чтобы ввести ячейку или диапазон ячеек, вы можете применять как Value, так и Formula. Листинг 16.16 демонстрирует несколько примеров такого использования.
Листинг 16.16. Использование методов Value и Formula для ввода данных
1	Sub CreateCalculator()
2	' Выплаты по ссуде в листе с именем ЛистЗ
3
4	Worksheets("ЛистЗ").Select
5
6	With Range("Al")
7	' введение заголовков:
8	.Value = "Расчет выплат	по ссуде"	„
9	.Font.Bold = True	\
10	.Font.Italic = True
11	.Font.Size = 16
12	.Offset(1).Value = "Тариф"
13	.Offset (2) .Value = "Период"
14	.Offset(3).Value = "Количество"
15	.Offset(5).Value = "Платеж”
16
17	' ввод формата чисел и формулы:
18	.Offset(l,	1).NumberFormat	=	"0.00%"	4
19	.Offset (3,	1) .NumberFormat	=	,##0_);	($#,##0)"
20	.Offset(5,	1) .NumberFormat	=	"$#,##0.00_) ; [Red]	($#,##0.00)"
21	.Offset (5,	1).Formula = "=PMT($B$2/12,	$B$3*12,	$B$4)"
22	End With
23
24	End Sub
Управление host-приложениями VBA
419
Данная процедура помещает на ЛистЗ активной книги простой калькулятор для расчета выплат по ссуде. Оператор With использует ячейку А1 как начальную. Свойство Value этой ячейки устанавливается содержащим текст "Расчет выплат по ссуде" (строка 8), кроме того, устанавливаются некоторые параметры шрифта (строки 9-11). В следующих четырех строках (12-15) используется свойство Value ячеек А2, АЗ, А4 и А6 для ввода заголовков. При работе с этими ячейками обратите внимание на использование метода Offset. Код строк 18-20 задает формат ячеек В2, В4 и В6. Выполняется данная операция при помощи свойства NumberFormat для диапазона ячеек, на который существует ссылка:
Object.NumberFormat = FormatString
Object — является объектной ссылкой на ячейку или диапазон, которые необходимо отформатировать, Formatstring — текстовая строка, определяющая форматирование.
Наконец, код строки 21 использует свойство Formula для введения в ячейку В6 формулы платежа.
Определение имени диапазона ячеек
Имена диапазонов ячеек в VBA являются Name-объектами. Для того чтобы их задать, необходимо использовать метод Add коллекции Names, которая обычно является коллекцией имен, определенных в книге. Ниже представлена сокращенная синтаксическая конструкция использования метода Add коллекции Names. Всего данный метод имеет одиннадцать аргументов — все необязательные. Полный синтаксис метода следует смотреть в справочной системе, а легче всего получить доступ к нужному разделу справочной системы при помощи Object Browser.
СИНТАКСИС
Names.Add([Warne][, RefersTo} [, RefersToRlCl])
Аргумент Name — любое строковое выражение, задающее имя, которое вы хотите использовать для нового именованного диапазона. RefersTo и RefersToRlCl — аргументы, описывающие диапазон, на который ссылается имя. Аргументы используются следующим образом:
• RefersTo: Используйте данный аргумент для ввода диапазона ячеек, описанного в Al-стиле, например: "=Sales!$A$l:$C$6".
 RefersToRlCl: Используйте данный аргумент, когда диапазон ячеек описывается или в стиле R1C1, например, "=Sales!RlCl:R6C3”, или когда описание диапазона является методом или свойством, возвращающим диапазон, например, Range("Al:C6") или Selection.
Листинг 16.17 демонстрирует применение метода Add коллекции Names.
Листинг 16.16. Задание имени диапазона при помощи метода Add коллекции Names
1	Sub CreateNameRange()
2	' При помощи вводимых пользователем координат и имени,
3	' создает именованный диапазон ячеек
4
5	Const strTaskName = "Имя диапазона"
б
7
8
9
10
11
12
Dim strTopLeft As String
Dim strBottomRight As String
Dim RngName As String
Worksheets("Лист1").Select
4*
420
Глава 16
13	' принять диапазон и имя:
14	strTopLeft = InputBox(prompt:="Верхний левый угол " & _
15	"в формате R1C1:", _
16	Title:=strTaskName)
17	strBottomRight = InputBox(prompt:="Нижний правый угол " &
18	" в формате R1C1:",	_
19	Title:=strTaskName)
20	RngName = InputBox(prompt:="Имя для нового " & _
21	"диапазона ячеек:",	_
22	Title:=strTaskName)
23
24	' задать имя нового диапазона ячеек:
25	Names.Add Name:=RngName, RefersToRlCl:="=Лист1!" & _
26	strTopLeft &	& strBottomRight
27
28	' выделить новый диапазон ячеек
29	Range(RngName).Select
30
31	End Sub
Данная процедура не очень сложна — она(содержит всего лишь несколько операторов InputBox для того, чтобы получить координаты диапазона ячеек (верхний левый угол и нижний правый) и его имя. Затем, используя предложенные координаты и имя, процедура создает именованный диапазон ячеек.
Как вырезать, скопировать и очистить данные
Если ваша процедура должна выполнять некоторые основные, наиболее часто используемые операции редактирования листа, то это можно делать методами Cut, Сору и Clear. Синтаксис первых двух из них следующий:
СИНТАКСИС
Object.Cut([Destination])
Object.Copy([Destination])
Object — объектная ссылка на объект типа Range, который необходимо вырезать или скопировать. Destination — ячейка или диапазон, в который нужно поместить содержимое вырезанного или скопированного диапазона. Если вы опустите аргумент Destination, данные будут вырезаться или копироваться в буфер обмена Windows.
Для очистки диапазона ячеек вы можете использовать метод Cut с аргументом назначения или без него или воспользоваться любым из следующих методов:
СИНТАКСИС
Object.Clear
Object.СleaгContents
Object.ClearFormats
Object.ClearNotes
В каждом случае Object является объектной ссылкой на диапазон ячеек, который следует очистить. Метод Clear очищает все — содержимое, форматирование и примечания. ClearContents очищает содержимое Object, ClearFormats — форматирование Object, ClearNotes удаляет из Object примечания.
Листинг 16.18 демонстрирует пример применения методов Cut, Сору и Clear.
Управление host-приложениями УВД
421
Листинг 16.18. Использование методов Cut, Сору и Clear
1	Sub CopyToTemp()
2	' Копирует данные во временный лист
3
4	Dim Lastcell As Range
5	Dim oldSheet As String
6
7	Application.Screenupdating = False
8
9	oldSheet = Activesheet.Name	'	имя текущего листа
10	Worksheets.Add	'	создается временный	лист
11	ActiveSheet.Name = "Временный"
12	Worksheets("Лист1").Select	'	выбирается Лист1
13
14	Set Lastcell = Range("Al").Specialcells(xlLastCell)
15	With Worksheets("Временный")
16	.Cells.Clear
17	RangeCAl", Lastcell) .Copy Destination : = . Range ( "Al" )
18	End With
19
20	Sheets(oldSheet).Select	'	восстанавливается	исходный лист
21	Application.Screenupdating	=	True
22
23	End Sub
24
25
26	Sub RestoreFromTemp()
27	' Восстанавливаются данные из временного листа
28
29	Dim Lastcell As Range
30	Dim oldSheet As String
31
32	Application.Screenupdating = False
33	oldSheet - ActiveSheet.Name
34
35	Worksheets("Лист1").Select
36	With Worksheets("Временный")
37	Set Lastcell = .Range("Al").Specialcells(xlLastCell)
38	.Range("Al", Lastcell).Cut Destination:=Range("Al")
39	End With
40
41	Sheets(oldSheet).Select
42	Application.Screenupdating	= True
43
44	End Sub
Код состоит из двух процедур: CopyToTemp (строки 1-23) и RestoreFromTemp (строки 26-44). Процедура CopyToTemp добавляет лист с именем Временный и выбирает лист с именем Лист1. Далее она копирует все данные из активного листа и сохраняет их в листе Временный. Для возврата последней ячейки активного листа и сохранения объектной ссылки результирующего объекта Range в переменной LastCell данная процедура использует метод SpecialCells с аргументом xlLastCell (строка 14). Затем с использованием оператора With над листом Временный выполняются два действия: код строки 16 использует метод Clear для очистки всего листа (метод Cells без аргументов возвращает все ячейки листа), код строки 17 использует метод Сору для копирования диапазона, заданного с помощью А1 (верхний левый угол) и LastCell (нижний правый угол); «получателем» является ячейка А1 листа Временный.
422
Глава 16
Вторая процедура, RestoreFromTemp, выполняет обратные действия. На этот раз LastCell устанавливается на последнюю ячейку листа Временный (строка 37). Диапазон от А1 до LastCell вырезается и помещается в ячейку А1 активного листа (строка 38). Активным является лист Лист1, выбранный в строке 35.
Для вставки данных из буфера обмена в лист используйте с объектами Worksheet или Range методы Paste или PasteSpecial. Синтаксис метода Paste следующий:
СИНТАКСИС
Object.Paste ([Destination], [Link])
Object — любая допустимая объектная ссылка на лист. Необязательный аргумент Destination — любой объект диапазона ячеек. Данные вставляются, начиная с верхнего левого угла диапазона. Если вы опустите аргумент Destination, данные вставляются, начиная с выбранной в данный момент ячейки. Использование аргумента Destination аналогично использованию команды Правка | Вставить (Edit | Paste). Если необязательный аргумент Link равен значению True, то должна быть задана ссылка на источник данных. Использование аргумента Link аналогично использованию команды Правка | Специальная вставка (Edit | Paste Special) с установленным флажком Связать (Link). Одновременное использование аргументов Destination и Link в одном операторе недопустимо.
Работа с объектами Word
До сих пор в данной главе обсуждалась работа только с объектами, доступными в Excel VBA. Word также создает многочисленные объекты, доступные VBA. В этой части главы вы узнаете, как управлять большинством наиболее важных и распространенных объектов Word. Во-первых, вы узнаете об объектах Document и Template, а затем о том, как управлять информацией, содержащейся в объекте Document.
Работа с объектами Document
В Word используется формат документа, в котором объекты и события полностью доступны VBA, что дает возможность управлять документом и его объектами при помощи VBA-кода. Такой формат документа Word позволяет выполнять наиболее распространенные задачи обработки текста быстрее и легче. В следующих нескольких разделах рассмотрены наиболее часто используемые объекты, методы и свойства Word.
Доступ к объекту Document
В Word каждый документ является объектом типа Document, а все открытые документы текущей сессии Word образуют коллекцию Documents. Для ссылок на конкретный документ следует использовать коллекцию Documents объекта Application.
СИНТАКСИС
Documents(index)
Index может быть:
	Численным выражением, представляющим документ, который необходимо использовать. Число 1 означает первый документ, открытый в ходе текущей рабочей сессии, 2 — второй открытый документ и так далее.
Управление host-приложениями УВД
423
	Строковым выражением, представляющим имя открытого документа, который нужно использовать.
Наиболее распространенным и в большинстве случаев наиболее удобным способом использования Index является текстовая строка.
Листинг 16.19 демонстрирует пример использования коллекции Documents.
Листинг 16.19. Использование коллекции Documents для возвращения документа
1	Sub SetDocumentActivate()
2	' Делает (открытый) документ активным
3
4	Documents("с:\F.DOC").Activate
5	MsgBox "F.DOC становится активным!"
6
7	End Sub
Выражение в строке 4, Documents("C:\F.DOC"), возвращает объектную ссылку на объект документ C:\F.DOC. Метод Activate делает указанный документ активным. Оператор MsgBox в строке 5 выводит об этом сообщение. (Документ C:\F.DOC в момент выполнения процедуры должен быть открыт, в противном случае вы получите сообщение о runtime-ошибке.)
Для ссылок на активный документ нужно применять Application-свойство ActiveDocument. Свойство ThisDocument следует использовать для ссылок на документ, содержащий выполняемую в данный момент процедуру, особенно если вы намереваетесь преобразовать свою программу в Word-надстройку (add-in)1.
Как открыть документ
Если необходимый вам документ не открыт, для загрузки его в память используйте метод Open:
СИНТАКСИС
Documents.Open(Filename)
Аргумент Filename является текстовой строкой, представляющей полный путь к документу: логический диск, папка и имя файла. Если вы не задали диск или имя папки, Word будет искать документ на текущем диске или в текущей папке.
Листинг 16.20 демонстрирует действие метода Open.
Листинг 16.20. Использование метода Open для открытия документа 1 2 3 4 5 6 7 8 9
1 Sub OpenTest()
2 ' Предлагает открыть документ и затем его открывает
3
4 Dim DocumentName As String
5
6	DocumentName = _
7	InputBox("Введите полный путь к документу")
8	If DocumentName <> "" Then
9	Documents.Open FileName:=DocumentName
1 До появления локализованной версии Office 97 использовался термин «надстройка», в Office 97 появился термин «дополнение», тем не менее Microsoft Press пользуется привычным русским пользователям термином «надстройка».
424
Глава 16
10 End If
11
12 End Sub
В данной процедуре переменная DocumentName объявляется как String (строка 4), а функция InputBox предлагает пользователю ввести имя документа (строки 6 и 7). Оператор If...Then (в строке 8) проверяет, не отменил ли пользователь диалог ввода. Если — нет (другими словами, если переменная Document-Name не пуста), метод Open использует ее для того, чтобы открыть заданный документ (строка 9).
Чтобы избежать ошибок при открытии существующего на диске файла (пользователь вряд ли введет в диалоговом окне функции InputBox правильное имя файла), следует использовать встроенное в Word диалоговое окно Open. Вы можете использовать встроенное в Word диалоговое окно Open при помбщи коллекции Dialogs, как показано ниже (Dialogs содержит все диалоговые окна, встроенные в Word):
Application.Dialogs(wdDialogFileOpen).Show
Как создать новый документ
Если вашей процедуре необходимо создать новый документ, используйте метод Add коллекции Documents, имеющий следующий синтаксис:
СИНТАКСИС
Documents.Add([Template], [NewTemplate])
Оба аргумента метода Documents.Add не являются обязательными. Template представляет строковое выражение, задающее имя шаблона документа, на ко-, тором должен основываться новый документ. Аргумент Template наряду с именем файла может включать имя диска и путь к папке. Включать полный путь необходимо, если шаблон документа расположен в папке, отличной от той, в которой по умолчанию хранятся шаблоны Word. Если вы опустите аргумент Template, Word создаст новый документ, основываясь на шаблоне Normal.dot.
Аргумент NewTemplate может быть любым выражением типа Boolean. Если он равен значению True, Word создает новый документ в виде шаблона. По умолчанию значение этого аргумента равно значению False.
Листинг 16.21 демонстрирует пример процедуры, создающей новый документ.
Листинг 16.21. Использование метода Add для создания нового документа
1 Sub CreateNewLetter()
2 ' Содает документ на базе шаблона Professional Letter
3
4 Dim dPath As String
5
6 dPath = "E:\Program Files\Microsoft Office\Templates\1049\"
7	Documents.Add Template:=dPath & "Professional Letter"
8 With ActiveDocument
9	.BuiltlnDocumentProperties("Title") = _
10	"Письмо из России"	%
11	.BuiltlnDocumentProperties("Subject") =	_
12	Str(Date)
13	.BuiltlnDocumentProperties("Author") =
14	Application.UserName
15 End With
16
17 End Sub
Управление host-приложениями УВД
425
Код листинга 16.21 создает новый документ на основании шаблона Professional Letter, поставляемого вместе с Word и Microsoft Office. Любой новый документ автоматически становится активным. В строках с 8 по 15 используется объект ActiveDocument для добавления некоторой общей информации, относящейся к новому документу. Свойства документа Title, Subject и Author хранятся в коллекции BuiltlnDocumentProperties объекта Document. В результате на экране появляется заготовка письма. Свойства активного документа, устанавливаемые в строках кода 8-15, можно увидеть в диалоговом окне Свойства (рис. 16.16).
Рис. 16.16
Свойства активного документа, заданные в строках кода 8-15, можно увидеть в этом диалоговом окне
Как сделать документ активным
Если ваша VBA программа хранит несколько документов, открытых одновременно, вам может понадобиться переключаться с одного документа на другой. Для того чтобы сделать какой-либо из открытых документов активным, используйте метод Activate:
СИНТАКСИС
Object.Activate
Object представляет собой ссылку на документ, который следует сделать активным.
Листинг 16.22 представляет пример процедуры, использующей метод Activate.
Листинг 16.22. Использование метода Activate для переключения к документу
1 Sub ActivateTest ()
2 ' Активизирует два документа без изменения вывода на экран 3
4	Dim SaveDoc As String
5
6	SaveDoc = ActiveDocument.Name
7
8 Application.ScreenUpdating = False 'не обновлять экран
426
Глава 16
9	Documents("TestData.DOC").Activate
10
11	' действие, выполненное над TestData.DOC
12	With Selection
13	.TypeText Text:="Документ данных установлен активным"
14	.Typeparagraph
15	End With
16	•
17	Documents(SaveDoc).Activate
18	Application.Screenupdating =	True 'обновлять экран
19
20	End Sub
Процедура листинга 16.22 демонстрирует два принципа хорошего стиля программирования: скрывать от пользователя промежуточные операции и всегда «возвращать пользователя» в то место, из которого он запустил программу. Назначение процедуры листинга 16.22 — переключиться из текущего документа в другой документ (TestData.doc), произвести в нем (программно) определенные изменения и затем вернуться к исходному документу. В первую очередь (в строке 6) имя текущего активного документа сохраняется в строковой переменной SaveDoc. Далее, чтобы избавить пользователя от наблюдения за подробностями выполнения процедуры, в строке 8 свойство ScreenUpdating задается равным значению False. В строке 9 активизируется документ TestData.doc. Строки с 12 по 15 представляют действия, выполняемые над документом TestData.doc. Данный фрагмент программы просто добавляет в документ некоторый текст. Чтобы «вернуть пользователя» обратно в исходный документ, в строке 17 документ вновь устанавливается активным. А в строке 18 свойство ScreenUpdating вновь получает значение True.
Не следует без особой необходимости активизировать документ. Как правило, вы можете выполнить изменения или получить информацию о документе, просто ссылаясь на соответствующий объект Document. Например, чтобы выяснить, какой шаблон присоединен (если вообще какой-нибудь присоединен) к TestData.doc, вы можете использовать следующий оператор (не делая документ активным):
DocTemplate = Document("TestData.doc").AttachedTemplate
Как сохранить документ
Если ваш VBA-код изменяет содержимое документа, вы должны быть уверены, что дадите пользователю возможность сохранить эти изменения, или обеспечить их сохранение с помощью вашей программы. Хотя вы можете включить встроенную в Word команду Save в меню и панели инструментов, вы, возможно, захотите сохранять документ под управлением процедуры, особенно если нужно не дать пользователю возможности отказаться от изменений, произведенных вашим VBA-кодом.
Для сохранения документа используйте метод Save объекта Document:
СИНТАКСИС
Object.Save
Object представляет ссылку на открытый объект типа Document, который необходимо сохранить.
Можно воспользоваться и родственным методом SaveAs. Данный метод сохраняет документ под новым именем и изменяет имя документа. (Метод имеет шестнадцать необязательных аргументов, здесь для простоты указаны только два из них. В справочной системе вы можете найти полный синтаксис этого метода.)
Управление host-приложениями УВД 427
СИНТАКСИС
Object.SaveAs([FileName] , [FileFormat] )
Object — любая допустимая ссылка на открытый документ типа Document. Необязательный аргумент FileName — строковое выражение, указывающее новое имя, под которым должен быть сохранен документ. FileName может включать полный путь (включая диск и папку). Если опустить полный путь, документ сохраняется в текущей папке на текущем диске. Если вы полностью опустите аргумент FileName, документ сохранится под текущим именем, если документ с подобным именем уже существует, он будет переписан без предупреждения.
Необязательный аргумент FileFormat определяет формат, в котором будет сохранен документ. Аргумент FileFormat может быть любой из встроенных констант (определенных в классе wdSaveFormat): wdFormatDocument, wdFormat-DOSText, wdFormatDOSTextLineBreaks, wdFormatEncodedText, wdFormat-FilteredHTML, wdFormatHTML, wdFormatRTF, wdFormatTemplate, wdFor-matText, wdFormatTextLineBreaks, wdFormatUnicodeText или wdFormatWeb-Archive.
Листинг 16.23 демонстрирует пример процедуры, использующей как Save, так и SaveAs.
Листинг 16.23. Применение методов Save и SaveAs
1	Sub CreateTemplate()
2	' На базе активного документа создается новый шаблон документа
3
4	Dim NewName As String
5
6	With ActiveDocument
7	If Not .Saved Then .Save
8	NewName = Left(.Name, Len(.Name) - 3) & "dot"
9	' .SaveAs FileName:=NewName, FileFormat:=wdFormatTemplate
10	End With
11
12	End Sub
Процедура этого листинга сохраняет активный документ, а затем сохраняет копию активного документа как шаблон. Начинается код с объявления переменной, предназначенной для сохранения имени файла нового шаблона. Оператор With в строках с 6 по 10 содержит операторы, связанные с объектом ActiveDocument.
Оператор If...Then (строка 7) проверяет свойство Saved документа. Если оно равно значению False, документ содержит изменения, которые еще не были сохранены, поэтому процедура вызывает метод Save.
Имя файла шаблона создается в строке 8 конкатенацией полного имени документа, за исключением последних трех символов, со стандартным расширением для имени файла шаблона "dot". (Имя документа получается из его свойства .Name.) Результат используется в качестве аргумента для метода SaveAs (строка 9), который сохраняет копию документа в виде файла шаблона. Обратите внимание на использование аргумента FileFormat, имеющего значение wdFormatTemplate — данное значение аргумента сообщает Word о том, что необходимо сохранить документ как шаблон.
Для проверки того, был ли документ когда-либо сохранен, следует использовать свойство Path объекта Document. Если Path возвращает пустую строку (""), то документ никогда прежде не сохранялся.
к
428
Глава 16
Как закрыть документ
Завершив работу с документом, вы должны закрыть его для освобождения памяти и других системных ресурсов. Закрыть документ можно, используя одну из следующих форм метода Close.
СИНТАКСИС
Documents.Close
Object.Close([SaveChanges] [, OriginalFormat ] [, RouteDocument ])
Первая синтаксическая форма просто закрывает все открытые документы. Word предлагает перед закрытием документа (если это необходимо) сохранить сделанные в нем изменения.
Вторая синтаксическая форма закрывает конкретный документ, на который указывает Object. Аргумент SaveChanges может быть равен одной из перечисленных ниже встроенных констант (определенных в классе wdSaveOptions): wdDoNotSaveChanges (документ закрывается без сохранения изменений), wdPromptToSaveChanges (Word запрашивает, нужно ли сохранять изменения), wdSaveChanges (изменения сохраняются). Аргумент OriginalFormat определяет формат сохранения для документа и может быть одной из следующих wdOriginalFormat-констант: wdOriginalDocumentFormat, wdPromptU-ser или wdWordDocument. Аргумент RouteDocument определяет необходимость передачи документа следующему получателю.
В листинге 16.24 приведен код с использованием метода Close.
'	Листинг 16.24. Применение метода Close
1	Sub CloseAll()
2	1 Закрывает все документы и предлагает сохранить изменения
3
4	Const qButtons = vbYesNo + vbQuestiion
5
6	Dim	Doc As Document
7	Dim	Ans As Integer
8	Dim	MsgPrompt As String
9
10	For	Each Doc In Documents
11	If Not (Doc.Name - ThisDocument.Name) Then
12	If Not Doc.Saved Then
13	MsgPrompt = "Сохранить изменения в " & Doc.Name & "?"
14	Ans = MsgBox(prompt:=MsgPrompt, Buttons:=qButtons)
15	If Ans	=	vbYes Then
16	Doc.Close SaveChanges:=wdSaveChanges
17	Else
18	Doc.Close SaveChanges:=wdDoNotSaveChanges
19	End If
20	Else
21	Doc.Close
22	End If
23	End If
24	Next Doc		'
25
26	End Sub
Процедура листинга 16.24 закрывает все открытые документы (за исключением документа содержащего саму процедуру) и спрашивает у пользователя, нужно ли выполнять сохранение внесенных изменений для каждого из документов,
Управление host-приложениями VBA
429
имеющих несохраненные изменения. Используйте подобную процедуру вместо метода Documents.Close, если необходимо заблокировать возможность отмены операции пользователем (встроенный в Word запрос Save имеет кнопку Cancel).
После объявления константы и нескольких переменных, процедура запускает цикл For Each для обработки всех документов коллекции Documents.
Поскольку закрытие документа, содержащего выполняемую в данный момент процедуру, приведет к завершению ее выполнения, в строке 11 находится оператор If...Then, проверяющий, не совпадает ли имя обрабатываемого в данный момент документа с именем документа, содержащего процедуру CloseAll. Если они совпадают, часть программы, закрывающая документ пропускается; строки с 12 по 22 выполняются только в том случае, если документ не содержит процедуры CloseAll (свойство ThisDocument возвращает ссылку на документ, содержащий выполняемую в данный момент программу).
Если документ содержит изменения, которые не были сохранены (строка 12), функция MsgBox «спрашивает», нужно ли сохранять изменения. Если пользователь выбирает кнопку Yes (то есть в переменную Ans возвращается значение константы vbYes), процедура запускает метод Close с аргументом SaveChanges, равным значению константы wdSaveChanges (строки 15 и 16). В противном случае процедура закрывает документ с аргументом SaveChanges, равным значению константы wdDoNotSaveChanges (строка 16). Если документ не содержит несохранен-ных изменений, процедура выполняет метод Close без аргументов (строка 21).
Работа с объектами Template
В Word каждый шаблон документа является объектом типа Template, a Templates — коллекцией всех открытых шаблонов. Далее рассматривается, как выполнять основные операции с объектами Template.
Как создать шаблон
Коллекция Templates не имеет метода Add. Поэтому для добавления к ней нового шаблона нужно создать этот шаблон, сначала создав объект Document. Вы можете создать новый шаблон документа одним из следующих способов:
	Использовать метод Documents.Add с аргументом NewTemplate, равным True, для одновременного создания нового документа и преобразования его в объект Template.
	Использовать метод SaveAs объекта Document с аргументом FileFormat, заданным как wdFormatTemplate для сохранения документа в виде шаблона (в листинге 16.23 это уже использовалось).
Как загружать и выгружать общие шаблоны
Как вы уже можете знать, единственный способ сделать код в проекте VBA Word доступным всем открытым документам — это сохранить его в шаблоне документа, загруженном как общий. По этой причине вам, возможно, захочется поместить процедуру текущего документа в шаблон, загруженный как общий, делая таким образом процедуры и другие ресурсы данного шаблона доступными всем открытым документам.
Коллекция Templates не имеет метода Open. Вместо этого следует загружать шаблон документа как общий посредством коллекции Addins объекта Applications Word. (Addins — коллекция всех доступных в Word надстроек, независимо от того, были они установлены или нет.) Поскольку они являются общими ресурсами для программ, панелей команд, стилей и других элементов, Word рассматривает общие шаблоны как разновидность надстройки.
Если вы знаете, что ваша программа больше не нуждается в ресурсах конкретного шаблона, то можете выгрузить общий шаблон для освобождения системных ресурсов компьютера.
430
Глава 16
Чтобы загрузить шаблон как общий, используйте метод Add коллекции Addins в следующей синтаксической форме:
СИНТАКСИС
Object.Add(FileName [, Install])
Object представляет ссылку на объект Addins. Аргумент FileName является обязательным. Это — строковое выражение, содержащее имя файла шаблона, включая полный путь.
Аргумент Install (необязательный) управляет установкой надстройки: при равенстве значению True (значение по умолчанию) надстройка устанавливается, при False — добавляется в список надстроек, но не устанавливается.
Для того чтобы выгрузить общий шаблон, используйте метод Delete коллекции Addins в следующей синтаксической форме:
СИНТАКСИС
Addins(Name).Delete
Name — строковое выражение, задающее имя шаблона, который нужно выгрузить, или численное выражение, указывающее номер индекса шаблона в коллекции. Как и для большинства других коллекций, следует пользоваться именами шаблонов, чтобы создавать удобочитаемые и надежные программы.
Листинг 16.25 содержит две демонстрационные процедуры: одна загружает шаблон как общий, а другая выгружает общий шаблон.
Листинг 16.25. Загрузка и выгрузка общего шаблона
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Sub LoadGlobalTemplate() ' Загружает и определяет общий шаблон
Dim strName As String
strName = InputBox(prompt:“"Введите имя шаблона:" &
vbCr & "(включая полный путь)", _
Title:“"Загружается общий шаблон")
If Trim(strName) = "" Then Exit Sub
Addins.Add FileName:“StrName
End Sub	•-
Sub UnloadGlobalTeplate() 1 Выгружает шаблон, заданный как общий
Dim strName As String
strName = InputBox(prompt:“"Введите имя шаблона:", _
Title:“"Выгрузка общего шаблона") 4 * * * *
If Trim(strName) = "" Then Exit Sub Addins(strName).Delete
End Sub
Управление host-приложениями VBA
431
Как присоединить шаблон
У вас может возникнуть необходимость определять, какой шаблон (если таковой вообще имеется) присоединен к документу. Или же у вас может появиться желание присоединить определенный шаблон к документу.
Чтобы задать присоединенный к документу шаблон, используйте свойство AttachedTemplate объекта Document в следующей синтаксической форме:
СИНТАКСИС
Object.AttachedTemplate = Template
Здесь Object — любая допустимая ссылка на объект типа Document. Template может быть как объектной ссылкой на уже открытый Template-объект, так и строковым выражением, задающим имя файла шаблона, который необходимо присоединить.
Свойство AttachedTemplate всегда возвращает объектную ссылку на объект типа Template. Если документ не содержит присоединенного шаблона, свойство AttachedTemplate возвращает ссылку на Normal.dot.
Следующий фрагмент программы присоединяет шаблон к активному документу (предполагается, что переменная TestTemplate содержит строку, включающую полный путь к файлу шаблона):
ActiveDocument.AttachedTemplate = TestMyTemplate
Для отключения от активного документа всех шаблонов достаточно использовать следующий код:
ActiveDocument.AttachedTemplate = ""
Компоненты объекта Document
Документ в Word представляет собой конструкцию довольно свободной формы: он состоит из символов, слов, предложений и абзацев. Документ может содержать колонтитулы, сноски и прочие элементы. Как следствие, число и тип объектов, используемых для управления содержимым документа, может сначала вызвать замешательство.
Каждый документ состоит из нескольких областей (stories). Каждая область документа соответствует конкретному разделу документа, такому как колонтитул, сноска основной текст документа, примечания и так далее. Многие методы объекта Document позволяют выбрать конкретную область. Многие объекты так же обладают свойствами, из которых можно извлечь значение, указывающее, какая область объекта документа в нем содержится. VBA Word предоставляет несколько внутренних констант (определенных в классе wdStoryType), которые вы можете использовать для задания конкретной области документа: wdMainTextStory, wdPrimaryFooterStory, wdPrimaryHeaderStory и другие.
Текст внутри области документа может рассматриваться как коллекция символов, слов, предложений или абзацев. Word предоставляет коллекцию объектов для каждого из этих представлений: Characters, Words, Sentences и Paragraphs. Ниже дана краткая характеристика этих коллекций:
	Characters. Коллекция символов. В зависимости от того, из какого объекта вы получили доступ к коллекции, она может содержать некоторые или все символы области документа. Объект для одного символа отсутствует. Каждый элемент коллекции Characters является объектом типа Range, включающим только один символ. (Объекты Range Word будут рассмотрены далее в этом разделе.)
	Words. Коллекция слов. В зависимости от того, из какого объекта вы получили доступ к коллекции Words, она может содержать некоторые или все слова
432
Глава 16
области документа. В Word отсутствует объект слово. Каждый элемент коллекции Words является объектом типа Range, включающим только одно слово. (Слово — это группа символов, отделенная пробелами или знаками пунктуации.)
	Sentences. Коллекция предложений. В зависимости от того, из какого объекта вы получили доступ к коллекции Sentences, она может .содержать некоторые или все предложения области документа. Подобно коллекциям Characters ' и Words объект одно предложение отсутствует. Каждый элемент коллекции Sentences является объектом типа Range (который будет описан далее в этой главе), включающим единственное предложение.
	Paragraphs. Коллекция абзацев. В зависимости от того, Paragraphs-коллекция какого именно объекта используется, может содержать некоторые или все абзацы области документа. Каждый элемент коллекции Paragraphs является объектом типа Paragraph. Вы можете использовать свойства и методы объекта Paragraph для изменения стиля, увеличения или уменьшения интерлиньяжа и других, связанных с абзацем задач. Каждый объект типа Paragraph, в свою очередь, содержит объект типа Range, который содержит текст параграфа.
Представленный обзор коллекций показывает, что доступ к тексту для каждой из этих коллекций, в конечном счете, осуществляется с помощью объекта Range. Объект Range является одним из основных объектов Word и появляется в виде свойства во многих других объектах Word.
Каждый объект Range представляет непрерывную часть области документа, определяемую положениями начального и конечного символов. Объект Range может не содержать ни одного, содержать один или много символов и может представлять весь документ или любую его часть. Используя методы и свойства объекта Range, можно добавлять текст, форматировать его, добавлять поля или выполнять любые другие действия. Объект Range также предоставляет методы, позволяющие задавать или изменять диапазон символов, на который ссылается конкретный объект Range, и определять, в каком текстовом блоке документа находится диапазон.
Другим основным объектом Word является объект Selection. Объект Selection представляет курсор вставки в окне, отображающем определенную часть документа. В каждом окне документа может находиться только один объект Selection, и только один объект Selection может быть активным в любой конкретный момент времени. Объект Selection используется для того, чтобы добавлять текст в место, на которое указывает курсор вставки, применять форматирование, выделять текст для копирования или вырезания, или любой другой задачи, которую можно выполнить интерактивно с помощью курсора вставки, вводя текст, щелкая, или перетаскивая его. Объект Selection может быть как непрерывной областью документа, так и сжатым до курсора вставки. В следующем разделе обсуждается, как с помощью свойств и методов объекта Selection выполнять основные операции с документом.
В дополнение к только что описанным основным компонентам документа каждый объект Document также содержит несколько других коллекций, таких как Fields (коллекция полей, включая поля для простановки почтовых реквизитов в документе), TablesOfContents и другие. Различные коллекции объекта Word упоминаются при их использовании в этой и других главах книги.
Как задать диапазон
Прежде чем вы сможете работать с объектом Range, следует задать в документе диапазон текста, с которым необходимо работать. Объект Range может являться курсором вставки, не содержащим ни одного символа, или быть непрерывной областью документа. Вы можете создать в документе более одного объекта Range.
Управление host-приложениями VBA
433
Как получить ссылку на объект
Существует несколько различных способов сослаться на конкретный диапазон документа. Можно задать диапазон непосредственно или получить его при помощи одной из коллекций документа: Paragraphs, Sentences или Words.
Для того чтобы задать диапазон в области основного текста документа непосредственно, воспользуйтесь *методом Range, применив следующую синтаксическую конструкцию:
СИНТАКСИС
Object.Range(Start, End)
Здесь Object — любая допустимая ссылка на объект Document. Start и End — целые значения типа Long, задающие положение начального и конечного символов диапазона, соответственно. Метод Range возвращает объект Range.
В следующем фрагменте программы метод Range используется для получения диапазона, начинающегося перед первым символом и заканчивающегося после двадцатого символа активного документа (AnyRange — объектная переменная):
Set AnyRange = ActiveDocument.Range(Start:=0, End:=20)
Ссылку на диапазон можно получить и с помощью свойства Range любой из коллекций диапазона, упоминавшихся ранее: Paragraphs, Sentences или Words. Представленные ниже примеры выражений демонстрируют, как это сделать:
ActiveDocument.Sentences(3)
ActiveDocument.Paragraphs(2)
ActiveDocument.Words (10)
Первое выражение возвращает объект Range, ссылающийся на третье предложение активного документа. Второе — возвращает объект Range, ссылающийся на второй абзац активного документа, а третье выражение возвращает объект Range, ссылающийся на десятое слово активного документа.
Следующие два примера выражений немного сложнее. Первое из помещенных ниже выражений возвращает объект Range, ссылающийся на первое слово второго абзаца активного документа. Коллекция Paragraphs используется для возвращения ссылки на второй абзац документа, а коллекция Word, связанная с диапазоном объекта Paragraph, — для возвращения ссылки на первое слово абзаца. Второе выражение возвращает объект типа Range, ссылающийся на первое слово первого предложения активного документа. Коллекция Sentences используется для возвращения ссылки на первое предложение документа, а коллекция Words данного предложения — для возвращения объекта Range, ссылающегося на первое слово в предложении.
ActiveDocument.Paragraphs(2).Range.Words(1)
ActiveDocument. Sentences (1) .Words(1)
Код листинга 16.26 демонстрирует пример процедуры, использующей различные диапазоны.
Листинг 16.26. Использование объектов Range 1 2 3 4 5 6 7 8
1 Sub TestRangeO
2 1 В активном документе первое слово каждого
3 ' абзаца, имеющего стиль "Основной текст" и длину не менее
4 ' трех слов, выделяется курсивом
5
6 Dim mParagraph As Paragraph
7
8 For Each mParagraph In ActiveDocument.Paragraphs
434
Глава 16
9	With mParagraph
10	If .Style = "Основной текст" Then
11	If .Range.Words.Count >= 3 Then
12	.Range.Words(1).Italic = True
13	End If
14	End If
15	End With
16	Next mParagraph
17
18	End Sub
Процедура TestRange выделяет курсивом первое слово каждого абзаца в главной области документа, если он содержит три или более слов и если стиль данного абзаца — Основной текст.
В строке 8 начинается цикл For Each, который перебирает все абзацы коллекции Paragraphs документа. Строка 9 начинается с оператора With, включающего несколько операторов, ссылающихся на свойства и методы текущего объекта Paragraph. В строке 10 используется оператор If для определения того, действительно ли абзац имеет стиль Основной текст. Текущий стиль абзаца определяется при помощи свойства Style.
В строке 11 используется оператор If для определения того, содержит ли абзац более двух слов. Поскольку символ конца абзаца считается словом, для любого абзаца, содержащего как минимум два слова, не считая символа конца абзаца, выражение в строке 11 будет равно значению True.
В строке 12 первое слово абзаца выделяется курсивом. Сначала при помощи свойства Range объекта Paragraph, возвращается диапазон, на который ссылается данный абзац. В свою очередь, коллекция Words используется для того, чтобы возвратить объект типа Range, ссылающийся на первое слово в диапазоне абзаца. Чтобы выделить слово курсивом, свойство Italic объекта Range устанавливается равным True.
Как выполнить ссылку на диапазон
Размер области, на которую ссылается конкретный объект Range, можно изменять. Например, вы можете сначала получить диапазон, который ссылается на один абзац, а затем изменить область данного диапазона, включив в него два следующих абзаца. Область документа, на которую ссылается объект Range, можно расширить или уменьшить, и даже сжать диапазон до курсора вставки.
Чтобы изменить область, на которую ссылается диапазон, используйте следующую синтаксическую конструкцию для метода SetRange:
СИНТАКСИС
Object.SetRange(Start, End)
Здесь Object — любая допустимая ссылка на объект Range или Selection. Оба аргумента Start и End являются обязательными, каждый из них является целым числом типа Long, представляющим новые позиции начального и конечного символов диапазона, соответственно. Следующий фрагмент программы демонстрирует, как объектная переменная MyRange сначала устанавливается для ссылки на первое слово активного документа, а затем переопределяется и включает уже первые два слова:
Set MyRange = ActiveDocument.Words(1)
AnyRange.SetRange Start:=AnyRangeStart, _
End:= ActiveDocument.Words(2).End
Вместо переопределения диапазона напрямую вы можете расширить или уменьшить диапазон до заданного размера или «свернуть» его полностью.
Управление host-приложениями VBA
435
Метод MoveStart изменяет положение начального символа диапазона, в то время как метод MoveEnd изменяет положение конечного символа диапазона. Для увеличения или уменьшения области, на которую ссылается диапазон, вы можете перемещать конечную точку диапазона, используя методы MoveEnd или Move-Start при помощи следующих синтаксических форм:
СИНТАКСИС
Object.MoveEnd([Unit], [Count])
Object.MoveStart([Unit] , [Count])
В данном синтаксическом выражении Object — любая допустимая ссылка на объект Range. Как для метода MoveEnd, так и для метода MoveStart аргументы Unit и Count являются необязательными. Аргумент Unit задает элемент, для которого будет изменяться начало или конец диапазона. Unit может быть одной из констант wdUnits, перечисленных в таблице 16.1. Если вы опустите аргумент Unit, методы MoveStart и MoveEnd по умолчанию будут использовать wdCharacter.
Аргумент Count — число элементов (units), на которое должна быть сдвинута конечная точка. Если вы используете для аргумента Count положительное число, конечная точка перемещается в документе вперед, если вы используете для аргумента Count отрицательное число, конечная точка перемещается назад.
Ниже приведены операторы, демонстрирующие применение методов Move-Start и MoveEnd (AnyRange является объектной переменной, содержащей ссылку на объект Range):
AnyRange.MoveStart Unit:=wdParagraph, Count:= -1
AnyRange.MoveEnd Unit:=wdWord, Count:=-2
AnyRange.MoveEnd Count:=6
AnyRange.MoveStart Count:=8
Таблица 16.1. Встроенные константы wdUnits
Константа	Описание
wdCell	Ячейка таблицы.
wdCharacter	Символ, включая скрытые и непечатаемые символы.
wdColumn	Столбец таблицы.
wdLine	Строка текста. Вы можете использовать данную константу только для аргумента Unit, если используемый метод применяется к объекту Selection.
wdParagraph	Абзац. Абзац ограничивается символом конец абзаца (Ц). Символ конца абзаца не отображается на экране пока вы не щелкните кнопку Показать все символы (Show АП) панели инструментов Word.
wdRow	Строка таблицы.
wdSection	Раздел документа.
wdSentence	Предложение. Предложение ограничивается знаками пунктуации, такими как точка (.), знак вопроса (?), и восклицательный знак (!).
wdStory	Область документа.
436
Глава 16
Константа	Описание
wdTable	Таблица.
wdWord	Слово. Слово ограничено пробелами и символами пунктуации.
Иногда вам может понадобиться расширить диапазон о*г его текущего значения, до размеров, включающих следующий, больший по величине компонент документа, например, расширить диапазон курсора вставки, чтобы он включал слово, в котором находится курсор вставки.
Чтобы расширить диапазон, применяйте метод Expand в следующей синтаксической форме:
СИНТАКСИС
Object.Expand([Unit] )
Здесь Object — представляет любую допустимую ссылку на объект Range или Selection. Необязательный аргумент Unit определяет элемент, до которого расширяется диапазон, и может быть равен одной из констант WdUnits, перечисленных в таблице 16.1. Если вы опустите аргумент Unit, метод Expand использует по умолчанию значение константы wdWord.
Ниже представлен фрагмент кода, выделяющий десятое предложение документа и затем расширяющий диапазон для включения в него всего абзаца, в котором находится десятое предложение (MyRange — объектная переменная):
Set MyRange = ActiveDocument.Sentences(10)
MyRange.Expand Unit:=wdParagraph
Работа с объектом Selection
Для большинства действий, связанных с управлением текстом документа, вы, вероятно, остановитесь на объекте Selection. Используя объект Selection можно создать VBA-программу, выполняющую с курсором вставки любые операции, которые можно выполнить в Word интерактивно: добавить текст, переместить курсор вставки, выделить текст и другие.
Выполнить ссылку на объект Selection очень просто: необходимо только использовать свойство Selection объектов Application, Рапе или Window. В большинстве случаев используется свойство Application.Selection, чтобы получить ссылку на выделенный в данный момент фрагмент в активном документе.
Как уже упоминалось в этой главе ранее, в любой момент может быть активным только один объект Selection и в любом окне, отображающем документ, может находиться только один объект Selection. Это вполне очевидно, поскольку объект Selection, по существу, является курсором вставки, который отображается на экране при интерактивной работе в Word.
Вы можете связать объект Selection с любым диапазоном, используя метод Select объекта Range:
MyRange.Select
Данный оператор выделяет область документа, на которую ссылается объектная переменная MyRange. Объект Selection теперь также совпадает с диапазоном, на который ссылается MyRange.
Управление host-приложениями VBA
437
Как переместить или «свернуть» объекты Selection и Range
Вы уже знаете, как определить или переопределить диапазоны и как связать текущий выделенный фрагмент с конкретным диапазоном. Объекты Range и Selection имеют несколько методов, позволяющих перемещать диапазон или выделенный фрагмент. Чаще всего эти методы используются для перемещения объекта Selection перед добавлением й выделением текста. В действительности, существует пара методов, которые доступны исключительно в объекте Selection, они не имеют аналогов в объекте Range.
Чтобы поместить объект Selection в начале или в конце текущей строки текста, столбца таблицы, строки таблицы или области документа и при желании выделить данную строку текста, столбец или строку таблицы, или же область, можно использовать методы НотеКеу или EndKey в следующей синтаксической форме:
СИНТАКСИС
Object.НотеКеу([Unit] , [Extend])
Object.EndKey([Unit], [Extend])
В обоих случаях Object представляет собой допустимую ссылку на объект Selection. В зависимости от конкретного значения используемого аргумента метод НотеКеу оказывает на выделенный фрагмент такое же действие, как и нажатие клавиш Home, Shift+Home, Ctrl+Home или Ctrl+Shift+Home. Аналогично метод EndKey оказывает на выделенный фрагмент такое же действие, что и нажатие в различных комбинациях клавиши End.
Необязательный аргумент Unit задает элемент, в конце которого должен помещаться выделенный фрагмент (в конце строки, столбца и т.д.). Unit может быть значением одной из следующих констант wdUnits: wdStory, wdLine, wdColumn или wdRow. Если аргумент Unit опустить, то как НотеКеу, так и EndKey используют по умолчанию значение константы wdLine (в конце строки).
Необязательный аргумент Extend определяет, должен ли выделенный фрагмент быть расширен или должен ли курсор вставки быть перемещен. В качестве Extend можно использовать значение одной из встроенных констант wdMo-vementType: wdMove или wdExtend. Использование wdMove приведет к «сворачиванию» выделенного фрагмента до курсора вставки, после чего курсор вставки переместится на начало или конец заданного элемента документа, определяемого аргументом Unit. Использование wdExtend оказывает такое же действие, как нажатие на клавиши Ноте или End при удерживаемой нажатой клавише Shift. Использование wdExtend приведет к тому, что выделенный фрагмент будет расширен до конца заданного элемента. Если вы опустите аргумент Extend, в качестве значения по умолчанию будет использована константа wdMove.
В представленном ниже примере каждый из двух операторов использует один из только что описанных методов. Выполнение первого оператора «сворачивает» выделенный фрагмент до курсора вставки и затем перемещает курсор вставки в начало текущей строки. Выполнение второго оператора расширяет выделенный фрагмент до конца текущей строки.
Selection.НотеКеу
Selection.EndKey Extend:=wbExtend
Хотя объекты Range и Selection имеют много различных методов для выполнения перемещений, возможно, наиболее мощным из них является метод GoTo. Метод GoTo позволяет помещать объекты Range и Selection в любое место в пределах текущей области и перемещать Selection или Range по документу вперед или назад на заданное количество символов, слов или абзацев.
438
Глава 16
Для перемещения объектов Selection или Range используйте метод GoTo в следующей синтаксической форме:
СИНТАКСИС
Object.GoTo([What], [Which], [Count], [Name])
Здесь Object — любая допустимая ссылка на объекты Selection, Range или Document. Если Object ссылается на Selection, то метод GoTo возвращает объект Range, представляющий новое положение выделенного фрагмента после его «сворачивания» до курсора вставки и перемещения в позицию символа, расположенного непосредственно перед заданным положением. Если Object ссылается на Range или Document, метод GoTo просто возвращает объект Range, представляющий начальное положение для заданной области.
Все аргументы метода GoTo являются необязательными. Аргумент What задает тип элемента, в который должен быть перемещен выделенный фрагмент, и может быть любой из встроенных констант wdGoToItem. В таблице 16.2 перечислены некоторые из констант wdGoToItem. Для того чтобы просмотреть полный список констант, доступных в классе wdGoToItem, используйте Object Browser.
Аргумент Which указывает, в какой элемент должен быть перемещен выделенный фрагмент. Which может быть равен любой из встроенных констант класса WdGoToDirection: wdGoToAbsolute, wdGoToFirst, wdGoToLast, wdGoToNext, wdGoToPrevious, wdGoToRelative.
Аргумент Count задает число элементов документа, на которое должен быть перемещен выделенный фрагмент. По умолчанию значение аргумента Count равно 1. Использование аргумента Count подразумевает использование аргумента What, указывающего, куда необходимо выполнить перемещение, и аргумента Which, задающего, какой тип перемещения необходимо выполнить. Последний аргумент Name определяет имя области, в которую должен быть перемещен выделенный фрагмент. Вы можете использовать аргумент Name только в том случае, если аргумент What также используется и равен при этом значению одной из следующих констант: wdGoToBookmark, wdGoToCom-ment, wdGoToField или wdGoToObject.
' В результате выполнения приведенного ниже оператора выделенный фрагмент перемещается на следующую страницу:
Selection.GoTo What:=wgGoToPage
Результатом выполнения следующего оператора будет перемещение выделенного фрагмента на последнюю страницу документа:
Selection.GoTo What:=wgGoToPage, Which:=wdGoToLast
В результате выполнения приведенного ниже оператора выделенный фрагмент перемещается на две строки вниз относительно текущего местоположения:
Selection.GoTo What:=wgGoToLine, Which:=wdGoToNext, Count:=2
Таблица 16.2. Встроенные константы WdGoToItem
Константа	Описание
wdGoToBookmark	Закладка.
wdGoToField	Поле, например поле даты или номера страницы.
wdGoToHeading	Заголовок, то есть текст отформатированный с помощью одного из стилей заголовка: Заголовок!, Заголовок2 и так далее.
Управление host-приложениями VBA
439
Константа	Описание
wdGoToLine	Строка документа.
wdGoToPage	Страница документа.
wdGoToPercent	Местоположение в документе, выраженное в процентах от длины документа.
В дополнение к изменению положения выделенного фрагмента вы можете «свернуть» выделенный фрагмент (или диапазон) до курсора вставки. Для этого используйте метод Collapse в следующей синтаксической форме:
СИНТАКСИС
Object.Collapse([Direction])
Здесь Object — любая допустимая ссылка на объекты Selection или Range. Необязательный аргумент Direction задает направление, в котором диапазон или выделенный фрагмент должны быть «свернуты». Он может быть равен одной из констант класса WdCollapseDirection: wdCollapseEnd или wdCollapseS-tart. По умолчанию используется значение константы wdCollapseStart.
Следующие операторы демонстрируют применение метода Collapse:
ActiveDocument.Paragraphs(3).Range.Select
Selection.Collapse Direction:=wdCollapseEnd
Первый оператор выделяет третий абзац активного документа. Второй оператор «сворачивает» выделенный фрагмент до курсора вставки, помещенного в конец предыдущего выделенного фрагмента.
Добавление текста	(
Основным назначением программ подготовки текста является хранение и обработка текста. Одной из основных задач, выполняемых вами при интерактивной работе с Word, является ввод текста в документ. Точно также, одна из наиболее распространенных задач, которую вам придется выполнять под управлением I VBA-кода, будет заключаться в том, чтобы добавлять текст. Объекты Selection и Range имеют несколько методов, предоставляющих возможность добавлять текст. В первую очередь рассмотрим методы добавления текста объекта Selection, поскольку вам чаще всего придется иметь дело именно с этим объектом.
Простейший способ добавить текст в документ состоит в использовании метода TypeText объекта Selection, сделать это можно при помощи следующей синтаксической конструкции:
СИНТАКСИС
Object.TypeText([Text])
Object — любая ссылка на объект Selection. Аргумент Text является обязательным, он может быть любым строковым выражением, и это — именно тот текст, который добавляется в документ. Метод TypeText помещает текст в то место, где расположен курсор вставки, как если бы вы ввели его с клавиатуры. Если Selection содержит диапазон и свойство ReplaceSelection равно значению True, то добавляемый текст заменяет выделенный фрагмент. В противном случае текст помещается перед курсором вставки объекта Selection. При установке Word свойство ReplaceSelection по умолчанию задается равным значению True.
440
Глава 16
Свойство ReplaceSelection соответствует флажку заменять выделенный фрагмент (Typing Replace Selection) на вкладке Правка диалогового Word-окна Параметры), которое можно открыть при помощи команды Сервис | Параметры. Можно также задать это свойство при помощи объекта Options.
Если метод TypeText добавляет текст так, как будто вы ввели его с клавиатуры, то, очевидно, что объекту Selection необходим метод, эквивалентный нажатию клавиши Enter, для того, чтобы можно было добавлять новый абзац. Этот метод так и называется TypeParagraph. Синтаксическая конструкция этого метода выглядит следующим образом:
СИНТАКСИС
Object.TypeParagraph
Object — ссылка на объект Selection. Метод TypeParagraph помещает в документ новый абзац аналогично тому, как это происходит при нажатии на клавишу Enter. Если объект Selection — диапазон, содержание диапазона заменяется новым абзацем. Если Selection — курсор вставки, добавляется новый абзац, а курсор вставки перемещается в документе вперед.
Чтобы случайно не заменить выделенный фрагмент, используйте метод Collapse для «сворачивания» выделенного фрагмента в курсор вставки.
Возможно, вам понадобится добавлять текст в диапазон, который не является выделенным. В этом случае следует использовать методы InsertAfter, InsertBefo-re, InsertParagraphAfter и InsertParagraphBefore. Все эти методы применимы как к объектам Selection, так и к объектам Range.
Для добавления текста в начало или конец диапазона используйте методы InsertBefore или InsertAfter со следующим синтаксисом:
СИНТАКСИС
Object. InsertBefore(Text)
Object. InsertAfter(Text)
Здесь Object — ссылка или на объект Selection, или на объект Range. Text — строковое выражение для текста, который необходимо добавить. Аргумент Text обязателен для каждого из методов. Заданный текст помещается в диапазон, и диапазон расширяется, включая в себя добавленный текст. Оправдывая свое имя, метод InsertBefore помещает текст в начало диапазона или выделенного фрагмента, a InsertAfter помещает текст соответственно в конец диапазона или выделенного фрагмента.
Применение метода InsertAfter имеет некоторые особенности, требующие дополнительных пояснений. Если выделенный фрагмент или диапазон включает целый абзац, метод InsertAfter вставляет текст как новый абзац. Так происходит потому, что выделенный фрагмент, включающий целый абзац, также включает и символ конца абзаца. Чтобы вставить текст в конец абзаца, необходимо или «свернуть» диапазон до курсора вставки в позиции перед символом конца абзаца, или таким образом изменить конечную точку диапазона, чтобы он содержал на один символ меньше.
Для всех методов, добавляющих текст - TypeText, InsertAfter и InsertBefore, -можно использовать функцию Chr и встроенные константы VBA (vbCr, vbLf, vbCrLf, vbTab) как часть строки аргумента Text для добавления символов, которые нельзя набрать на клавиатуре, или символов, которые имеют в VBA специальное значение (например, кавычки).
Управление host-приложениями VBA
441
Так же, как метод TypeText имеет сопутствующий ему метод TypeParagraph, который можно использовать для добавления нового абзаца, методы InsertBefore и InsertAfter имеют сопутствующие методы для добавления нового абзаца перед областью или после области, на которую ссылается определенный диапазон.
СИНТАКСИС
Object.InsertParagraphBefore
Object.InsertParagraphAfter
В каждой синтаксической конструкции Object — ссылка на объект Selection или на объект Range. Метод InsertParagraphBefore добавляет символ конца абзаца перед диапазоном или выделенным фрагментом, в то время как метод InsertParagraphAfter добавляет символ конца абзаца в конец диапазона или выделенного фрагмента. Ни тот, ни другой метод не имеют аргументов. Как и в случае с другими методами Insert..., диапазон или выделенный фрагмент расширяется для включения добавленного символа конца абзаца.
Листинг 16.27 демонстрирует использование методов InsertBefore, Insert-After и InsertParagraphAfter.
Листинг 16.27. Применение методов InsertAfter, InsertBefore, InsertParagraphAfter
1	Sub InsertDocumentlnformation()
2	' Помещает в начало документа два абзаца
3	' Первый абзац содержит имя файла, в котором хранится документ
4	' Второй абзац содержит имя файла-шаблона документа
5
6	Dim aRange As Range
7
8	Set aRange = ActiveDocument.Range(Start:=0, End:=0)
9
10	With aRange
11	.InsertBefore ТехГ:="Имя файла документа: " & _
12	ActiveDocument.FullName
13	' .InsertParagraphAfter
14	,	.InsertAfter Text:="Присоединенный к документу шаблон: " &
15	ActiveDocument.AttachedTemplate.FullName
16	.InsertParagraphAfter
17	End With
18
19	End Sub
Как вырезать, скопировать, вставить и удалить текст
Вам обязательно понадобится не только вводить, но и вырезать, копировать, вставлять или удалять текст в документе. Для выполнения этих задач, как объекты Selection, так и объекты Range имеют соответствующие методы.
Чтобы вырезать, скопировать или вставить выделенный фрагмент в или из буфера обмена Windows, можно использовать один из следующих методов:
СИНТАКСИС
Object.Cut
Object.Copy
Object.Paste
Для каждого из этих методов Object — любая ссылка на объект Selection или Range. При использовании метода Cut содержимое диапазона или выделенно
442
Глава 16
го фрагмента вырезается из документа и помещается в буфер обмена Windows. Объекты Selection или Range остаются в документе, «сворачиваясь» до курсора вставки. Метод Сору копирует содержимое диапазона или выделенного фрагмента в буфер обмена Windows. Объекты Selection или Range при этом не изменяются.
Метод Paste вставляет содержимое буфера обмена Windows в заданный диапазон или выделенный фрагмент. Если диапазон или выделенный фрагмент не является курсором вставки, то текст, вставляемый из буфера обмена, заменяет содержимое заданного диапазона или выделенного фрагмента. Когда вы используете метод Paste с объектом Range, диапазон расширяется, включая в себя содержимое вставленного из буфера обмена текста. При использовании же метода Paste с объектом Selection выделенный фрагмент располагается после вставленного из буфера обмена текста; выделенный фрагмент не расширяется.
Листинг 16.28 содержит процедуру, которая при помощи методов Cut и Paste объекта Selection меняет местами два абзаца документа. Код листинга 16.29 при помощи методов Cut и Paste объекта Range меняет местами два слова в документе.
Листинг 16.28. Использование методов Cut и Paste совместно с объектом Selection
1	Sub TransposeParagrahs()
2	' Меняет местами текущий абзац и абзац, следующий за ним.
3	' Используется объект Selection.
4
5	With Selection
б	.Expand Unit:=wdParagraph
7	.Cut
8	.Move Unit:=wdParagraph
9	.Paste .
10	End With
11
12	End Sub
	Листинг 16.29. Использование Cut и Paste совместно с объектом Range
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16	Sub Transposewords() ' Меняет местами слово, на которое помещен курсор вставки, ' и слово, следующее за ним Dim MyRange As Range If Selection.Type <> wdSelectionIP Then Exit Sub Set MyRange = Selection.Range With MyRange .Expand Unit:=wdWord . Cut .Move Unit:=wdWord .Paste End With	' End Sub
Для удаления из документа текста используйте метод Delete. Синтаксическая конструкция для его использования следующая:
Управление host-приложениями VBA
443
СИНТАКСИС
Object.Delete([Unit] , [Count])
Object — любая ссылка на объекты Selection или Range. Оба аргумента Unit и Count являются необязательными. Аргумент Unit может быть равен значению wdCharacter или wdWord. По умолчанию значение Unit равно wdCharac-ter. Аргумент Count задает количество символов или слов (в зависимости от значения аргумента Unit), которые должны быть удалены. Если объекты Range или Selection ссылаются на диапазон текста, метод Delete удаляет содержимое данного диапазона.
Для удаления заданного числа символов или слов до или после диапазона или выделенного фрагмента сначала его необходимо «свернуть» до курсора вставки. Для того чтобы удалить элементы текста после курсора вставки, следует использовать в качестве аргумента Count положительное число, а чтобы удалить элементы текста до курсора вставки, — отрицательное.
Если вы используете метод Delete как функцию, она возвращает значение, указывающее число удаленных элементов текста, или — 0, если операция удаления не удалась.
Глава 17
Работа с другими приложениями: Automation
В этой и следующих главах показано, как Visual Basic for Applications может управлять и работать с другим приложением, не являющимся текущим host-приложением VBA. Например, вы можете управлять операциями Excel из VBA Word или операциями Word из VBA Excel. Точно так же вы можете использовать VBA Excel или Word для управления такими приложениями, как Microsoft Access, и любыми другими приложениями, которые поддерживают OLE или Automation.
Что такое OLE?
/
Прежде чем вы узнаете, как Visual Basic for Applications работает с объектами Automation и OLE, вам нужно понимать, что такое Automation и что такое OLE.
Краткая история OLE
OLE версии 2.1 (аббревиатура Objects Linking and Embedding — связывание и внедрение объектов) — это одна из попыток компании Microsoft дать пользователям возможность создавать действительно составные документы (compound documents). Составной документ — это любой файл, который содержит данные более чем одного приложения. Например, вы можете создать рабочий лист в Excel, который в дополнение к своим собственным числам и формулам будет содержать документ Word или рисунок из графической программы; такой рабочий лист является составным документом. Другим примером составного документа может служить документ Word, который содержит диаграммы Excel. Как вы увидите, OLE 2.1 существенно упрощает взаимодействие приложений.
В ранних версиях Microsoft Windows вы могли передавать данные из приложения в приложение только через буфер обмена. Вы копировали данные из одной программы в буфер обмена, а затем вставляли их из буфера обмена в другое приложение. Если вам нужно было внести изменения в данные, вы должны были открыть оригинальное приложение, открыть соответствующий файл, ввести изменения, а затем повторить весь процесс копирования и вставки.
Хотя способ передачи информации через буфер обмена лучше, чем отсутствие всякого способа, это не самое эффективное решение задачи. Чтобы уменьшить количество шагов, требуемых для обновления и передачи информации между двумя различными приложениями, Microsoft предложила такое решение, как динамический обмен данными (Dynamic Data Exchange — DDE). При использовании DDE вы по-прежнему должны создать данные в одном приложении (сервере), а затем скопировать их в буфер обмена. Однако приложение, которое поддерживает DDE (клиент), позволяет использовать команду Paste Link (вставить связь) вместо обычной команды Paste (вставить) для вставки данных из буфера обмена. Команда Paste Link устанавливает коммуникационную связь между двумя приложениями. Такая коммуникационная связь имеет два преимущества:
Работа с другими приложениями: Automation
445
1. Если оба приложения выполняются в одно и то же время и данные, созданные приложением-сервером, изменяются, то документ приложения-клиента обновляется автоматически.
2. Если вы редактируете связанные данные в приложении-сервере, а приложение-клиент в это время закрыто, связанные данные автоматически обновляются и в приложении-клиенте. Это происходит, когда вы открываете в приложении-клиенте файл, содержащий связанные данные, или когда вы явно используете команду Update (Обновить) в приложении-клиенте.
Не путайте термины.....и......... Клиент — это всегда приложение, которое по-
лучает данные; сервер — это всегда приложение, которое поставляет данные.
Динамический обмен данными — это значительное улучшение первоначальной методики копирования-вставки, но эта технология все еще имеет некоторые недостатки. Во-первых, данные, вставляемые из буфера обмена, независимо от того, вставляются ли они обычным образом или как DDE-связь, просто вставляются в приложение-клиент, практически, без какого-либо форматирования. Во-вторых, редактирование данных может быть трудной процедурой. Чтобы внести изменения в данные, связанные по технологии DDE, вы должны перейти в приложение-сервер для связанных данных (или запустить приложение-сервер). Ситуация остается, по меньшей мере, немного неудобной. Но особые трудности возникают в тех случаях, когда вы не уверены в том, какое приложение является сервером для данных, связанных через DDE, или вы просто не можете вспомнить, какой документ сервера содержит исходные данные.
Чтобы обойти эти проблемы, Microsoft приняла новый подход к совместному использованию данных: связывание и внедрение объектов (Object Linking and Embedding — OLE). В технологии OLE данные, вставляемые из приложения-сервера, появляются в документе-клиенте как объекты. Каждый объект может вставляться одним из двух способов: как связанный, (linked) или как внедренный (embedded). Оба типа OLE-объектов сохраняют имя сервера OLE, а также любую информацию, в которой нуждается сервер. Эти два типа OLE-объектов имеют следующие возможности:
1. Связанные объекты: Объект содержит образ данных сервера и поддерживает связь между клиентом и сервером во многом аналогично технологии DDE. Оригинальные данные остаются в отдельном файле, находящемся под управлением приложения-сервера. Если данные изменяются, то эта связь гарантирует, что объект-клиент будет автоматически модифицироваться. Как правило, следует связывать объекты в тех случаях, когда другим приложениям может потребоваться доступ к тому же самому файлу данных.
2. Внедренные объекты: Объект содержит автономную версию данных сервера. По существу, это — копия данных сервера. Между сервером и клиентом не устанавливается никакой связи, поскольку в этом нет необходимости. Объект-клиент содержит не только данные, но также и всю основную информацию, связанную с приложением-сервером: имя приложения, структуру файла, коды форматирования и т.д. Как правило, вы должны внедрять объекты в тех случаях, когда планируете работать с данными только под управлением приложения-клиента.
Другое преимущество OLE состоит в том, что часто вам не нужен документ сервера. Вы можете создать данные, запустив приложение-сервер из приложения-клиента, а затем вставить эти данные в документ-клиент как внедренный объект. Это означает, например, что вы могли бы вставить пустой документ Word в рабочий лист Excel как внедренный OLE-объект, а затем напечатать письмо, записку, замечание т.д.
446
Глава 17
Связываете вы или внедряете данные, OLE-объект сохраняет первоначальное форматирование данных. Это означает, что OLE-объекты появляются в документе-клиенте точно такими же, как в приложении-сервере. OLE-объект сохраняет имя своего приложения-сервера, и, если OLE-объект связан, в нем также сохраняется имя файла сервера, из которого исходил этот объект. Таким образом, вам никогда не требуется знать, какое приложение и какой файл являются источником внедренных данных. Вы просто выполняете двойной щелчок на объекте, а механизм OLE загружает приложение-сервер и в случае необходимости открывает нужный исходный файл данных.
OLE 2.1 имеет следующие преимущества:
1.	Обмен данными по технологии «перенести-положить» (drag-and-drop). Вы можете легко передавать информацию между двумя открытыми приложениями, поддерживающими OLE 2.1, буксируя мышью выбранные данные из одного приложения в другое. Если вы хотите скопировать данные, то при буксировке удерживайте нажатой клавишу Ctrl.
2.	Вставка «по месту» (in-place inserting). Если вы вставляете объект OLE 2.1, находясь в приложении-клиенте, то клиент активизирует вставку «по месту». В этом состоянии некоторые возможности окна клиента, например панели инструментов и команды меню, временно заменяются возможностями OLE-сервера; приложение-сервер не отображается в отдельном окне. Другими словами, документ остается тем же самым, а изменяется окружающее приложение.
3.	Редактирование «по месту» (in-place editing). Когда вы выполняете двойной щелчок на объекте OLE 2.1, чтобы его отредактировать, этот объект остается в документе, а окно клиента изменяется точно так же, как и в случае со вставкой «по месту».
4.	Automation. Для VBA-программиста наиболее захватывающей возможностью OLE 2.1 является Automation. (Automation была известна в OLE 2.0 как OLE-Automation; по существу, OLE-Automation и Automation — одно и то же.) По технологии Automation объекты приложений (такие как Workbook, Worksheet, Document, Paragraph и т.д.) становятся видимыми для других приложений, поддерживающих Automation. В частности, видимые объекты приложения доступны для VBA, и вы можете написать VBA-процедуры в одном приложении, которые управляют объектами другого приложения. Например, процедура VBA в Excel может использовать Automation для управления объектами другого приложения OLE 2.1, такого как Microsoft Word, Microsoft Access. Любое приложение, которое поддерживает Automation, делает видимыми часть или все свои объекты, независимо от того, поддерживает оно VBA или нет. Это означает, что вы можете использовать свою VBA-программу для управления объектами приложений, которые не имеют VBA, но могут функционировать как сервер Automation или OLE.
Работа Visual Basic for Applications с технологией OLE
Компания Microsoft разрабатывала Visual Basic for Applications, ориентируясь на OLE: многие из объектов, с которыми вы работаете в VBA, являются также объектами Automation [их называют компонентами (components) Automation]. В частности, host-приложение обычно предоставляет в ваше распоряжение специальные объекты и коллекции объектов, посредством которых вы можете обращаться к OLE-возможностям других приложений. Эти объекты и их соответствующие коллекции имеют много свойств и методов, которые позволяют создавать свя-‘тнны! или внедренные данные и работать с ними.
Кроме того, VBA может йспользовать объекты других приложений, которые поддерживают Automation. Это означает, например, что процедура VBA в Excel мо
Работа с другими приложениями: Automation
447
жет обращаться к объектам и манипулировать объектами, которые созданы другим приложением, поддерживающим Automation. Причем происходит это таким образом, как если бы процедура VBA работала непосредственно в данном приложении.
Поиск типа класса объекта
В главе 7 вы узнали, что объекты host-приложения VBA разделены на различные классы. Объекты, которые приложение делает доступными для OLE и Automation-компонентов, также делятся на различные классы.
Прежде чем вы сможете вызывать или использовать OLE-объект или Automation-компонент в своем VBA-коде, необходимо определить его класс. Указывая класс объекта, вы даете VBA информацию, которая нужна для поиска определения объекта и для выполнения методов объекта. Для того чтобы указать тип класса объекта — также называемого программным идентификатором (programmatic ID) — вы должны сначала узнать этот тип.
Класс OLE-объекта или Automation-компонента однозначно указывает на характер объекта, которым может быть рабочий лист Excel, документ Word, база данных Access и т.д. Каждый класс имеет уникальное имя и код идентификатора, которые назначаются конкретному OLE-объекту или объекту Automation данного класса. Windows использует тип класса, чтобы определить, какое приложение является сервером для конкретного связанного или внедренного OLE-объекта.
Windows поддерживает базу данных реестра (Registry data base), которая содержит, среди прочего, информацию о приложениях, установленных на вашей системе, включая специфическую информацию о «видимых» Automation-компонентах и OLE-объектах приложений. Один из секретов функционирования технологии OLE и Automation состоит в том, что реестр Windows содержит имена всех классов объектов, «видимые» различными приложениями или библиотеками, и «следит» за тем, какие исполняемые файлы обеспечивают ресурсы для этих объектных классов. Когда вашему VBA-приложению нужны «услуги» компонента Automation, VBA «просит» операционную систему Windows выполнить соответствующий код для этого объекта; Windows делает это, основываясь на типе класса объекта.
Чтобы узнать значение программного идентификатора любого Automation-компонента или OLE-объекта, доступного на вашей компьютерной системе, вы можете найти тип класса этого объекта в базе данных реестра Windows. Альтернативный способ получить ту же информацию — запустить программу Microsoft System Information. Далее рассматриваются вопросы использования той и другой методики для поиска типа класса объекта.
Использование реестра Windows
База данных реестра Windows (или просто реестр) содержит полную информацию об аппаратных средствах вашей системы и конфигурации программного обеспечения. Для просмотра содержания реестра следует запустить редактор реестра (Registry Editor). (Редактор реестра обычно устанавливается в каталог Windows, но в меню Start (Пуск) Windows нет ярлыка этой программы.) Чтобы запустить редактор реестра, выполните следующие шаги:
1. В меню Start (Пуск) Windows выберите команду Run (Выполнить).
2. В окне редактирования Open (Открыть) напечатайте Regedit.exe и выберите ОК (рис. 17.1). Windows запустит редактор реестра, который выведет окно, показанное на рис. 17.2. Конечно, вид древовидной диаграммы зависит от конфигурации системы и может отличаться от того, который показан на этом рисунке.
«
448
Глава 17
Рис. 17.1
В окне редактирования Open (Открыть) напечатайте Regedit.exe и выберите ОК (рис 17 1) Windows запустит редактор реестра
О Type the name of a program, folder, document, or Internet resource, and Windows will open it for you
 »	,л|
OK J | Cancel | j Browse
Левая панель окна редактора реестра отображает древовидную диаграмму, отражающую содержание реестра, а правая панель — конкретные данные, содержащиеся в выбранном элементе. Многие ветви дерева реестра содержат в столбце Data (данные) в правой панели окна редактора реестра текст value not set (значение не присвоено), что и показано на рис. 17.2 для ветви HKEY_CLASSES_ROOT. Это не означает, что в данную ветвь не введено никаких данных: просто выбранная ветвь дерева ведет к дополнительным ответвлениям или элементам реестра.
Рис. 17.2
Окно редактора реестра содержит древовидную диаграмму, которая сводит вместе данные о программном обеспечении
и аппаратных средствах вашего компьютера
Поиск объектного класса в реестре
Реестр хранит информацию об OLE-объектах в ветви HKEY_CLASSES_ROOT, которая выбрана на рис. 17.2. Чтобы просмотреть зарегистрированные на вашей системе классы OLE-объектов и объектов Automation, выполните следующие шаги: 1. Щелкните в древовидной диаграмме небольшой квадрат, расположенный слева от ветви HKEY_CLASSES_ROOT, чтобы развернуть эту ветвь. Редактор реестра теперь отображает список всех зарегистрированных типов файлов и OLE-объектов. (Этот список обычно очень длинный.)
2. Прокручивайте древовидную диаграмму в левой панели окна редактора реестра до тех пор, пока не найдете имена зарегистрированных классов OLE-объектов. (Поскольку этот список содержит много различных расширений файлов, которые расположены в алфавитном порядке перед большинством имен классов OLE-объектов, вам нужно прокручивать список достаточно долго, прежде чем вы дойдете до имен классов OLE-объектов.)	• *
Работа с другими приложениями: Automation
449
Вы можете распознать типы классов OLE-объектов в реестре по тому признаку, что они обычно начинаются с имени приложения-сервера. На рис. 17.3 показана развернутая ветвь реестра HKEY_CLASSES_ROOT, прокрученная до точки, где в списке появляются OLE-объекты и Automation-компоненты Excel. На рис. 17.3 выбран объектный класс Excel.application. 10, который представляет непосредственно приложение Excel.
Обратите внимание, что данные, показанные в правой панели окна редактора реестра на рис. 17.3, указывают имя выбранного объектного класса — Приложение Microsoft Excel. Обратите также внимание на то, что в левой панели окна редактора реестра можно видеть и другие OLE-объекты и Automation-компоненты Excel: Excel.Addin, Excel.Chart, Excel.Sheet и т.д. Каждый из этих элементов является именем OLE- или Automation-объекта, и именно это имя вы должны использовать, указывая тип класса объекта.
& Registry Editor
£dt View Favorites йф
* z I Eventsystem Eventsystem Л Name
$ ,_I EventSystem Eventsystem 1 ^(Default)
Zj Excel Addn
t Zj Excel Appteaoon
Type	Data
REG_SZ	Приложение Microsoft Excel
|E. M Appt
л	ZJ Excel Backup
*	Z3 Excel Chart
i	| Excel Chart 5	'
*	*	Excel	Charts	»
л	I Excel CSV	s
t	 < Excel Dialog
г	Excel DIF	1
*	Zj Excel Macrosheet	J
*	t Excel Sheet	।
♦	ZJ Excel Sheet 5
t	ZJ Excel Sheet 8
* Zj Excel SLK	v
€ > <
My ComputerM-KEY CLASSES ROOT^xcel Appbcadoo 10
Рис. 17.3. Ветвь реестра HKEY_CLASSES_ROOT содержит зарегистрированные на вашей системе классы OLE-объектов
После того как вы найдете в реестре нужный объектный класс, запишите его имя для будущих ссылок. В таблице 17.1 приведен список типов классов для нескольких, часто используемых объектов.
Таблица 17.1. Типы классов для часто используемых объектов
Объект	Тип класса
1-2-3 Worksheet	123Worksheet
Приложение Microsoft Access	Access. Application. 10
Приложение Microsoft Excel	Excel. Application.10
Диаграмма Microsoft Excel	Excel.Chart
Лист Microsoft Excel	Excel.Sheet
Приложение Microsoft Graph	MSGraph. Application
Приложение MS PowerPoint	PowerPoint. Application
15 Программирование на VBA 2002
450
Глава 17
Объект	Тип класса
Приложение Microsoft Word	W ord. Application. 10
Документ Microsoft Word	W ord.Document
Использование программы System Information
Другой способ получить информацию об OLE-объектах и Automation-компонентах, установленных на вашей компьютерной системе, состоит в том, чтобы использовать апплет (applet) System Information (Сведения о системе), который поставляется вместе с Microsoft Office.
Вы можете получить доступ к апплету System Information двумя способами:
1. Посредством команды Справка | О программе (Help | About), доступной в любом приложении пакета Microsoft Office.
2. Запустив программу Msinfo32.exe, хранящуюся в папке C:\Program Files\Com-mon Files\Microsoft Shared\MSInfo на ващем жестком диске.
Чтобы запустить апплет System Information командой Справка | О программе (Help | About), выполните следующие шаги:
1. В любом из приложений Microsoft Office (например, Word иди Excel) выберите в меню команду Справка | О программе (Help | About). Приложение выведет диалог О программе <имя приложения* (About), который показывает имя приложения, версию и информацию об авторских правах на данную программу ' (рис. 17.4). Конкретный вид диалога О программе <имя приложения* немного отличается от приложения к приложению, но в каждом из них есть кнопки ОК, О системе (System Info) и Поддержка... (Tech Support).
Рис. 17.4
Из этого окна можно запустить апплет System Information
О программе Microsoft Word
Microsoft® word 2002 (10 2627 2625)
© Корпорация Майкрософт (Microsoft Corporation), 1983 2001 Все права защищены
ОРФО ® Промрка «рфогррфии © Информатик А О 1990 2000 В« прав* 1*цищани ОРФО ® Ркст*ю»к» переносе» © Информатик А О , 1992 2000 Вс» права хшицвни ОРФО ® Тенурус © Информатик А О 1992 2000 Все пр*»* хащищаны ОРФО ® Гр«мм*тич«к*я и стилистическая проеерк* ©Информатик А О 1990 1997 Все пр*»* хашишены Portions of International CorrectSpel’* spelling correction system © 1993 by Lemout & Hauspi* Speech Products NV All nghts r»s*tv«d English th»s»utus content developed For Microsoft by Bloomsbury Publishing Pk The American Heritage® Dictionary of the English Language Third Edition Copyright © 1992 Houghton Mifflin Company Electronic version licensed from Lemout В Hauspie Speech Products N V All rights reserved РУТА"" Переефк» уч>а1нсмЫ орфосрафп ©Пролит Лтд 1997 2000 Уо прав* 1»ги«ено РУГА** Переноси » уфаьгемоп словах ©Пролит Лтд., 1997 2000 Va права авхищено РУТА*' Ttiaypyc yrpaiHcanti мо»и ©Прол1нгЛтд 1999 2000 Ус1 прав» хашиаеио Неиоторем иаблоны рахработанм для корпорации Майкрософт компанией Impress* Systems Санта Роха, Калифорния Сравнение версий ©Advanced Software Inc ,1993 2000 Все права зациценч
Правом использования этой копии продукта обладает
Владимир Кузьменко
i Home computer
s Номер продукта 54521 750 6140064-17694
Внимание! Данная программа защищена законами об авторских правах и международными соглашениями Незаконное воспроизведение или распространение данной программы или любой ее части влечет гражданскую и уголовную ответственность
О системе
Поддержка
О1кп объекты j
2. В диалоге О программе <имя приложения* щелкните кнопку О системе. Приложение запустит апплет System Information, который выведет окно, аналогичное показанному на рис. 17.5.
Если вы хотите использовать апплет System Information вне Microsoft Office, можете запустить его непосредственно из Windows, выполнив следующие шаги:
Работа с другими приложениями: Automation
451
1. В меню Start (Пуск) Windows выберите команду Run (Выполнить).
2. Напечатайте в окне редактирования Open (Открыть) текст "C:\Program Files\ Common Files\Microsoft Shared\MSInfor\Msinfo32.exe" (предполагается, что компоненты Microsoft Office и Windows были установлены в папки, выбираемые по умолчанию) и щелкните кнопку OK. Windows запустит апплет System Information, который выведет окно, аналогичное показанному на рис. 17.5.
Рис. 17.5
Апплет System
Information позволяет просматривать список установленных OLE-объектов
О System Information
File Edit View loots tjelp
♦	Hardware Resources
♦	Components - Software Environment System Drivers Signed Drivers Environment Vanablt Print Jobs
Network Connections Running Tasks Loaded Modules Services Program Groups Startup Programs
Windows Error Repo * Internet Settings
Object
Windows Media Player 7
Windows Media Services DRM Stor WordPad Document
Диаграмма Microsoft Excel BnarpaMMaMicrosoft Excel Диаграмма Miao soft Excel Диаграмма Microsoft Graph Документ Microsoft Word Документ Microsoft Word 6 0-70 Лист Microsoft Excel Лист Microsoft Excel Макрос Microsoft Excel 4 0 Презентация Microsoft PowerPoint Рисунок Microsoft Word Рисунок Microsoft Word 6 0-70 Слайд Microsoft PowerPoint
Local Server	**
Not Available
Not Available
*%programfilesH\window$ nt\accessories' Not Available
8\progra~1Vnicros'’,2\oftice1C\excel exe Not Available
еДргод'аГ 1\micros~2\oflice10\graph exe e\progra~1\micros~2\oftice1C\winword ex>
Not Available
Not Available
e\progra~’Vnicros*“2\oftice1C\exce1 exe Not Available
e \progra~1 \micros'“2\offtce10\powerpnt e e\progra~1\micros~2\ofticelC\winword exi Not Available
e\progra~1\miaos~2\office10\powerpnte v

И
Find what s
П Search selected category only	О Search category names only
Апплет System Information отображает в левой панели окна древовидную диаграмму с определенной частью информации о конфигурации вашей системы. Правая панель окна System Information отображает специфическую информацию для категории, выбранной в левой панели. Щелчком на небольшом квадрате, расположенном с левой стороны от ветви, вы можете развернуть или свернуть ветвь «дерева».
На рис. 17.5 правая панель окна отображает список всех OLE-объектов, которые установлены в базу данных реестра вашей системы. Информация в окне System Information не настолько полна, как та, которую вы можете получить из базы данных реестра, но апплет System Information намного проще в использовании и работать с ним безопаснее с точки зрения возможных повреждений системы, чем при работе с редактором реестра. Для многих целей быстрее и проще найти тип класса объекта с помощью апплета System Information, чем использовать базу данных реестра.
Добавление связанных и внедренных объектов
Технология OLE существенно расширяет ваши возможности при разработке VBA-приложения. Цена, которую платят «конечные» пользователи за эту технологию — дополнительная сложность приложения. Это особенно верно по отношению к неопытным пользователям, которые чувствуют себя не очень уверенно, имея в своем распоряжении большой набор различных возможностей, предоставляемых типовой операцией OLE. Например, если вы скопировали данные из приложения-сервера OLE, команда Paste Special (Специальная вставка) в приложении-клиенте дает вам целый ряд возможностей: вы можете вставить информацию как объект, как изображение или текст (в зависимости от данных); вы можете вставить данные как связанные или несвязанные; вы можете вставить данные в виде значка или в режиме полного просмотра.
Чтобы упростить «жизнь» пользователям вашей программы, вы можете написать процедуры VBA для управления объектами OLE, поскольку VBA позволяет
15’
452
Глава 17
контролировать каждую из приведенных выше возможностей на процедурном уровне. Например, вы можете предоставить вашим пользователям одиночную команду или кнопку в панели инструментов, которая создает определенный объект OLE, но скрывает все детали и варианты выбора, возникающие при его создании. В следующих разделах показано, как создавать объекты OLE в VBA.
Объекты Shape и OLEFormat
В главе 10 описывалась модель объектов слоя векторной графики в Microsoft Word, Microsoft Excel и Microsoft PowerPoint. В этой главе рассматриваются свойства и методы, предназначенные для управления OLE-объектами, находящимися в коллекции Shapes.
Каждый объект Shape имеет свойство OLEFormat, которое возвращает объект OLEFormat. Объект OLEFormat содержит информацию о характеристиках OLE-объекта Shape. Определенные свойства и методы объекта OLEFormat изменяются в зависимости от того, работаете ли вы в Word, Excel или PowerPoint. Как и объект Shape, объекты OLEFormat в Word, Excel и PowerPoint имеют одинаковые свойства. Например, объекты OLEFormat имеют свойство Progid, которое сохраняет программный идентификатор конкретного OLE-объекта.
Следующие несколько разделов этой главы объясняют, как добавлять OLE-объекты из различных источников в коллекцию Shapes.
Использование метода AddOLEObject коллекции Shapes
Чтобы добавить связанный или внедренный OLE-объект в коллекцию Shapes Word, Excel или PowerPoint, следует использовать метод AddOLEObject. Метод AddOLEObject использует немного различные наборы аргументов в зависимости от того, работаете ли вы в Word, Excel или PowerPoint, й имеет следующий синтаксис:
СИНТАКСИС
в Excel 2002:
expression.AddOLEObject([ClassType][,FileName] [,Link] [,DisplayAsIcon]
[,IconFileName] [,Iconindex] [,IconLabel]
[,Left] [,Top] [, Width] [, Height])
в Word 2002:
express!on.AddOLEObject([ClassType] [, FileName]
[, LinkToFile] [,DisplayAsIcon] [,IconFileName] [,Iconindex] [,IconLabel] [,Left] [,Top] [, Width] [,Height], Anchor}
в PowerPoint 2002:	v
expression.AddOLEObject([,Left] [,Top] [, Width] [, Height] [,ClassName] [, FileName] [,DisplayAsIcon] [,IconFileName] [,Iconindex] [,IconLabel] [,Link] )
Во всех трех случаях expression — это любое выражение, которое является допустимой ссылкой на коллекцию Shapes. Коллекция Shapes находится в объектах Worksheet, Document и Slide.
	FileName — (необязательный аргумент) строковое выражение, определяющее имя файла объекта, который необходимо вставить в качестве OLE-объекта; имя файла должно иметь расширение, соответствующее зарегистрированному приложению-серверу OLE. Используйте аргумент FileName для вставки существующего файла как OLE-объекта. Например, если вы хотите вставить существующий файл документа Word в рабочий лист Excel или слайд презентации, то в качестве аргумента FileName вы могли бы исполь
Работа с другими приложениями: Automation
453
зовать строку следующего вида: "C:\My documents\MyWords.doc” (предполагается, что файл, который вы хотите вставить, имеет имя MyWords.doc и находится в папке с именем Му documents). Если указывается аргумент ClassType, то аргумент FileName игнорируется.
	Link (для Excel, PowerPoint) и LinkToFile (для Word) — (необязательный аргумент) указывает, связывается или внедряется объект, указанный в File-Name. Если значение аргумента равно True, объект OLE, определенный строкой FileName, связывается. Если — False (значение по умолчанию), объект OLE, определенный строкой FileName, внедряется. (Внедрение объекта создает независимую копию объекта.) Если вы определяете ClassType, аргумент Link/LinkToFile должен иметь значение False или должен быть опущен.
	DisplayAsIcon — (необязательный аргумент) определяет способ отображения объекта. Если значение аргумента равно True, то объект отображается на экране как значок. Если — False или значение опущено, то объект отображается в его нормальном виде.
	IconFileNате — (необязательный аргумент) используется только в тех случаях, когда аргумент DisplayAsIcon имеет значение True. IconFileName — это строка, определяющая имя файла, содержащего значок, который необходимо отобразить для вставленного OLE-объекта. Если IconFileNате не используется или заданный файл не содержит никакого значка, то для этого класса OLE используется значок, заданный по умолчанию.
	Iconindex — (необязательный аргумент) индекс значка в IconFileName. Некоторые файлы содержат несколько значков; аргумент Iconindex выбирает в файле значок, который необходимо отобразить. Нумерация значков начинается с 0; первый значок имеет индекс 0, второй — 1 и т.д. Используйте Iconindex только в том случае, когда аргумент DisplayAsIcon имеет значение True и вы указали аргумент IconFileName. Если вы задаете несуществующий индекс значка, номер значка получает значение 1 (т.е. используется второй значок в файле). По умолчанию аргумент Iconindex имеет значение 0.
	IconLabel — (необязательный) аргумент, применяемый для настройки надписи значка OLE-объекта (если только DisplayAsIcon имеет значение True). Значением IconLabel может быть любое строковое выражение.
	Left и Тор — (необязательные) аргументы, задающие положение (в пунктах) левого верхнего угла объекта, которое отсчитывается от левого и верхнего краев документа, рабочего листа (не экрана) или слайда. Позиция объекта коллекции Shapes отсчитывается в точках от левого и верхнего краев рабочего листа, документа или слайда, так что объект будет выведен на экран и напечатан с одним и тем же относительным местоположением. Аргументы Left и Тор имеют по умолчанию значение 0, т.е. положение левого верхнего угла объекта совпадает с левым верхним углом рабочего листа, документа или слайда.
	Width и Height — (необязательные) аргументы, задающие начальную ширину и высоту OLE-объекта (в пунктах).
	Anchor — (необязательный аргумент) доступен только в Word-версии метода AddOLEObject и определяет в документе диапазон, к которому должен быть привязан объект. Если вы включаете аргумент Anchor, OLE-объект привязывается к первому абзацу диапазона привязки. Если вы опускаете этот аргумент, новый объект будет выровнен по левому и верхнему краям страницы документа.
	ClassType (для Excel, Word) ClassName (для PowerPoint) — (необязательный аргумент) строковое выражение, определяющее имя класса объекта, который необходимо вставить в качестве OLE-объекта. Используйте этот аргумент, ко
454
Глава 17
гда необходимо вставить новый (чистый или пустой) OLE-объект. Когда вы обращаетесь к методу AddOLEObject, следует включать или аргумент Class-Type (ClassName), или аргумент FileName.
В следующих таблицах приводятся возможные значения аргумента ClassType (ClassName) для различных OLE-объектов.
Таблица 17.2а. Значения ClassType (ClassName) для ActiveX Controls
Значения аргумента ClassType (ClassName)	Создаваемый элемент управления
Forms .CheckBox. 1	CheckBox
Forms. ComboBox. 1	ComboBox
Forms. CommandButton. 1	CommandButton
Forms.Frame.l	Frame
Forms.Image.l	Image
Forms. Label. 1	Label
Forms.ListBox.l	ListBox
Forms.MultiPage. 1	MultiPage
Forms. OptionBu tton. 1	OptionButton
Forms.ScrollBar. 1	ScrollBar
Forms.SpinButton. 1	SpinButton
Forms.TabStrip. 1	TabStrip
Forms.TextBox. 1	TextBox
Forms. ToggleButton. 1	ToggleButton
Таблица 17.2b. Значения ClassType (ClassName) для объектов Microsoft Access
Значение аргумента ClassType (ClassName)	Создаваемый объект
Access. Application	Application
Access.CodeData, Access.CurrentData	CurrentData
Access.CodeProject, Access.CurrentProject	CurrentProject
Access.Def aultWebOptions	DefaultW ebOptions
Таблица 17.2c. Значения ClassType (ClassName) для объектов Microsoft Excel
Значение аргумента ClassType (ClassName)	Создаваемый объект
Excel. Application	Application
Excel. Addin	Workbook
Excel.Chart	Workbook	„
Excel.Sheet	Workbook
Работа с другими приложениями: Automation
455
Таблица 17.2d. Значение ClassType (ClassName) для объекта Microsoft Outlook
Значение аргумента ClassType (ClassName)	Создаваемый объект
Outlook .Application	Application
Таблица 17.2е. Значение ClassType (ClassName) для объекта Microsoft PowerPoint
Значение аргумента ClassType (ClassName)	Создаваемый объект
PowerPoint. Application	Application
Таблица 17.2f. Значения ClassType (ClassName) для объектов Microsoft Word
Значение аргумента ClassType (ClassName)	Создаваемый объект
Word. Application	Application
Word.Document, Word.Template	Document
Word.Global	Global	
Примеры использования метода AddOLEObject коллекции Shapes
В следующих разделах рассматриваются несколько примеров использования метода AddOLEObject коллекции Shapes.
Вставка нового внедряемого объекта
Чтобы вставить новый внедряемый объект в рабочий лист или документ, необходимо выполнить метод AddOLEObject коллекции Shapes с аргументом Class-Type.
В коде листинга 17.1 к коллекции ActivePresentation.Slides(l).Shapes добавляется новый документ (строки 4-6) с использованием в качестве аргумента ClassName строки "Word.Document" (см. табл. 17.2f) и новая рабочая книга (строки 9-11) с использованием в качестве аргумента ClassName строки "Excel.Sheet” (см. табл. 17.2с). На рис. 17.6 отображено окно приложения PowerPoint с помещенными на слайд значками Word и Excel (перед «захватом» экрана значки были вручную увеличены).
Листинг 17.1. Использование метода AddOLEObject с аргументом ClassName
1	Sub AddOLEObjectExample2()
2	Set myDocument = ActivePresentation.Slides(1)
3
4	myDocument.Shapes.AddOLEObject Left:=100, Top:=100,
5	Width:=200, Height:=300, _
6	ClassName:="Word.Document", DisplayAslcon:=True
7
8
9 myDocument.Shapes.AddOLEObject Left:=200, Top:=100,
456
Глава 17
10	Width:=200, Height:=3OO, _
11	ClassName:="Excel.Sheet", DisplayAsIcon:=True
12
13 End Sub
Рис. 17.6
Окно приложения PowerPoint
с помещенными на слайд значками Word и Excel (перед «захватом» экрана значки были вручную увеличены)
j
Вставка существующего файла как внедренного объекта
В коде листинга 17.2 к коллекции ActivePresentation.Slides(l).Shapes добавляется уже существующий документ (строки 4-6) с использованием в качестве аргумента FileName строки "c:\d.doc". Результат работы кода листинга 17.2 представлен на рис. 17.7.
Рис. 17.7
Окно приложения PowerPoint с внедренным Word-документом
Работа с другими приложениями: Automation
457
Листинг 17.2. Использование метода AddOLEObject с аргументом FileName (внедрение)
1	Sub AddOLEOb]ectExamplel()
2	Set myDocument = ActivePresentation.Slides(1)
3
4	myDocument.Shapes.AddOLEObject Left:=100, Top:=100, _
5	Width:=200, fteight:=300, _
6	FileName:="c:\d.doc"
7
8	End Sub
Если вам необходимо отредактировать внедренный документ, щелкните на нем дважды. После этого вам предоставится возможность редактировать этот документ в (почти) обычной Word-среде (рис. 17.8). О документе-источнике можно забыть так же, как «забыло» о нем приложение PowerPoint. На рис. 17.8 в документ добавлена одна строка текста и нарисована небольшая таблица.
Рис. 17.8
Внедренный Word-документ редактируется в PowerPoint и не имеет никакой связи с исходным документом
^Microsoft PowerPoint • [Презентация 19]
Ч 39%
Файл Правка Вид Вставка Формат Сервис Таблица Справка
g ' 2 ' 3 ' 4 ' 5 < б > 7 > 8 । 9 । 10- _1 > 12- > 13 И
Исправления в измененном документе Показать •
Объекты S/мреи 0L£FofWil
В главе 10 опнсывъл.-кь модель объектов слоя векторном графики в Microsoft Woid Microsoft Evtel н Mxiosoft ft) w₽i Point В этой главе рксматрнваются (вомствэ и методы преднтнэченкые для управления OLE объектами находящимися в коллекции shape*
ттот документ не кмзет нголкои связи с исходным
Слайд 1 из 1
юрмление по умолчан русский (Россия)
Вставка существующего файла как связанного объекта
Если вам необходимо вставить существующий файл как связанный, а не как внедренный, то следует задать аргумент Link метода AddOLEObject равным True, как показано в листинге 17.3. После выполнения кода этого листинга вы можете увидеть на экране такую же картинку, что и на рис. 17.7. Если же вам будет необходимо изменить содержимое документа, то редактировать нужно будет документ-источник.
Листинг 17.3. Использование метода AddOLEObject с аргументом FileName (связывание)
1	Sub AddOLEObjectExample2()
2	' Вставка связанного документа
3
4	Set myDocument = ActivePresentation.Slides(1)
5
6 myDocument.Shapes.AddOLEObject Left:=100, Top:=100,
458
Глава 17
7	Width:=700, Height:=400, _
8	FileName:="c:\d.doc", Link:=msoTrue
9
10 End Sub
Редактировать документ-источник (связанный документ) можно по-разному. Например, двойной щелчок на объекте в приложении-клиенте откроет приложение-сервер со связанным документом. После внесения исправлений сохраните и закройте документ. Ваши исправления сразу же появятся в приложении-клиенте (рис. 17.9).
Рис. 17.9
Ваши исправления сразу же появятся в приложении-клиенте, если приложение-сервер запускалось из приложения-клиента
।
О Microsoft PowerPoint - [Презентация! 9]
файл Ставка вид Вставка Формат Сервис Показ слайдов Окно Оправка D 7
($ Коцструктор "* Создать слайд С
Объекты Shift и OLErormat
В главе 111 «нськша моднь ойиктов моя влторноп графики в Minowft Word Miaondt Exit) п Мнючнй PowerPoint В >mi главе ршипрнваются (Байства u истоды предаяиченные да упрлиюия OLE ж.агами, плодящимися в во и&щи Shapes
ЬкД М№Ц	J Ji	Ы ШИ
Действия*^] Автофигуры- \ \ Е i < гй!М О Ь» ' Слайд 1 из 1 юрмление по умолчат русский (Россия) С?
Г
Если же вы запустите приложение-сервер и отредактируете связанный документ, ваши исправления документа в приложении-клиенте появятся только при очередном запуске приложения-клиента (со связанным документом) и только с вашего разрешения — перед загрузкой приложения-клиента на экране появится диалоговое окно, представленное на рис. 17.10.
Microsoft PowerPoint
Презентация F \VB_books\VBA\Bce о 7ВА\Часть III Управление другими приложениями^"лава 19 Работа с другими приложениями Автоматизация\Презентация19 ppt содержит связанные объекты которые нельзя обновить
|[ О&чоеить связи J Отмена j Справка
Рис. 17.10. Исправления связанного документа, выполненные в приложении сервере, в приложении-клиенте появятся только при очередном запуске приложения клиента и только с вашего разрешения
Коллекция Excel OLEObjects
В дополнение к коллекции Shapes Excel поддерживает коллекцию OLEObjects — все связанные или внедренные OLE-объекты рабочего листа; каждый объект в коллекции OLEObjects — это OLEObject. В отличие от коллекции Shapes, которая может содержать линии, прямоугольники и другие элементы гра
Работа с другими приложениями: Automation
459
фического слоя, коллекция OLEObjects содержит только связанные или внедренные OLE-объекты. Для добавления OLEObject в коллекцию OLEObjects, используйте метод Add со следующим синтаксисом:
СИНТАКСИС
Object.OLEObjects.Add(
[ClassType] , [FileName] , [Link], [DisplayAsIcon] , [IconFileName] , [Iconindex], [IconLabel], [Left], [Top], [Width], [Height])
Object в этом методе — любая допустимая объектная ссылка на объект Worksheet. Метод OLEObjects.Add имеет такие же аргументы, как и метод Shapes.AddOLEObject. Описание аргументов метода OLEObjects.Add смотрите в описании синтаксиса метода Shapes.AddOLEObject, приведенном ранее в этой главе.
В листинге 17.4 показана процедура, использующая коллекцию OLEObjects (вместо коллекции Shapes).
Листинг 17.4. Использование метода Add Excel-коллекции OLEObjects
1	Sub EmbedWordDoc()
2	' Внедрение существующего файла c:\d.doc
3
4	With Worksheets(1)
5	.OLEObjects.Add Filenamec:\d.doc" , _
6	DisplayAsIcon:=True, _
7	IconFileName:="E:\WIN_XP\setupl.exe", _
8		Iconindex:=0, _
9	IconLabel:="c:\d.doc - Double-click to open"
10	End With
11
12	End Sub
Результат работы кода листинга 17.4 представлен на рис. 17.11. Обратите внимание на значок внедренного объекта (в строке 7 указан значок файла E:\WIN_XP\setupl.exe) и на надпись под значком (в строке 9 используется выражение c:\d.doc — Double-click to open).
Рис. 17.11
Исправления связанного документа, выполненные в приложении-сервере, в приложении-клиенте появятся только при очередном запуске приложения-клиента и только с вашего разрешения
460
Глава 17
Коллекция InLineShapes в Word
В дополнение к коллекции Shapes, Word также поддерживает коллекцию InLineShapes. В то время как коллекция Shapes содержит объекты Shape в графическом слое документа, коллекция InLineShapes содержит объекты InLineSha-ре, которые являются частью текстового слоя документа. Объект InLineShape обрабатывается в документе как символ текста и позиционируется подобно символам текста. Несмотря на то, что объект Shape связывается с определенным диапазоном текста, его можно свободно перемещать и позиционировать в каком-либо месте страницы; объект InLineShape всегда располагается на странице согласно его положению в строке текста.
Чтобы включить в коллекцию InLineShapes новый OLE-объект, используйте метод AddOLEObject со следующим синтаксисом:
СИНТАКСИС
Object OLEObjects Add(
[ClassType], [FileName] , [LinkToFile],
[DisplayAsIcon], [IconFileName] , [Iconindex], [IconLabel] , [.Range] )
Здесь Object является любой допустимой ссылкой на коллекцию InLineShapes. Аргументы ClassType, FileName, LinkToFile, DisplayAsIcon, IconFileNa me, Iconindex и IconLabel идентичны аргументам с теми же именами, которые уже обсуждались для метода Shapes.AddOLEObject в Word. Аргумент Range является выражением, указывающим диапазон, в который будет помещен в текст объект InLineShape. Если диапазон не является местом вставки, то добавляемый объект InLineShape заменяет диапазон. Если вы опускаете аргумент Range, расположение объекта определяет приложение Word.
Листинг 17.5 показывает пример вставки OLE-объекта как InLineShape-объекта Процедура EmbedPaintPicturelnLine вставляет файл E:\WIN_XP\ Gone Fishing.bmp как InLineShape-объект в текущее место вставки. На рис. 17.12 показан результат выполнения процедуры EmbedPaintPicturelnLine.
Рис. 17.12
OLE объект, вставленный как объект InLineShape процедурой листинга 17 5
"Л Работа с другими приложениями Автоматизация - Microsoft WerJ
файл Озавка Вид Вставка Формат Сдэеис Таблица дкно ^правка
J Г& У ’	<1 120% v ? limes New Roman
Ж
Исправления в измененном документе Показать - *>	& - & -	tC ,
§ *
2
3
5
б
8
10
Листинг 19 ' показывает пример вставки OLE-объекта как ]
EmbedP lintPktui elnLine вставляет файл Е WIN XP Gone Fisluiig
1
текущее место вставь.!
EinbedPaintPktui eliiLine
Нт рис 19 12 показан
л
Стр
Tintтинг 19 < Вставка OLE объекта как объекта InLiueShape
1 Sub Ejnbcdp'tmtFichuelnLuKO
2 Встроить существа тощий фзГп MSPnint как ооьект loLmeSInpe
Кол 1
18 Разд 1
18/36 На О 7см
русским (Ро С
Работа с другими приложениями: Automation
461
Листинг 17.5. Вставка OLE-объекта как объекта InLineShape
1	Sub EmbedPaintPicturelnLine()
2	' Встроить существующий файл MSPaint как объект InLineShape 3
4	With ActiveDocument.InlineShapes
5	.AddOLEObject Range:“Selection.Range, _
6	FileName:="E:\WIN_XP\Gone Fishing.bmp"
7	End With
8
9	End Sub
Объекты InLineShape можно вставлять как связанные, так и внедренные. Работа с объектом InLineShape подобна работе с объектом Shape. Вы можете преобразовывать объекты Shape в объекты InLineShape (и наоборот), используя метод Shape-объекта ConvertToInlineShape или метод InLineShape-объекта ConvertToShape.
Работа со связанными и внедренными объектами
После того как вы связали или внедрили OLE-объект в рабочий лист, документ или презентацию, вы можете, среди прочего, изменять размеры объекта и его форматирование, обновлять данные OLE-объекта, редактировать и удалять объект из рабочего листа, документа или презентации.
Вы можете управлять связанными или внедренными OLE-объектами, используя свойства и методы объекта Shape и объекта OLEFormat, содержащегося в объекте Shape. В Excel также имеется возможность управления связанными или внедренными OLE-объектами посредством OLEObject-свойств и методов. В Word можно к тому же управлять объектами InLineShape при помощи свойств и методов объекта InLineShape и объекта OLEFormat, который в нем содержится.
Доступ к OLE-объектам
Прежде чем вы исследуете методы управления OLE-объектами, вы должны знать, как обращаться к OLE-объектам, включенным в рабочий лист, документ или презентацию. Один из способов состоит в использовании коллекции Shapes:
СИНТАКСИС
Object.Shapes(Index)
Object является любой допустимой ссылкой на объект Worksheet, Document или Presentation.Slide, содержащий OLE-объект, с которым нужно работать. Аргумент Index может быть:
	номером, представляющим объект, к которому необходимо обратиться; число 1 означает первый объект Shape, вставленный в рабочий лист или документ, число 2 — второй вставленный объект Shape и т.д.
	текстовым именем объекта Shape, к которому необходимо обратиться; каждому OLE-объекту, добавленному в коллекцию Shapes, присваивается имя в форме Object п, где п — номер, соответствующий порядку, в котором объект был вставлен в рабочий лист, документ или слайд; первый OLE-объект имеет имя Object 1, второй — Object 2 и т.д.
Если вы работаете в VBA Excel, вы также имеете возможность доступа к отдельным OLE-объектам через коллекцию OLEObjects с использованием того же самого синтаксиса доступа (показанного в следующем примере), что и для коллекции Shapes (оба выражения ссылаются на один и тот же OLE-объект в рабочей книге):
462
Глава 17
ActiveWorkbook.Worksheets("Sheet1").OLEObjects(1)
ActiveWorkbook.Worksheets("Sheetl").OLEObjects("Object 1")
В Excel вы можете выяснить имя любого OLE-объекта, щелкнув на нем и посмотрев на поле Name (Имя) в строке формул.
В VBA Word к OLE-объектам, созданным как объекты InLineShape, можно обращаться через коллекцию InLineShapes. Объекты InLineShape не имеют имен; вы можете обратиться к элементу коллекции InLineShapes, используя только числовой индекс, как показано в следующем выражении (которое возвращает ссылку на второй объект InLineShape в документе):
ActiveDocument.InLineShapes(2)
Коллекция Shapes и в Word, и в Excel, и в PowerPoint может содержать не только OLE-объекты. Если объект OLEFormat объекта Shape ссылается на Nothing, то объект Shape не является OLE-объектом. Коллекция InLineShapes в Word может также содержать объекты, не являющиеся OLE-объектами. Если объект OLEFormat объекта InLineShape ссылается на Nothing, то объект InLineShape не является OLE-объектом.
При помощи свойства Туре объектов Shape или InLineShape можно определить, является ли OLE-объект связанным или внедренным. Для определения типа объекта Shape используйте класс встроенных констант MsoShapeType (определенный в библиотеке Office). Свойство Туре связанных OLE-объектов имеет значение msoLinkedOLEObject, а внедренных OLE-объектов — msoEmbeddedOLEObject. Для объектов InLineShape используйте константы wdlnLineShapeEmbeddedOLE-Object и wdlnlineShapeLinkedOLEObject класса встроенных констант wdlnLine-ShapeType, определенного в библиотеке Word.
Использование свойств OLE-объектов
Подобно любому объекту в VBA объект Shape коллекции Shapes имеет ряд свойств, которые вы можете использовать в VBA-коде для изменения вида объекта Shape или его поведения.
Одним из свойств объекта Shape является свойство OLEFormat, которое возвращает объект OLEFormat. Этот объект содержится в объектах Shape и сохраняет дополнительную информацию, необходимую для полного представления внедренного OLE-объекта. Другое свойство объекта Shape — LinkFormat — возвращает объект LinkFormat. Объект LinkFormat также содержится в объекте Shape и сохраняет часть дополнительной информации, необходимой для представления связанного OLE-объекта.
В таблице 17.3 приведены наиболее часто используемые свойства, которые относятся к OLE-объектам. В дополнение к краткому описанию каждого свойства таблица показывает, для какого объекта доступно данное свойство и доступно ли это свойство одновременно для Word, Excel и PowerPoint.
Таблица 17.3. Некоторые свойства OLE-объектов
Свойство	Приложение	Объект-носитель	Назначение
Anchor	Word	Shape	Объект Range указывает диапазон документа, с которым связывается объект Shape.
Работа с другими приложениями: Automation
463
Свойство	Приложение	Объект-носитель	Назначение
AutoUpdate	Excel, Word, PowerPoint *	LinkFormat	Имеет значение True, если связанный OLE-объект автоматически обновляется, когда изменяются данные приложения-сервера.
Bottom-RightCell	Excel	Shape	Возвращает объект Range, определяющий ячейку рабочего листа под правым нижним углом объекта Shape.
Height	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает высоту объекта Shape, измеряемую в точках.
Left	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает позицию левого края объекта относительно левого края рабочего листа или документа (в точках).
Line	Excel, Word, PowerPoint	Shape	Возвращает объект LineFormat, свойства которого управляют видом рамки OLE-объекта.
LinkFormat	Excel, Word, PowerPoint	Shape	Возвращает объект LinkFormat, свойства которого сохраняют информацию о связанном OLE-объекте.
Name	Excel, Word, PowerPoint	Shape	Имя объекта. Используйте это свойство, чтобы вернуть имя OLE-объекта или переименовать OLE-объект.
Object	Excel, Word, PowerPoint	OLEFormat	Возвращает Automation-объект, связанный с объектом.
OLEFormat	Excel, Word, PowerPoint	Shape	Возвращает объект OLEFormat, свойства которого содержат информацию как о связанных, так и о внедренных объектах.
OnAction	Excel	Shape	Вы можете использовать это свойство в Excel, чтобы установить или вернуть имя процедуры события для данного объекта Shape.
Progid	Excel, Word, PowerPoint	OLEFormat	Возвращает строку, содержащую тип класса OLE-объекта.
Shadow	Excel, Word, PowerPoint	Shape	Возвращает ссылку на объект ShadowFormat, который сохраняет информацию о состоянии тени, отбрасываемой объектом: видима она или — нет, ее цвет, величину сдвига относительно объекта и т.д.
Top	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает позицию верхнего края объекта относительно верхнего края рабочего листа или документа (в точках).
464
Глава 17
Свойство	Приложение	Объект-носитель	Назначение
TopLeftCell	Excel	Shape	Возвращает объект Range, определяющий ячейку рабочего листа, расположенную под верхним левым углом объекта Shape. Используйте TopLeftCell и BottomRightCell для поиска ячеек, перекрытых объектом Shape.
Type	Excel, Word, PowerPoint	Shape	Возвращает численное значение, указывающее тип объекта Shape. Используйте встроенные константы MsoShapeType для определения типа Shape.
Visible	Excel, Word, PowerPoint	Shape	Установите это свойство в состояние False, чтобы скрыть объект, или в состояние True, чтобы сделать его видимым.
Width	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает ширину объекта Shape (в точках).
В листинге 17.6 показана процедура Excel, которая демонстрирует использование некоторых из этих свойств, а на рис. 17.13 — результат работы этой процедуры: рисунок слева — это результат выполнения кода строк 7-13 (внедрение объекта), рисунок справа — это результат выполнения кода строк 15-21 (редактирование объекта).
S Microsoft Excel - Книга!?
ЕЗ Microsoft Excel - Книга! 9
8^ Файл Правка Вид вставка Формат Сдэеис Данные Окно Справка	- s х
й”	- " <	"
Объект 11	▼ д =ВНЕДРИТЬ( “Bitmap
____ __	. _ |п1адв„ .„)
2	Дважды щелкните для редактирования
► и\Лист1/Лист2 / Лист: [ < | j ►
ГОТОЕ	л
If] Файл Правка Вид Вставка Формат Сдзеис Данные
Окно Справка	_ s х
У?	"
Новое имяобъекта -г д =ВНЕДРИГЬ( "Bitmap
.	. д ...	.	„ image’',”")
2	Дважды щелкните для редактирования"'
3 •
6
7	ВИВИ
8	"ЗЭИВЭи
и « ► м \Лист 1/Лист2 / Лист | < !	1
ГОТОЕ	,
Рис. 17.13. Результат работы процедуры листинга 17.5
Листинг 17.6. Процедура Excel, использующая некоторые свойства OLE-объекта 1 2 3 4 5 6 7
1 Sub OLEObjectProperties()
2 ' Внедряет новый объект, а затем
3 ' устанавливает некоторые из его свойств
4
5	Dim BMPObject As Shape
6
7	With Worksheets("Лист!")
Работа с другими приложениями: Automation
465
8	.Activate
9	.Cells(2, 2).Value = "Дважды щелкните	для редактирования"
10	.Cells (4, 2).Select
11	Set BMPObject = .Shapes.AddOLEObject(	_
12	Filename:="E:\WIN_XP\Zapotec.bmp")
13	End With
14
15	With BMPObject *
16	.Line.Weight = xlThin
17	.Name = "Новое имя объекта”
18	.Shadow.Visible = True
19	.Shadow.OffsetX = 8
20	.Shadow.OffsetY = 8
21	End With
22
23	End Sub
Процедура OLEObjectProperties вставляет внедряемое изображение в рабочий лист Excel, а затем устанавливает некоторые из свойств нового OLE-объекта. Процедура начинается с объявления переменной типа Shape (с именем BMPObject). Оператор в строках 11 и 12 использует метод AddOLEObject в качестве функции, создавая новый объект и одновременно возвращая ссылку на этот объект; при этом в рабочий лист вставляется файл Zapotec.bmp как внедренный OLE-объект.
Строки 15-21 содержат оператор With, который использует переменную BMPObject для ссылок на только что вставленный OLE-объект. Строка 16 устанавливает толщину рамки объекта Shape (тонкая линия), присваивая значение константы xlThin свойству Weight объекта LineFormat, возвращаемого свойством Line объекта Shape. Строка 17 изменяет имя вставленного объекта, присваивая строку "Новое имя объекта" свойству Name — обратите внимание на окно Имя Excel-листа на правой половине рис. 17.12 (в левой половине этого рисунка в окне Имя указано имя объекта по умолчанию). Строки 18-20 устанавливают характеристики тени для объекта Shape, присваивая значения свойствам объекта ShadowFormat, возвращаемого свойством Shadow объекта Shape. Строка 18 устанавливает тень в видимое состояние, а строки 19 и 20 задают видимую область тени, устанавливая ее сдвиг относительно объекта Shape.	, ,
Методы OLE-объектов
Объекты Shape включают в себя несколько методов, которые можно использовать для управления этими объектами после их вставки. Многие из этих методов, например Copy, Cut, Delete, Activate и Select, не требуют разъяснений. Однако существуют два метода — Update и Verb (Doverb), которые доступны через свойство Shape.OLEFormat и имеют особое значение для OLE-объектов. В следующих двух разделах эти методы рассмотрены подробно.
Метод Update
Если вы вставляете объект Shape, который содержит связанный OLE-объект, связь между объектом и файлом сервера обычно является автоматической. Это означает, что каждый раз, когда файл сервера изменяется, объект-клиент модифицируется автоматически. В следующих двух случаях модификация не выполняется автоматически:
	Если вы переключили автоматическую связь на связь по запросу. (Вы можете сделать это, выбрав команду Правка | Связи, выбрав исходный файл в диалоговом окне Изменение связей (рис. 17.14 и 17.15), а затем — опцию по запросу.
466
Глава 17
	Если вы закрыли, а затем вновь открыли документ-клиент и выбрали Нет, ко гда Word или Excel выдали запрос, не хотите ли вы восстановить связи.
Рис. 17 15
Диалоговое окно Связи в PowerPoint
Рис. 17.14
Диалоговое окно Изменение связей в Excel
Связи
Связи
Тип
Обновление
Закрыть


мС ,ь
Обновить
Открыть ИСТОЧНИК
Изменить источник
Разорвать связь
Источник С DOC
Tun Документ М crosoft Word
Обновленке	автоматическое
вручную
В этих ситуациях вы можете использовать метод Update для обновления объекта:
СИНТАКСИС
Object LinkFormat Update
Здесь Object — это ссылка на объект Shape, содержащий связанный OLE-объект, который следует обновить. Если вы работаете в Word, Object может также быть ссылкой на объект InLineShape, который содержит связанный OLE-объ ект. Если вы работаете с объектами OLEObject Excel, то используйте следующий синтаксис для метода Update вместо приведенного выше (где Object — это ссылка на OLEObject в Excel):
Object Update
В листинге 17.7 приведен пример использования метода Update с объектами Shape.
Листинг 17.7. Применение метода Update для обновления OLE объектов в рабочей книге Excel 1 2 3
1 Sub ExcelUpdateAllObjects()
2 1 Обновляет OLE-объекты в Excel
3
Работа с другими приложениями: Automation
467
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 End
Dim aSheet As Worksheet
Dim Obj As Object
For Each aSheet In ActiveWorkbook.Worksheets Application.StatusBar = "Обновление в" _ & aSheet.Name
For Each Obj In aSheet.Shapes
If Obj.Type = msoLinkedOLEObject Then Obj.LinkFormat.Update
End If
Next Obj
Next aSheet
Application.StatusBar = False
MsgBox prompt:="Обновление связанных объектов Title, Buttons:=vbInformation
Sub
завершено",
Эта процедура VBA Excel обновляет все связанные OLE-объекты в каждом рабочем листе активной рабочей книги. Первый цикл For Each (строка 7) использует переменную aSheet для обработки каждого рабочего листа активной рабочей книги. Свойство StatusBar выводит имя каждого рабочего листа в строку состояния, чтобы пользователь мог наблюдать последовательность обработки связанных объектов для каждого листа (строки 8 и 9). Вложенный цикл For Each, начинающийся в строке 10, использует переменную Obj для обработки каждого объекта Shape текущего (для цикла) рабочего листа. В строке 11 проверяется, является ли объект Shape связанным OLE-объектом, т.е. равно ли свойство Туре значению константы msoLinkedOLEObject. Если объект Shape содержит связанный OLE-объект, то этот объект обновляется посредством вызова метода Update объекта LinkFormat (строка 12). Когда оба цикла For Each завершены, процедура «сбрасывает» строку состояния Excel (строка 17) и выводит сообщение о завершении работы (строки 19 и 20).
В листинге 17.8 приведена процедура, предназначенная для обновления OLE-объектов в Word.
Листинг 17.8. Применение метода Update для обновления QLE-объектов в документе Word
1 Sub WordUpdateAllObjects()
2 ' Обновляет все связанные объекты в Word
3
4	Dim Obj As Object
5
6	With ActiveDocument
7	' обновить связанные объекты в коллекции Shapes
8	For Each Obj In .Shapes
9	If Obj.Type = msoLinkedOLEObject Then
10	Application.StatusBar = _
11	"Обновление Shape-объекта: " & Obj.Name
12	Obj.LinkFormat.Update
13	End If
14	Next Obj
15
16	1 11 обновить связанные объекты в коллекции InLineShapes
17	For Each Obj In .InlineShapes
18	If Obj.Type = msoLinkedOLEObject Then
19	Application.StatusBar = _
20	"Обновление InLineShape-объекта: " & Obj.Index
21	Obj.LinkFormat.Update
22	End If
468
Глава 17
23	Next Obj
24	End With
25
26	Application.StatusBar = "Обновление связанных объектов завершено"
27
28	MsgBox prompt:="Обновление связанных объектов завершено", _
29	Title:="", buttons:=vblnformation
30	End Sub
Процедура WordUpdateAllObjects в листинге 17.8 обновляет все связанные OLE-объекты в активном документе как в коллекции Shapes, так и в коллекции InLineShapes. В остальном код процедуры WordUpdateAllObjects почти не отличается от кода процедуры ExcelUpdateAllObjects .
Методы Verb и DoVerb
Каждый OLE-объект имеет один или большее количество команд (verbs), определяющих действия, которые могут быть выполнены над этим объектом. В отличие от методов, которые определяют, какие действия вы можете выполнить над объектом с точки зрения VBA, verb-команды определяют, какие действия вы можете выполнить над объектом с «точки зрения» сервера. Другими словами, verb-команды — это действия, выполняемые над OLE-объектом приложением, в котором вы создали этот объект. Типичным примером verb-команды является команда Edit; посылка verb-команды Edit OLE-объекту открывает приложение-сервер для редактирования объекта.
Чтобы послать verb-команду OLE-объекту, следует использовать методы Verb или DoVerb. Метод Verb можно применять при работе с объектом OLEFormat Excel, а метод DoVerb — при работе с объектом OLEFormat Word. Перед тем как рассмотреть специфический синтаксис для методов Verb и DoVerb, приведем некоторые факты, которые надо иметь в виду при работе с verb-командами OLE-объекта:
	Все OLE-объекты имеют первичную verb-команду, совпадающую с действием, которое выполняется в ответ на двойной щелчок на объекте.
	Для большинства объектов, первичная verb-команда позволяет редактировать объект. Если вы хотите редактировать объект, но не точно знаете, что делает первичная verb-команда, используйте verb-команду Open.
	Если объект поддерживает вторичную verb-команду, вы можете определить эту verb-команду, используя число 2 в качестве значения для аргументов Verb или Verbindex (объясняется в обсуждении синтаксиса методов Verb и DoVerb).
	Для внедренных объектов, которые поддерживают OLE 2.0 или выше, первичная verb-команда позволяет редактировать объект «по месту», а вторичная — открыть объект в отдельном окне сервера.
Метод OLEFormat.Verb имеет в Excel следующий синтаксис:
СИНТАКСИС
Object.Verb([Verb])
Object в этом синтаксисе является ссылкой на любой объект OLEFormat Excel. Необязательный аргумент Verb — это числовое выражение, определяющее действие verb-команды, которое должен выполнить OLE-сервер. Excel определяет класс встроенных констант xlOLEVerb для упрощения определения значений для аргумента Verb. Используйте константы хЮреп, чтобы послать verb-команду Open, и xlPrimary, чтобы послать первичную verb-команду. Если вы опускаете аргумент Verb, то OLE-серверу посылается verb-команда, заданная по умолчанию.
Работа с другими приложениями: Automation
469
В листинге 17.9 показан пример применения метода Verb в процедуре VBA Excel.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Листинг 17.9. Применение метода OL.EFormat.Verb Excel для редактирования OLE-объекта
Sub InsEditWordDoc()
' Добавляет в Excel-лист OLE-объект и предлагает его редактировать.
' Если пользователь отказывается редактировать "по месту", то ' для редактирования документа открывается отдельное Word-окно. ' Если пользователь отменяет редактирование, то внедренный 1 документ удаляется.
Dim MyWordDoc As Object
Dim Ans As Integer
Dim aSheet As Worksheet
' создать внедренный документ:
Set aSheet = ActiveWorkbook.Worksheets("Лист1") With aSheet .Activate .Cells(3, 1).Select Set MyWordDoc = _
.Shapes.AddOLEObject(ClassType:="Word.Document") End With
' предложить пользователю три варианта
' дальнейшей работы:
Ans = MsgBox(prompt:="Редактировать документ 'по месту'?”, _ Buttons:=vbYesNoCancel + vbQuestion, _ Title ^"Редактирование документа")
If Ans = vbYes Then ' выбрана кнопка Yes - редактировать OLE-объект ' в Excel-окне ("по месту"): MyWordDoc.OLEFormat.Verb xlPrimary
Else If Ans = vbNo Then ' выбрана кнопка No - редактировать OLE-объект ' в отдельном Word-окне: MyWordDoc.OLEFormat.Verb xlOpen Else
' выбрана кнопка Cancel - удалить OLE-объект: MyWordDoc.Delete
End I f
End If	\
End Sub
Эта процедура внедряет новый документ Word в рабочий лист Excel. Затем процедура «спрашивает» пользователя, редактировать ли документ «по месту»; если пользователь отвечает «Нет» (выбирает кнопку No), то документ редактируется в отдельном окне. Если пользователь отменяет редактирование (выбирает кнопку Cancel), то внедренный объект-документ удаляется. На рис. 17.16 приведен пример редактирования документа при выборе режима редактирования «по месту».
470
Глава 17
Рис. 17.16
Редактирование документа «по месту»
Метод OLEFormat.DoVerb Word имеет следующий синтаксис:
СИНТАКСИС
Object.DoVerb([Verbindex) )
Object — это ссылка на любой объект OLEFormat Word. Необязательный аргумент Verbindex является числовым выражением, определяющим действие verb-команды, которое должен выполнить OLE-сервер. Word определяет класс встроенных констант wdOLEVerb для упрощения определения значений аргумента Verbindex. Встроенными константами wdOLEVerb являются: wdOLE-VerbDiscardUndoState (снимает состояние отмены объекта, оставляя его активным), wdOLEVerbHide (скрывает интерфейс пользователя объекта), wdOLE-VerblnPlaceActivate (активизирует объект, но не отображает интерфейс пользователя объекта), wdOLEVerbOpen (открывает объект в отдельном окне), wdO-LEVerbPrimary (посылает эквивалент verb-команды объекту, на котором был выполнен двойной щелчок), wdoLEverbshow (показывает объект для редактирования или просмотра) и wdOLEVerbUIActivate (активизирует объект «по месту» и отображает его интерфейс).
В листинге 17.10 показан пример применения метода DoVerb в процедуре VBA Excel.
Листинг 17.10. Применение метода OLEFormat.DoVerb
Word для редактирования OLE-объектов
1 Sub EditEmbWorksheets()
2 ' Создает внедренный Excel-объект.
3 ' Для всех объектов в коллекции Shapes	‘
4 1 11 предлагает пользователю возможность редактирования
5 1 внедренного рабочего листа Excel либо "по месту", либо 6 1 в отдельном окне.
7
8 Const strTitle = "Внедренный рабочий лист" ,
9
10	Dim MsgAns As Integer
11	Dim TmpObj As Shape, MyWordDoc
12
13	' создать внедренный лист:
14 Set MyWordDoc = ActiveDocument.Shapes.AddOLEObject(
15	ClassType:="Excel.Sheet.8")
16
17
18 For Each TmpObj In ActiveDocument.Shapes
Работа с другими приложениями: Automation
471
19
20	If TmpObj . Type = msoEmbeddedOLEObject Then
21
22	If TmpObj.OLEFormat.ProgID = "Excel.Sheet.8" Then
23	MsgAns = MsgBox(prompt:“"Редактировать " & _
24	TmpObj.Name & " 'по месту'?", _
25	'	buttons:=vbYesNo + vbQuestion, _
26	*	Title:=strTitle)
27
28	If MsgAns = vbYes Then
29	TmpObj.OLEFormat.DoVerb wdOLEVerbPrimary
30	Else
31	TmpObj.OLEFormat.DoVerb wdOLEVerbOpen
32	End If
33
34	Exit For
35
36	•
37	End If
38
39	End If
40
41 Next
42
43 End Sub
Процедура Edit Emb Worksheets в листинге 17.10 создает внедренный рабочий лист (строки 14-15). В цикле For Each (начало в строке 18) проверяются все объекты коллекции Shape активного документа. Если встречается внедренный OLE-объект (определяется проверкой значения свойства Туре объекта Shape в строке 20), то проверяется значение свойства Progid этого объекта для определения того, является ли внедренный объект рабочим листом Excel (строка 22).
Если внедренный объект — это рабочий лист Excel, оператор MsgBox в строках 23-26 предлагает редактирование листа в режиме «по месту». В случае положительного ответа (выбор кнопки Да) вызывается метод DoVerb с константой wdOLEVerbPrimary в качестве аргумента, иначе — метод DoVerb с константой wdOLEVerbOpen в качестве аргумента. При помощи оператора Exit For цикл заканчивается.
Чтобы определить, какие verb-команды доступны для конкретного OLE-объекта, вы можете использовать редактор реестра Windows. Запустите редактор реестра, как описано ранее в этой главе, когда вы искали типы классов объектов, и используйте команду Find редактора реестра для поиска типов классов объектов. Нажимайте клавишу F3 (или Find Next)) до тех пор, пока не дойдете до ветви \HKEY_CLASSES_ROOT\<c/ass type> (где <class type> — тип класса, который вы ищете). Раскрывайте ветви реестра под этой ветвью, пока не увидите ветвь \HKEY_CLASSES_ROOT\<c/ass tj/pe>\protocol\StdFileEditing\Verb. Список ветви Verb содержит verb-команды, которые «понимает» класс данного типа. На рис. 17.17 показано окно редактора реестра после завершения поиска типа класса Excel.Sheet.8 и последующего раскрытия соответствующих ветвей реестра.
Чтобы определить конкретную verb-команду, используйте его численное значение (0, 1 и т.д.) в ветви Verb базы данных реестра в качестве аргумента для методов Verb/DoVerb.
472
Глава 17
Рис. 17.17
Применение редактора реестра для поиска verb-команд, доступных OLE-объекту
£ Registry Editor____________________________________________________LJB®
0е &it View Fgyorltes Нф
Ll Insertable	* Name Type Data
Li Kfotlnsertable	*b] (Default)	REG_SZ ^Изменить
- Li protocol
- Li StdFiteEdrtng
Ll server - L] verb	*
LJO	’
Li	Excel Sheet 8	‘
*	Li	Excel SLK	I
t Li	Excel Template
*	Li Excel VBAModde	v
< > < >
My ComputerVKEY CLASSES R.OOTi£xcel Sheet 5\protocol\StcFiieEdit]ng\verb\l
Технология Automation
Automation1 (OLE-Automation) — это технология управления объектами одного приложения из другого, технология на основе СОМ, позволяющая прикладной программе-серверу предоставлять свои сервисы в распоряжение других программ-клиентов.
VBA может управлять объектами других приложений, поддерживающих Automation, точно так, как объектами своего host-приложения. Microsoft Access, Visio, Microsoft Graph, Microsoft Word, Microsoft Excel и PowerPoint — только некоторые из большого числа приложений, которые делают видимыми для VBA множество своих объектов.
Например, Visio делает видимыми такие объекты, как документы, страницы, формы и окна, a Microsoft Access — формы, отчеты и модули. Каждый из этих объектов имеет собственную коллекцию методов и свойств, которые программа VBA может читать и изменять, как если бы это были свойства и методы Excel или Word. Вы можете использовать Automation для управления объектами Excel из VBA Word, а объектами Word из VBA Excel. Количество приложений Windows, которые в настоящее время поддерживают Automation, быстро растет, хотя их относительно мало. Разумеется, любое другое приложение, которое использует Visual Basic for Applications, будет также поддерживать и Automation. Действительно, компания Microsoft уже сделала Visual Basic for Applications частью своих основных Windows-приложений. Текущий список приложений Microsoft, являющихся host-приложениями VBA и поддерживающих Automation, включает Excel, Word, Access, Outlook, Project, PowerPoint, Visio и Visual Basic 6.
t
Доступ к объектам Automation
Способ обращения к объекту Automation из VBA зависит от того, имеет ли объект соответствующий файл библиотеки объектов (.olb), файл библиотеки типов
Часто этот термин переводят как Автоматизация. Словари, по крайней мере, это подтверждают. Но, если понять смысл, который вкладывается в слово Automation — технология на основе СОМ, позволяющая прикладной программе-серверу предоставлять свои сервисы в распоряжение других программ-клиентов, — то, похоже, что этот термин не имеет к автоматизации никакого отношения. Автоматический процесс — это процесс, происходящий без участия человека (или «умного» животного) с использованием некоторых приборов, собирающих информацию для управления, и механизмов, осуществляющих управление этим процессом. Технология Automation не подразумевает никакого автоматического процесса, она подразумевает манипуляции объектами одного приложения из кода некоторого другого приложения. Здесь ничего не происходит автоматически. Именно поэтому в данной книге используется только термин Automation как название технологии корпорации Microsoft.
Работа с другими приложениями: Automation
473
(.tlb) или библиотеку динамической компоновки (.dll), которые содержат определения объектов, предоставляемых этой библиотекой другим приложениям. Microsoft Access, например, передает свои объекты через файл MSACC.OLB, Microsoft Word — через MSWORD.OLB, Microsoft Excel — через EXCEL.EXE1.
Если приложение предоставляет библиотеку объектов, вы можете обращаться к этим объектам непосредственно в VBA-коде, как если бы вы обращались к объектам host-приложения VBA, в Котором работаете. Чтобы сделать объекты, определенные в файле библиотеки Automation, доступными для конкретного проекта VBA, выберите команду редактора VB Tools | References и убедитесь в том, что в диалоговом окне References установлен флажок для данной библиотеки объектов.
Непосредственный доступ к объектам — это самый простой способ работы с Automation. Для доступа к объектам, определенным в другом приложении, используйте следующий синтаксис:
СИНТАКСИС
Application.ObjectName
Здесь Application — это имя приложения, содержащее объект, к которому необходимо обратиться, a ObjectName — имя объекта. Каждый объект OLEFormat имеет свойство Object, которое может обеспечить доступ к имени приложения или к ссылке на приложение:
Object.Object.Application
Здесь Object является ссылкой на объект OLEFormat. (Объекты OLEFormat содержатся в объектах Shape.) Когда метод Application используется указанным способом, он возвращает строку, содержащую имя Automation-приложения.
Вы можете также использовать метод Application для возвращения ссылки на исходное приложение объекта. Предположим, что вы внедрили документ Word в рабочий лист Excel и присвоили объектной переменной MyWordDoc такое значение, чтобы она сохраняла ссылку на объект Shape, который содержит внедренный документ Word. В этом случае для вывода имени свойства ActivePrinter приложения Word вы могли бы использовать следующий оператор:
MsgBox "Активный принтер: " & _
MyWordDoc.OLEFormat.Object.Application.ActivePrinter
В листинге 17.11 приведен пример доступа к Automation-объекту из VBA Excel. Здесь при помощи VBA-кода в рабочий Excel-лист внедряется новый документ Word, который затем редактируется также посредством кода — с использованием Automation, причем внедрение Word-документа в Excel-лист повлияло только на способ последующего доступа к Word-документу. Заметьте, что в диалоговом окне References не установлен флажок Microsoft Word 10.0 Object Library.
Листинг 17.11. Ссылка на объекты Automation из VBA Excel 1 2 3 4 5 6 7 8 9
1 Sub AutoWordObject()
2 1 Эта процедура внедряет новый документ Word, а затем работает
3 1 с документом, используя собственные методы и приложение
4
5	Dim	WdApp As Object
6	Dim	WdDoc As Object
7	Dim	aShape As Shape
8
9 Application.StatusBar = "Внедряем и редактируем документ"
1 Имя файла (и полный путь) можно увидеть в диалоговом окне References (в нижней секции) при установке флажка для конкретной библиотеки объектов.
474
Глава 17
10
11
12
13
14
15
16
17 
18
19
20
21
22
23
24
'25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 End
Application.Screenupdating = False
1 выбрать левую верхнюю ячейку
With Worksheets("Лист1")
.Activate	'
,Cells(2, 1).Select 1 создать новый внедренный документ: Set aShape = .Shapes.AddOLEObject(ClassType:="Word.Document") End With ' установить ссылки на приложение Word и внедренный документ: Set WdApp = aShape.OLEFormat.Object.Object.Application 1 проверить, на что ссылаемся: MsgBox "WdApp - Ссылка на: " & Chr(10) & Chr(13) & WdApp.Name
Set WdDoc = aShape.OLEFormat.Object.Object
1 проверить, на что ссылаемся:
MsgBox "WdApp - Ссылка на: " & Chr(10) & Chr(13) & WdDoc.Name
' Automation:
WdDoc.Activate	1 активизировать внедренный документ
1 доступ к объекту приложения Word:
With WdApp
.Selection.TypeText Text:“"Вводимый в Word-документ текст"
1 расширить выделенный фрагмент до абзаца:
. Selection.Expand Unit:=4
.Selection.Range.Bold = True
End With
’ обновить представление объекта
aShape.OLEFormat.Verb Verb:=xlVerbPrimary
Cells (1, 1).Select
Application.Screenupdating = True
Application.StatusBar = False
Sub
Поскольку ссылка на Microsoft Word 10.0 Object Library не задана, переменные WdApp (ссылка на Automation-приложение) и WdDoc (документ), объявлены (в строках 5, 6) как Object (ни к чему не обязывающее описание ссылки на переменную типа Object). В строках 9-18 содержатся рассмотренные ранее (в этой главе) операторы для внедрения Word-документа в Excel-лист.
В строке 21 переменной WdApp (до этих пор эта переменная имела значение Nothing) присваивается ссылка на Word-приложение. В этом можно убедиться при выполнении оператора в строке 23, который при помощи MsgBox выводит в диалоговом окне (рис. 17.18, а) текст «WdApp — Ссылка на:» и перенесенное на другую строку наименование приложения. В строке 25 переменной WdDoc (до этих пор эта переменная имела значение Nothing) присваивается ссылка на внедренный Word-документ. В этом можно убедиться при выполнении оператора в строке 27, который при помощи MsgBox выводит в диалоговом окне (рис. 17.18, Ь) текст «WdDoc — Ссылка на:» и перенесенное на другую строку наименование документа.
То, ради чего был написан этот код (использование Automation), содержится в строках 30-38. Здесь документ становится активным, затем в него вставляется и редактируется некоторый текст (рис. 17.19).
Работа с другими приложениями: Automation
475
Рис. 17.18
Результат выполнения
строк 23 и 27 кода листинга 17.11
Рис. 17.19
Результат выполнения кода листинга 17.11
Создание нового Automation-объекта
Если Automation-приложение предоставляет библиотеку объектов, вы можете использовать объекты этого приложения непосредственно в коде, создавая ссылку в проекте VBA на библиотеку объектов Automation (в диалоговом окне References). Если приложение не имеет библиотеки объектов или вы не хотите устанавливать ссылку на библиотеку объектов, можно для создания новых Automation-объектов использовать VBA-функцию CreateObject.
Функция CreateObject
Функция CreateObject является одной из функций VBA-класса Interaction и имеет следующий синтаксис:
СИНТАКСИС
CreateObject(Class)
Аргумент Class является программным идентификатором (programmatic identifier) (т.е. типом класса), определяющим Automation-приложение и тип объекта, который необходимо создать. Например, для Word программным идентификатором является Word.Application, а для Excel — Excel.Application. Среди других примеров можно привести программный идентификатор для приложения Visio — Visio.Application и для приложения Access — Access.Application. Функция CreateObject возвращает объектную ссылку на созданный объект.
В листинге 17.12 приведен пример использования функции CreateObject. Обратите внимание на то, что переменные MyWord (для ссылки на Word-приложение) и MyWdDoc (для ссылки на Word-документ) описаны как Object, то есть нет необходимости устанавливать ссылку на библиотеку Microsoft Word 10.0 Object Library.
476
Глава 17
Листинг 17.12. Применение CreateObject для создания объекта Automation
1	Sub CreateWordObject()
2	' Запускает Word, создает новый документ, редактирует его,
3	1 устанавливает некоторые свойства документа, закрывает Word
4
5	Dim	MyWord As Object
6	Dim	MyWdDoc As Object	•
7	Dim	fName As String	'	имя	документа
8	Dim	iconfName As String	'	имя	файла,	содержащего значок
9
10
11	' Создать экземпляр приложения Word
12	Set MyWord = CreateObject("Word.Application")
. 13
14	' установить имя файла, используя папку активной рабочей книги
15	fName = ActiveWorkbook.Path
16	fName = fName & "\Document Created by Excel VBA.doc"
17
18	' создать новый документ и установить объектную ссылку на него
19	Set MyWdDoc = MyWord.Documents.Add
20
21	' добавить в новый документ некоторый текст
22	With MyWord
23	.Selection.TypeText Text:="3TOT документ был создан " & _
24	"VBA-кодом из Excel"
25	.Selection.TypeParagraph
26	End With	,
27
2S	With MyWdDoc
29	' установить некоторые свойства документа
30	.BuiltinDocumentProperties("Title") = __
31	"Тестовый документ"
32	.BuiltinDocumentProperties("Subject") = _
33	"Automation-тестирование"
34
35	' сохранить документ и закрыть его
36	.SaveAs fName
37	.Close
38	End With
39
40	MyWord.Quit	' Выйти из Word
41
42	End Sub
Код этого листинга отличается от кода предыдущего способом создания нового документа (строки 12-19) — здесь для запуска Word-приложения используется функция CreateObject (строка 12), а для создания документа — метод Add (строка 19). В строках 22-26 документ редактируется (добавляется текст, изменяется стиль); в строках 30-33 для созданного документа устанавливаются свойства Title и Subject (рис. 17.20).
Приведем еще один пример использования функции без использования ссылки на библиотеку объектов. Представьте, что при разработке вами некоторого приложения заказчик потребовал, чтобы у него имелась возможность.посылать вам сообщения с отзывами о работе этого приложения. Заказчик не совсем активно использует компьютер и не хочет для посылки сообщений изучать многочисленные почтовые приложения. Ему нужно диалоговое окно в вашем приложении (к этому он уже привык), в котором можно набрать текст, может быть, адрес, а затем только нажать на кнопку отправки. Согласитесь — это справедливо.
Работа с другими приложениями: Automation
477
Рис. 17.20
Результат выполнения кода листинга 17 12
файл Правка Вид Вставка Формат
И У 'Л	Г 120%
Свойства Document Ciet'ej jy Ever VBA
Общие Документ j статистика j Состав Прочие
Исправления в измененном документе
Этот дою мент был с<
Стр 1
Разд 1
1/1
Название
Тема
Автор
Руководитель
Учреждение
Группа
Ключевые слова
Заметки
База гиперссылки Шаблон
.Этот документ был создан VBA кодом из I
AutDmation-тестирование
Владимир Кузьменко
Home computer
Normal
Создать рисунок для предварительного просмотра
На 1 Удй " Ct 1 К.6Л 7
1 Отмена £ус<?Кйй"1Г
2
3
Согласитесь также с тем, что эту задачу решить не трудно. Диалоговое окно в режиме разработки представлено на рис. 17.21, процедура обработки щелчка для кнопки Послать сообщение приведена в листинге 17.13. Код процедуры CmdSend_ Click создает при помощи функции CreateObject экземпляр Outlook-приложения (строка 10). Далее с использованием Automation-технологии создается новое сообщение (строка 13) и заполняются поля Subject, Body и То (строки 15-21). Код строки 24 посылает сообщение, а строки 26 -— закрывает Outlook-приложение.
Рис. 17.21
Диалоговое окно для отправки E-mail-сообщения
Текст сообщения
Сообщение автору программы
Адрес автора paleiiki@inail com
Послать сообщение I
Выход |

Листинг 17.13. Применение CreateObject для создания объекта Automation
1	Private Sub CmdSend_Click()
2	' Обработка события кнопки "Послать сообщение"
3
4	Dim	OutlookApp As Object
5	Dim	OutlookAddress As Object
6	Dim	myltem As Object
7	Dim	myRecipient As Object
8
9	' создать Outlook-приложение.
10	Set OutlookApp = CreateObject("Outlook.Application")
11
478
Глава 17
12	' создать новое сообщение:
13	Set myltem = OutlookApp.Createltem(olMailltem)
14
15	myltem.Sub]ect = UserForml.Caption
16
17	' текст сообщения из текстового окна:
18	myltem.Body = Msglext.Text
19
20	' записать адрес Outlook:
21	myltem.То = EmaliAdress.Text
22
23	' послать сообщение:
24	myltem.Send
25
26	OutlookApp.Quit
• 27
28 End Sub
Использование ссылок на библиотеки объектов
Если вы устанавливаете ссылку на библиотеку объектов для вашего VBA-проекта, то можете объявлять переменные, которые имеют специфические типы данных объектов библиотеки, а также создавать новые экземпляры объектов библиотеки, используя ключевое слово New.
Для демонстрации использования ссылок на библиотеки объектов изменим предыдущий листинг (17.13), как показано в листинге 17.14. При этом в диалоговом окне References необходимо (до набора кода) установить флажок Microsoft Outlook 10.0 Object Library (рис. 17.22).
Рис. 17.22
Для установки ссылки на библиотеку объектов Outlook в диалоговом окне References необходимо (до набора кода) установить флажок Microsoft Outlook 10 0 Object Library
References - VBAPrcjeet
Available References
Cancel
browse
*	* Visual Basic For Applications Microsoft Excel 10 0 Object Library
*	OLE Automation
*	* Microsoft Office 10 0 Object Library
*	’ Microsoft Forms 2 0 Object Library ------------------------—
VBAProject
IAS Helper COM Component 1 0 Type Library
IAS RADIUS Protocol 1 0 Type Library
Active Directory Types
Active Setup Control Library
ActiveMovie control type library
ASFChop 1 0 Type Library
ASFChoo 1 0 Tvoe Librarv

Microsoft Outlook 10 0 Object Library
Location E \program Files\Microsoft Office\OfficelO\msoutl olb
Language Standard
Установка ссылки на библиотеку объектов дает нам дополнительные преимущества: как только (в строке 10) мы вводим ключевое слово New, VB-редактор предлагает в списке объектов необходимый объект Outlook (рис. 17.23), а после выбора этого объекта — его свойства (объекты).
Листинг 17.14. Использование ссылки на библиотеку объектов
1	Private Sub CmdSend__Click ()
2	' обработка события кнопки "Послать сообщение" 3
Работа с другими приложениями: Automation
479
4	Dim	OutlookApp As Outlook.Application
5	Dim	OutlookAddress As Outlook.AddressLists
6	Dim	myltem As Outlook.Mailltem
7	Dim	myRecipient As Recipient
8
9	' создать Outlook-приложение:
10	Set OutlookApp = New Outlook.Application
11
12	' создать новое сообщение:
13	Set myltem = OutlookApp.Createltem(olMailltem)
14
15	myltem.Subject = UserForml.Caption
16
17	' текст сообщения:
18	myltem.Body = MsgText.Text
19
20	' запись адреса в Outlook:
21	myltem.To - EmaliAdress.Text
22
23	' послать сообщение:
24	myltem.Send
25
26	OutlookApp.Quit	,
27
28	End Sub
Рис. 17.23
Как только мы вводим ключевое слово New, VB-редактор предлагает в списке объектов необходимый Outlook-объект
Доступ к существующим объектам Automation
Вместо создания нового экземпляра объекта вам может понадобиться работать с уже существующим экземпляром объекта. Если приложение-сервер уже выполняется, то, чтобы обратиться к существующему объекту Automation, вызовите VBA-функцию GetObject:
СИНТАКСИС
GetObject([pathname], [Class])
Здесь необязательный аргумент pathname является строкой, определяющей полный путь папки и имя файла, содержащего объект, который необходимо найти. Если вы опускаете аргумент pathname, то тогда следует указать аргумент Class.
480
Глава 17
Необязательный аргумент Class является строкой, определяющей программный идентификатор объекта, с которым вы хотите работать. (Для аргумента Class функции GetObject используйте тот же самый синтаксис, что и для аргумента Class функции CreateObject.) Если вы опускаете аргумент Class, то необходимо указать аргумент pathname. При этом класс объекта будет определяться файлом, который вы указали; тип файла определяется по его расширению. VBA обращается к реестру Windows, чтобы определить, какой Automation-сервер требуется для файла этого типа.
В качестве примера использования функции GetObject рассмотрим ту же задачу посылки сообщения из Excel-кода, только добавим возможность указать имя прикрепленного файла. На рис. 17.24 приведено модифицированное для этого окно, а в листинге 17.15 — код обработчика события кнопки Послать сообщение.
Рис. 17.22
Диалоговое окно (модифицированное) для отправки E-mail-сообщения
Листинг 17.15. Использование функции GetObject для ссылки на открытое приложение
1	Private Sub CmdSend_Click()
2	' обработка события кнопки "Послать сообщение"
3
4	Dim	OutlookApp As Outlook.Application
5	Dim	OutlookAddress As Outlook.AddressLists
6	Dim	myltem As Outlook.Mailltem
7	Dim	myRecipient As Recipient
8
9
10	On Error Resume Next
11	Set OutlookApp = Nothing
12
13	' попытка получить ссылку на открытое приложение:
14	Set OutlookApp = GetObject(, "Outlook.Application")
15
16	If Err.Number 0 Then
17	Set OutlookApp = CreateObject("Outlook.Application")
18	End If
19
20
21	' создать новое сообщение:
22	Set myltem = OutlookApp.Createltem(olMailltem)
23
24	myltem.Subject = UserForml.Caption
25
26	' текст сообщения:
27	myltem.Body = MsgText.Text
28
Работа с другими приложениями: Automation
481
29	' имя прикрепленного файла:
30	myltem.Attachments.Add TexTAttFile.Text
31
32	1 E-mail-адрес:
33	myltem.To = EmaliAdress.Text
34
35	' послать сообщение:
36	myltem.Send
37
38	OutlookApp.Quit
39
40	End Sub
В строке 14 делается попытка получить ссылку на открытое ранее приложение. Если приложение не будет найдено, то выполнится код в строке 17 (без генерации ошибки, благодаря коду строки 10). Все остальное — как всегда, только добавлена строка 30 для указания имени прикрепленного файла.
Имейте в виду, что если сервер Automation зарегистрирован в реестре Windows как объект в единственном экземпляре (т.е. в любой данный момент на вашей системе может существовать только один экземпляр объекта), то независимо от того, сколько раз вы вызываете функцию CreateObject, будет создан только один экземпляр объекта. Точно так же функция GetObject всегда будет возвращать один и тот же экземпляр для объектов, существующих, по определению, только в одном экземпляре.
16 Программирование на VBA 2002
Глава 18
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
В главе «Работа с другими приложениями: Automation» было показано, как применять технологию OLE и Автоматизацию в работе с другими приложениями Windows. В этой главе рассматривается еще один способ обмена информацией между приложениями — Dynamic data exchange (DDE). DDE — это механизм, поддерживаемый Microsoft-приложениями в Windows (и в Macintosh), для обеспечения «диалога» между двумя приложениями.
Динамический обмен данными является таким способом «общения» приложений, когда два приложения непрерывно посылают друг другу данные и команды. Так же как и в технологии OLE, два приложения, включенные в этот процесс, называются клиентом и сервером. Приложение, которое инициирует и управляет DDE-обменом, называется клиентом (client); приложение, которое отвечает на запросы клиента, — сервером (server). Во время DDE-обмена приложение-клиент может запрашивать информацию и посылать команды приложению-серверу. Приложение-сервер может принимать/возвращать информацию и выполнять команды клиента (рис. 18.1).
Рис. 18.1
Роли приложений, участвующих в DDE-обмене
Приложение-клиент	/	\ ' DDE-канал ,	Приложение- сервер
Инициирует "диалог" Посылает команды Запрашивает информацию Посылает информацию Заканчивает "диалог"		Выполняет команды Обеспечивает информацией Принимает информацию
Для инициирования DDE-обмена приложение-клиент должно определить имя приложения-сервера и предмет DDE-обмена (conversation topic). Имя приложения-сервера и предмет DDE-обмена однозначно определяют DDE-обмен. Если один из участников обмена изменяет имя приложения или предмет DDE-обмена, «диалог» между ними прекращается.
Каждое приложение, поддерживающее технологию DDE, имеет уникальное DDE-имя. В Windows чаще всего (но не всегда) DDE-имя является именем исполняемого файла приложения (без расширения). В следующей таблице приведен ряд приложений Microsoft и их DDE-имена.
Microsoft Access	MSAccess
Microsoft Excel for Windows	Excel
Microsoft FoxPro for Windows	FoxPro
Microsoft Project for Windows	WinProj
Microsoft Word for Windows	WinWord
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»483
С каждым DDE-«диалогом» связано приложение-сервер и предмет обмена, в роли которого чаще всего выступают открытые файлы приложения. В Microsoft Excel предметом обмена может быть рабочий лист, в Microsoft Word — документ, а в Microsoft Access — база данных, таблица базы данных.
Особым предметом обмена, распознаваемым многими приложениями-серверами, является «System». В отличие от других предметов обмена, которые не всегда доступны (файл с листом, документом или базой может быть закрыт), «System» всегда доступен и может обеспечить списком других доступных в данный момент предметов обмена и другой информацией о приложении.
В течение DDE-обмена приложение-клиент и приложение-сервер могут изменять информацию, относящуюся к одному или более элементам (items) в рамках предмета обмена. Например, для Microsoft Excel элементами, которые могут изменяться в течение DDE-диалога, являются ссылки на ячейки рабочего листа, для Microsoft Word — закладки (bookmarks), для Microsoft Access — команды SQL.
Запуск приложения-сервера
Основным требованием DDE-обмена является одновременное выполнение приложений-участников «диалога». Поскольку мы, вообще-то, выступаем от имени приложения, которое является клиентом, то есть выполняет в данный момент некоторый написанный нами код, то требование быть запущенным, по всей видимости, относится к приложению-серверу.
Для того чтобы запустить другое приложение из процедуры VBA, следует вызвать VBA-функцию Shell:
СИНТАКСИС
Shell(РаthName [.Windowstyle})
Аргумент Pathname — это строковое выражение для (полного) имени исполняемого файла — запускаемого приложения. В строку аргумента Pathname можно включать любые ключи командной строки или аргументы запускаемого приложения. Аргумент WindowStyle — это число, которое указывает, какой тип окна появится после запуска приложения. VBA определяет несколько встроенных констант, которые упрощают использование аргумента WindowStyle; эти константы и их значения перечислены в Таблице 18.1. Если вы опускаете аргумент WindowStyle, приложение запускается в минимизированном состоянии и получает фокус.
Если функция Shell была выполнена успешна, она возвращает числовое значение — идентификационный номер задачи (task identification number) для только что запущенного приложения (Windows присваивает каждому работающему в данный момент приложению уникальный идентификационный номер (ID) задачи; для каждого рабочего сеанса ID задачи меняется.) Если Shell была выполнена неудачно, то она генерирует ошибку.
Shell выполняет приложение асинхронно, т.е. VBA запускает программу, а затем немедленно продолжает выполнение остальной части процедуры.
Таблица 18.1. Встроенные константы VBA для аргумента WindowStyle функции Shell
(WindowStyle	Вид окна
I vbHide	Скрытое, с фокусом
j vbNormalFocus	Нормальный размер, с фокусом
16’
484
Глава 18
WindowStyle	Вид окна
vbMinimizedFocus	Минимизированное, с фокусом
vbMaximizeFocus	Максимизированное, с фокусом
vbNormalNoFocus	Нормальный размер, без фокуса
vbMinizedNoFocus	Минимизированное, без фокуса
После того как вы запустили выполнение других программ, вашему приложению может потребоваться переключиться на какую-либо из этих программ. Например, вы планируете, что пользователь переключится из Excel в Control Panel, чтобы изменить различные настройки. Чтобы переключиться на любое запущенное из VBA-кода приложение, используйте оператор AppActivate:
СИНТАКСИС
AppActivate (Ti tie [, Wait] )
Аргумент Title может быть либо числовым выражением, результатом которого является допустимый номер идентификатора задачи (возвращаемый функцией Shell), либо строковым выражением, содержащим имя приложения, на которое вы хотите переключиться. В этом случае именем приложения является текст, который появляется в строке заголовка окна приложения. Для некоторых приложений строка заголовка окна включает как имя приложения, так и имя активного документа. Если Title не соответствует в точности ни одной строке заголовка работающих приложений, VBA пытается найти заголовок окна, который начинается со строки, переданной в аргумент Title. Если Title соответствует началу строки заголовка более чем одного выполняющегося приложения, то одно (произвольным образом) из этих приложений будет активизировано.
Необязательный аргумент Wait — это значение типа Boolean, которое определяет, когда VBA переключается на заданное приложение. Если значение Wait равно True, то AppActivate ждет до тех пор, пока вызывающее приложение станет активным; для VBA это означает, что AppActivate ждет до тех пор, пока host-приложение VBA не станет активным (например, Word или Excel). Если значение Wait равно False или опущено, метод AppActivate переключается на другое приложение немедленно. Устанавливайте Wait в состояние True каждый раз, когда вам нужна гарантия того, что ваша VBA-программа активизирует другое приложение только в том случае, когда host-приложение VBA находится в активном состоянии, а не выполняется в фоновом режиме.
Инициализация и завершение связи
с DDE-сервером
Обмен в технологии DDE состоит из трех этапов:
1.	Инициализация связи между клиентом и сервером1. Эта связь, называемая каналом, является путем, по которому общаются два приложения. Поскольку инициализируют диалог VBA-процедуры, для DDE-связи клиентом является VBA.
2.	Работа с сервером: Как только связь установлена, клиент может обмениваться данными с сервером и может управлять сервером, вызывая его внутренние макрокоманды или посылая на сервер «нажатия клавиш».
3.	Завершение связи: Когда клиент завершил работу с сервером, VBA-процедура должна закрыть DDE-канал.
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
485
Инициализация и завершение связи с DDE-сервером
Для того чтобы инициализировать DDE-диалог, ваша VBA-процедура должна установить соединение с приложением-сервером. Для установления канала между host-приложением VBA и другим DDE-приложением необходимо использовать метод DDEInitiate, имеющий следующий синтаксис:
СИНТАКСИС
object.DDEInitiate(Арр, Topic)
Здесь аргумент object является необязательным и представляет объект Application (DDEInitiate — метод, принадлежащий host-приложению VBA). Аргумент Арр является строкой, содержащей DDE-имя приложения-сервера, с которым вы хотите установить связь. DDE-имя зависит от приложения, с которым вы связываетесь, и, как правило, это имя исполняемого файла (без расширения), который запускает приложение. Например, DDE-имя для Excel — Excel, а DDE-имя Word — Winword.
Аргумент Topic — это строка, определяющая часть сервера, с которой вы хотите работать. Можно считать, что это «предмет диалога» между клиентом и сервером. Для большинства приложений используется либо предмет System (когда происходит обращение к приложению-серверу в целом), либо имя конкретного файла сервера, с которым вы хотите работать.
Если метод DDEInitiate завершается успешно, он возвращает значение типа Long, которое идентифицирует канал. На это значение следует ссылаться во всех последующих DDE-обменах между клиентом и сервером.
Если приложение-сервер уже открыто, когда вы выполняете метод DDEInitiate, то открывается DDE-канал. Если DDE-сервер еще не запущен, выполнение метода DDEInitiate вызовет запуск приложения-сервера. Однако существуют несколько причин, по которым запуск приложения-сервера выполнением метода DDEInitiate может быть неудобным:
	Каждый раз, когда приложение-сервер запускается выполнением метода DDEInitiate, host-приложение VBA выводит сообщение о том, что удаленные данные недоступны и предлагает запустить приложение-сервер. Чтобы продолжить работу, пользователь должен щелкнуть кнопку Yes; если пользователь выбирает кнопку No, метод DDEInitiate генерирует runtime-ошибку VBA. Даже если вы попытаетесь обойти эту проблему, установив свойство Application.DisplayAlerts в состояние False, VBA все равно будет генерировать ошибку времени исполнения.
	Если в данный момент выполняется более одного экземпляра приложения-сервера DDE, пользователю может быть представлен диалог, спрашивающий, какой из экземпляров сервера нужно использовать.
	Если приложение-сервер DDE не находится в текущей папке или на диске, а также не находится на диске или в папке в пути поиска файлов DOS, метод DDEInitiate не сможет его найти. Чтобы решить эту проблему, перед вызовом метода DDEInitiate нужно вставить оператор VBA ChDir для перехода в папку DDE-сервера (или включить полный путь папки в определение аргумента Арр).
	В большинстве случаев перед вызовом метода DDEInitiate для открытия DDE-канала следует вызывать функцию Shell для запуска приложения-сервера.
Когда приложение-клиент завершает DDE-«диалог», следует закрыть связь между клиентом и сервером. Для этого предназначен метод DDETerminate:
486
Глава 18
СИНТАКСИС
DDETerminate Channel
Здесь Channel — это число типа Long, указывающее DDE-канал, который должен быть закрыт; Channel должен ссылаться на допустимый номер DDE-кана-ла (тот номер, который был возвращен методом DDEInitiate).
В листинге 18.1 показан пример процедуры, вызывающей методы DDEInitiate (для открытия DDE-канала) и DDETerminate (для закрытия DDE-канала).
Листинг 18.1. Применение метода DDEInitiate для открытия DDE-канала
1	Option Explicit
2	Dim ddeChannel As Long
3
4	Sub OpenDDEchannel()
5	' Открывает DDE-канал между Excel (клиент) c Word (сервер)
6
7	Const ITitle = "Открытие DDE-канала"
8
9	.	On Error GoTo BadConnection
10
11	Shell PathName:="E:\Program Files\Microsoft Office\OfficelO" &
12	"\Winword.exe", WindowStyle:=vbMinimizedNoFocus
13
14	ddeChannel = DDEInitiate(App:="Winword", Topic:="System")
15
16	MsgBox prompt:="DDE-канал открыт!", Buttons:=vblnformation, _
Title:=lTitle
17	DDETerminate ddeChannel
18	Exit Sub
19
20	BadConnection:
21	MsgBox prompt:="Невозможно открыть DDE-канал", _
22	Buttons:=vbExclamation, Title:=lTitle
23	End Sub
Процедура OpenDDEchannel открывает DDE-канал между Excel (клиент) и Word (сервер). В строке 3 объявляется переменная уровня модуля ddeChannel; это дает возможность другим процедурам в этом модуле ссылаться на номер канала, возвращаемый методом DDEInitiate.
Сама процедура OpenDDEchannel начинается со строки 5. Оператор в строке 10 включает обработчик ошибок. Включение обработчика ошибок в DDE-процедуру всегда оправдано, поскольку DDE-соединения известны своей ненадежностью.
Вызов функции Shell (строки 12-13) запускает Word в минимизированном состоянии без фокуса; в данном случае возвращаемый функцией Shell результат игнорируется. Код строки 15 вызывает метод DDEInitiate; Word уже выполняется в результате вызова функции Shell, так что метод DDEInitiate только открывает DDE-канал. Если все идет нормально, номер канала сохраняется в переменной ddeChannel и (строка 17) оператор MsgBox сообщает пользователю, что соединение было установлено. Если происходит ошибка, выполнение кода переходит к метке BadConnection (строка 21) и выводится сообщение об ошибке (строки 22 и 23).
Код в строке 18 закрывает DDE-канал — пока без дальнейшего «общения» с сервером.
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
487
Управление приложением-сервером
• Как только у вас есть открытый DDE-канал, вы можете использовать метод DDEExecute для управления приложением-сервером DDE. Вы можете посылать команды, которые «понимает» приложение-сервер, например команды на его макроязыке (если таковой имеется), или можете посылать приложению-серверу «нажатия клавиш». DDEExecute'имеет следующий синтаксис:
СИНТАКСИС:
DDEExecute(Channel, String)
Channel — это номер канала, возвращаемый методом DDEInitiate, a String — строковое выражение, которое представляет команды или «нажатия клавиш», посылаемые серверу. Формат, используемый для команд, зависит от приложения-сервера DDE. Некоторые приложения «разрешают» использовать команды своего макроязыка, другие — используют специальные DDE-команды. (Информацию относительно DDE-команд, поддерживаемых конкретным приложением, можно получить из документации приложения-сервера или обратившись в отдел технической поддержки разработчика приложения.) Метод DDEExecute возвращает значение типа Boolean, указывающее, успешно ли выполнен метод.
В листинге 18.2 приведен простой пример вызова метода DDEExecute.
Листинг 18.2. Применение метода DDEExecute для управления приложением-сервером
1	Sub DDEExecuteExamplel()
2	' Пример использования DDEExecute
3
4	Const ITitle = "Открытие DDE-канала"
5	Dim ddeChannel As Long
6
7	On Error GoTo The_End
8
9	Application.StatusBar = "Запуск WinWord..."
10
11	Shell PathName:="E:\Program Files\Microsoft Offrce\OfficelO" & _
12	"\Winword.exe", Windowstyle:=vbMinimizedNoFocus
13
14	' Инициализировать канал с "предметом диалога" - System
15	Application.StatusBar - "Opening test document..."
16	ddeChannel = DDEInitiate(App:="WinWord" , Topic:="System")
17
18	' послать серверу команду на открытие документа:
19	DDEExecute Channel:=ddeChannel, _
20	String:="[FileOpen ""F:\VB_books\DBMS\01.DOC""]"
21
22	' закрыть канал:
23	DDETerminate ddeChannel
24
25	Exit Sub ' обойти метку The_End
26
27	The_End:
28	MsgBox prompt:="Что-то у нас не ладится", _
29	Buttons:=vbExclamation, Title:=lTitle
30	Application.StatusBar = False
31	End Sub
488
Глава 18
Процедура DDEExecuteExamplel отличается от процедуры OpenDDEchannel (из листинга 18.1) только одним оператором (строки 19-20), который при помощи метода посылает серверу (приложению Word) команду открыть документ F:\VB_books\DBMS\01.DOC, который к этому моменту должен действительно находится в указанной папке. В результате работы процедуры вы можете увидеть указанный вами открытый документ.
Если нужного документа на диске не окажется, вы поЛучите два сообщения (последовательно), приведенные на рис. 18.2. Кроме того, будет создан новый документ с именем по умолчанию.
Рис. 18.2
Роли приложений, участвующих в DDE-обмене
Run-time error '1076'
Файл не найден
Попробуйте выполнить следующие действия
* Убедитесь, что имя документа введено правильно
* Попробуйте другое имя файла
(F AVB_books\PBMS\02.DOC)
j End ‘ Г Qebug 1 Help
В листинге 18.3 также приведен код с использованием метода DDEExecute. Здесь сначала повторяются операторы листинга 18.2 (строки 1-23), а затем в открытом документе выделяется фрагмент текста и копируется в Windows-буфер, из которого может быть помещен в любое приложение.
Листинг 18.3. Применение метода DDEExecute для управления приложением-сервером
1	Sub DDEExecuteExample2()
2	' Пример использования DDEExecute	t
3
4	Const ITitle = "Открытие	DDE-канала"
5	Dim ddeChannel As Long
6
7	On Error GoTo The_End
8
9	Application.StatusBar = " Запуск WinWord..."
10
11	Shell PathName:="E:\Program Files\Microsoft Office\OfficelO" &
12	"\Winword.exe", Windowstyle:=vbMinimizedNoFocus
13
14	' Инициализировать канал с "предметом диалога"- System
15	Application.StatusBar = "Opening test document..."
16	ddeChannel = DDEInitiate(App:="WinWord" , Topic:="System")
17
18	' послать серверу команду на открытие документа:
19	DDEExecute Channel:=ddeChannel,
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
489
20	String:="[FileOpen ""F:\VB_books\DBMS\01.DOC""]"
21
22	' закрыть канал:
23	DDETerminate ddeChannel
24
25	' Инициализировать канал	с	"предметом	диалога"- документ
26 Application.StatusBar = "Copying text..."
27	ddeChannel = DDEInitiate(Арр:="WinWord",	__
28	Topic:="F:\VB_books\DBMS\01.DOC")
29
30	' Перейти в начало документа:
31 DDEExecute Channel:=ddeChannel, String:="[StartOfDocument]"
32	' Выделить первую строку документа:
33 DDEExecute Channel:=ddeChannel, String:="[EndOfLine 1]"
34	' Копировать выделенный фрагмент в Windows-буфер:
35 DDEExecute Channel:“ddeChannel, String:="[EditCopy]"
36
37 DDETerminate ddeChannel ' закрыть DDE-канал
38
39 Exit Sub ' обойти метку The_End
40
41	The_End:
42	MsgBox prompt:="Что-то у нас не ладится!",
43	Buttons:=vbExclamation, Title:=lTitle
44	Application.StatusBar = False
45	End Sub
Код в строках 27-28 открывает новый DDE-канал с «предметом диалога» — открытый предыдущими операторами процедуры документ. Команда, переданная по DDE-каналу серверу посредством 31 строки кода, переводит курсор (точку вставки) в начало документа. Посредством команды, переданной кодом строки 33, выделяется первая строка документа. Код строки 35 передает команду копирования выделенного фрагмента в Windows-буфер.
После того как код листинга 18.3 выполнится, вы можете проверить, что оказалось в Windows-буфере, выполнив команду вставки либо в Excel, либо в Word.
Обмен данными с приложением-сервером DDE
Как вы только что видели, каждый DDE-диалог между клиентом и сервером имеет определенный «предмет диалога». Все, что два приложения «обсуждают» в текущем DDE-сеансе, ограничено темами, относящимися к заданному «предмету диалога». В предыдущем разделе вы видели, как включаются в DDE-обмен команды сервера. В этом разделе рассматривается другой предмет, который вы можете использовать в DDE-обменах: элементы данных.
Каждое поддерживающее DDE приложение-сервер определяет один или большее количество элементов (items), которые оно может использовать совместно с клиентом. Например, типичным элементом рабочего листа является ячейка, а типичным элементом текстового процессора — закладка (закладка — это именованный блок текста). Эти элементы всегда составлены только из текста и чисел — в DDE-обмене вы не можете передать графику и другие объекты высокого уровня.
В следующих двух подразделах показано, как использовать методы DDERe-quest и DDEPoke для обмена элементами данных между клиентом и сервером.
Получение данных от DDE-сервера
Если сервер имеет данные, которые следует передать приложению-клиенту, вы можете установить между двумя приложениями DDE-связь и вызвать метод DDERequest для получения данных:
490
Глава 18
СИНТАКСИС
DDERequest(Channel, Item)
Аргумент Channel — номер канала, возвращаемый методом DDEInitiate. Item — строка, определяющая элемент данных, который вы хотите получить от сервера. Как и с другими DDE-методами, DDERequest возвращает значение Boolean, указывающее на успешное или неуспешное выполнение операции.
В листинге 18.4 приведен пример использования метода DDERequest.
Листинг 18.4. Применение DDERequest для получения данных из приложения
1	Sub WordDataRequest()
2	' Устанавливает закладку в документе Word;
3	' восстанавливает текст закладки
4	Const ITitle = "Обмен по	DDE-каналу"
5	Dim ddeChannel As Integer
6	Dim WordData As Variant
7
8	On Error GoTo Retreat
9
10	' открыть документ (см. листинги 18.2, 18.3)
11	Shell PathName:="Е:\Program Files\Microsoft Office\OfficelO" &
12	"\Winword.exe", Windowstyle:=vbMinimizedNoFocus
13	ctdeChannel = DDEInitiate(App:“"WinWord" , Topic:“"System")
14	DDEExecute Channel:“ddeChannel, _
15	String:="[FileOpen ""F:\VB_books\DBMS\01.DOC""]"
16	DDETerminate ddeChannel
17
18	' открыть новый DDE-канал с предметом - документ
19	ddeChannel = DDEInitiate(Арр:“"Winword" , _
20	Topic:="F:\VB_books\DBMS\01.DOC")
21
22	' найти ключевое слово и вставить закладку
23	. DDEExecute	Channel:“ddeChannel,	String:="[StartOfDocument]"
24	DDEExecute	Channel:“ddeChannel,	_
25	String:="[EditFind .Find = ""Database""]"
26	DDEExecute	Channel;“ddeChannel,	_
27	String:="[SelectCurSentence]"
28	DDEExecute	Channel:“ddeChannel,	_
29	String:="[EditBookmark .Name = ""Base""]"
30
31 WordData = DDERequest(Channel:“ddeChannel, Item:“"Base")
32
33	' вставить WordData в первую ячейку рабочего листа	'
34	Worksheets("Sheetl").[Al].Value = WordData
35
36	DDETerminate ddeChannel
37
38 Exit Sub
39
40	Retreat:
41	DDETerminate ddeChannel
42	’ '
43	MsgBox prompt:="Что-то у нас не ладится", _
44	Buttons:=vbExclamation, Title:“ITitle v
45	Application.StatusBar = False
46	End Sub
Процедура WordDataRequest в листинге 18.4 находит определенный раздел текста в документе Word, считывает и передает его в Excel.
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
491
Код строк 11-12 вызывает функцию Shell для запуска Word. Код строки 13 открывает DDE-канал для Word с «предметом обмена» System. В строках 14 и 15 находится оператор, который вызывает метод DDEExecute для передачи серверу команды открытия указанного файла с документом. После того как файл открыт, этот DDE-канал больше не нужен, поэтому он закрывается кодом строки 16 (методом DDETerminate).
Код строк 19-20 открывает новый DDE-канал для Word, используя на этот раз открытый документ как «предмет обмена». В строках 23-29 содержатся четыре оператора, использующих метод DDEExecute: в строке 23 выполняется переход в начало документа, код строк 24-25 ищет в документе заданное слово, код строк 26-27 выделяет строку с искомым текстом, а код строк 28-29 вставляет закладку в выбранный текст.
Код строки 31 вызывает метод DDERequest для передачи по DDE-каналу текста, отмеченного новой закладкой, и сохраняет этот текст в переменной Word-Data. Код строки 34 вставляет содержимое переменной WordData в первую ячейку указанного рабочего листа активной рабочей книги.
В листинге 18.5 приведен пример использования метода DDERequest для запроса данных из приложения Access, до сих пор мало встречавшегося в этой книге. Как известно, Microsoft Access — это приложение для хранения и управления таблицами данных. Подобно тому, как в Excel основными объектами являются рабочие книги, листы и ячейки, в Access основные объекты — базы данных, таблицы, поля и строки таблиц. В четвертом разделе книги элементы баз данных будут рассматриваться более подробно, а в листинге 18.5 показан пример, как можно запросить данные из некоторой таблицы Access-базы данных. (Эта база данных может быть установлена в качестве примера при установке Microsoft Access.)
Листинг 18.5. Применение DDERequest для получения данных из приложения Access
1	Sub AccessDataRequest()
2	' Запрашивает данные из таблицы Access
3
4	Const ITitle = "Обмен по DDE-каналу"
5	Dim ddeChannell As Integer, ddeChannel? As Integer
6
7
8	On Error GoTo Retreat	/
9
10	' открыть канал ddeChannell:
11	ddeChannell = DDEInitiate(App:="MSAccess" , Topic:="System")
12
13	DDEExecute ddeChannell, _
14	"[OpenDatabase ""E:\Program Files\Microsoft _
15	OfficeXOfficel0\Samples\Борей.mdb""]"
16	' открыть канал ddeChannel2:
17 ddeChannel? = DDEInitiate("MSAccess", "Борей;TABLE Товары ")
18
19	' запросить данные из таблицы:
20 data = DDERequest(ddeChannel2, "All")
21
22	' заполнить данными первые десять строк листа:
23	Worksheets("Лист1").[Al:К10].Value	= data
24
25	DDETerminate ddeChannell
26	DDETerminate ddeChannel2
27 Exit Sub
28
29
30 Retreat:
492
Глава 18
31
32	DDETerminate ddeChannell
33	DDETerminate ddeChannel?
34
35	MsgBox prompt:="Что-то у	нас не ладится",
36	Buttons:=vbExclamation, Title:=lTitle
37
38 End Sub
Код строки 11 открывает первый канал для DDE-обмена с приложением Access (при этом, поскольку не использовалась функция Shell, Windows выдаст запрос на запуск Access). Код строк 13-14 посылает команду серверу для открытия файла Борей.шйЬ, который на разных компьютерах может располагаться в различных местах. Код в строке 17 открывает второй канал (до сих пор мы закрывали первый открытый канал и снова открывали его с другим «предметом обмена»), где в качестве «предмета обмена» уже используется таблица Товары открытого файла Bopeh.mdb.
В строке 20 данные из таблицы Товары передаются в переменную data. В строке 23 полученные данные вставляются в рабочий лист в указанные столбцы.
Видимая часть таблицы Товары базы данных Борей представлена на рис. 18.3. На рис. 18.4 представлен лист, в который были помещены запрошенные из Access данные.
 Товары : таблица
| Код товара !	Марка________
|Genen Shouyu 2 Pavlova 3 Alice Mutton 4 Carnarvon Tigers 5 Teatime Chocolate Biscuits 6 Sir Rodney’s Marmalade 7 Sir Rodney's Scones 8 Gustafs Knackebrod 9 Tunnbrod 10 Guarana Fantastica
11 NuNuCa Nuss-Nougat-Creme АО Германия-Россия 12 Gumbar Gummibarchen АО Германия-Россия
T ► I ИЭ 77	Д ‘
|_______Поставщик_______
Mayumi’s
Pavlova Ltd Pavlova. Ltd Pavlova Ltd Specialty Biscuits Ltd Specialty Biscuits. Ltd Specialty Biscuits Ltd PB Knackebrod AB PB Knackebrod AB Refrescos Amencanas LTD
Загиъ 1<Н |Г
I__________Тип________
Приправы
Кондитерские изделия Мясо/птица Рыбопродукты Кондитерские изделия Кондитерские изделия Кондитерские изделия Хлебобулочные изделия Хлебобулочные изделия Напитки
Кондитерские изделия Кондитерские изделия
Рис. 18.3. Видимая часть таблицы Товары базы данных Борей
[ £3 Microsoft Excel - New Лист Microsoft Excel				ИВИМИИИШВИИ.- i', -JH	
Фай'1	□эаека Вил Вставка Формат Сервис	Данные	Окно	Справка	- _ <5 х
	’ Е - 100% ’	7 Ала!		• 10	” ж к ч & & -%	$	
E13	-r	a					
	А	В	С		D	Е	F	GT
1 КодТовара Марка	КодПоставщика КодТипа ЕдиницаИзмерения					Цена НаСклс
2	1 Genen Shouyu		6	2 24 бутылки по 250 мп	697 5
3 (	2 Pavlova		7	3 32 коробки по 500 г	785 25
4	3 Alice Mutton		7	6 20 банок по 1 кг	1755
5	4 Carnan/on Tigers		7	8 16 кг упаковка	2812 5	—
6	5 Teatime Chocolate Biscuits		8	3 10 коробок по 12 шт	414
7	6 Sir Rodney’s Marmalade		8	3 30 коробок	3645
8	7 Str Rodney’s Scones		8	3 24 упаковки по 4 шт	450
9	8 Gustafs Knackebrod		9	5 24 упаковки по 500 г	945	1
10	9 Tunnbrod		9	5 12 упаковок по 250 г	405
м < > н	\лист1/ ЛИСТ2 Z ЛистЗ /			bi	I	► г
Готово					мим
Рис. 18.4. Данные, полученные из таблицы Товары базы данных Борей
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
493
Передача данных DDE-серверу
Как и все диалоги, обмен между DDE-клиентом и DDE-сервером может выполняться в обе стороны. Это означает, что приложение-клиент также может посылать данные серверу, используя метод DDEPoke:
СИНТАКСИС:
DDEPoke(Channel, Item, Data)
Как обычно, Channel — номер канала, возвращаемый методом DDEInitiate; аргумент Item — строка, определяющая элемент сервера, куда вы хотите послать данные. Аргумент Data — данные, которые вы хотите послать; данные должны быть либо простым текстом, либо числами. Метод DDEPoke возвращает результат типа Boolean, который указывает, успешно ли выполнена операция.
В листинге 18.6 приведен пример использования метода DDEPoke.
Листинг 18.6. Применение DDEPoke для передачи данных приложению-серверу
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Sub SendDataToServer()
' Передает данные приложению-серверу (Word)
Dim ddeChannel As Integer
Dim PokeData As Object
On Error GoTo DDE_Error
' открыть документ (см. листинги 18.2, 18.3):
Shell PathName:="E:\Program Files\Microsoft Office\OfficelO" ”\Winword.exe", Windowstyle:“vbMinimizedNoFocus ddeChannel = DDEInitiate(App:“"WinWord", Topic:“"System") DDEExecute Channel:“ddeChannel, _
String:="[FileOpen ""F:\VB_books\DBMS\01.DOC""]" DDETerminate ddeChannel
' открыть DDE-канал с "предметом" - документ: ddeChannel = DDEInitiate(App:“"Winword", _ Topic:“"F:\VB__books\DBMS\01.DOC")
1 перейти в конец документа:
DDEExecute Channel:“ddeChannel, String:="[EndOfDocument]" ' вставить новый абзац:
DDEExecute Channel:“ddeChannel, String:="[InsertPara]" 'создать закладку:
DDEExecute Channel:“ddeChannel, _
String:="[EditBookmark .Name = ""NewBookmark""]"
' подготовить передаваемые данные:
With Worksheets("Лист1")
If .Cells (1, 1).Value = Then
.Cells(1, 1).Value = "Просто - текст!" End If ' отправляемые серверу данные: Set DDEPokeData = .Cells(1, 1)
End With
1 послать данные в место, отмеченное закладкой:
Application.DDEPoke Channel:“ddeChannel, _ Item:“"NewBookmark",
494
Глава 18
41	Data:=DDEPokeData
42	DDETerminate ddeChannel
43
44	Exit Sub
45
46	DDE_Error:
47	DDETerminate ddeChannel
48
49	End Sub
Процедура SendDataToServer передает данные (строки 39-41) из ячейки листа Excel (строки 30-36) в место Word-документа, которое отмечено закладкой, предварительно созданной самой же процедурой (строки 22-27).
Передача «нажатий клавиш» другому приложению
К сожалению, существуют много приложений Windows, которые не поддерживают Automation и не имеют макроязыка, с помощью которого можно управлять приложением через DDE-канал. Казалось бы, такими приложениями невозможно управлять из VBA-кода. Однако здесь — «не все так плохо». Этим приложениями можно управлять «нажатиями клавиш».
В общем-то, многие приложения имеют команды (функции), имитирующие «нажатия клавиш», что очень полезно при отладке приложений или создания демонстрационных версий программ. При этом коды «нажатых клавиш» заранее записываются в некоторый буфер (хотя, конечно, это можно делать и в момент выполнения приложения), а затем извлекаются из него при помощи операторов, имитирующих «нажатия клавиш».
В рассматриваемом нами случае управляемое приложение не само генерирует «нажатия клавиш», а получает их от приложения, которое является управляющим, при помощи VBA оператора SendKeys. Вы можете послать любую клавишу или комбинацию клавиш (в том числе такие комбинации, которые включают клавиши Alt, Ctrl и Shift) приложению-серверу DDE. Результат будет точно таким же, как если бы вы нажали эти клавиши непосредственно на клавиатуре. Оператор SendKeys имеет следующий синтаксис:
СИНТАКСИС
SendKeys (String [,Wait])
Аргумент String — это клавиша или комбинация клавиш, которую необходимо послать активному приложению. Для символов, чисел и знаков препинания следует заключить этот символ в кавычки, например "а". Для других клавиш используйте строки, перечисленные в таблице 18.2.
Необязательный аргумент Wait — это значение типа Boolean, указывающее, будет или не будет VBA ждать, когда переданные приложению «нажатия клавиш» будут им обработаны. Если аргумент Wait имеет значение True, VBA «ждет», пока приложение закончит обработку переданных клавиш, прежде чем перейти к следующему оператору процедуры; в ином случае VBA продолжает выполнять процедуру (в которой появляется SendKeys), не ожидая завершения обработки.
Для того чтобы использовать SendKeys, нет необходимости устанавливать DDE-связь. Все, что нужно сделать — активизировать программу, используя функцию Shell или AppActivate. После этого можно посылать любые «нажатия
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
495
клавиш», которые необходимы. Например, вы можете закрыть любое активное приложение Windows, послав комбинацию клавиш Alt+F4 следующим образом:
SendKeys String:="%{F4}"
Таблица 18.2. Строки, используемые в качестве аргумента String в методе SendKeys
Клавиши	Коды
BACKSPACE	{BACKSPACE}, {BS} или {BKSP}
BREAK	{BREAK}
CAPS LOCK	{CAPSLOCK}
DEL или DELETE	{DELETE} или {DEL}
DOWN ARROW	{DOWN}
END	{END}
ENTER	{ENTER} или -
ESC	{ESC}
HELP	{HELP}
HOME	{HOME}
INS или INSERT	{INSERT} или {INS}
LEFT ARROW	{LEFT}
NUM LOCK	{NUMLOCK}
PAGE DOWN	{PGDN}
PAGE UP	{PGUP}
PRINT SCREEN	{PRTSC}
RIGHT ARROW	{RIGHT}
SCROLL LOCK	{SCROLLLOCK}
TAB	{TAB}
UP ARROW	{UP}
Fl	{Fl}
F2	{F2}
F3	{F3}
F4	{F4}
F5	{F5}
F6	{F6}
F7	{F7}
F8	{F8}
F9	{F9}
F10	{F10}
Fll	{Fll}
496
Глава 18
Клавиши	Коды
F12	{F12}
F13	{F13}
F14	{F14}
F15	{F15}
F16	{F16}
Комбинируя клавиши из таблицы 18.2 с клавишами Alt, Ctrl и Shift, вы можете создать любую комбинацию клавиш. Для этого поставьте перед строкой из таблицы 18.2 одну или большее количество кодов, перечисленных в таблице 18.3.
Таблица 18.3. Коды для клавиш Alt, Ctrl и Shift
Клавиша	Знак
SHIFT	+
CTRL	
ALT	%
В листинге 18.7 приведен пример1 передачи «нажатия клавиш» программе Calculator при помощи функции SendKeys.
Листинг 18.7. Использование функции SendKeys
1	Sub SendTestO
2	1 Запускает программу Calculator и передает ей "нажатия клавиш"
3
4	Dim MyAppID, I
5	MyAppID = Shell("CALC.EXE", 1) ’ запуск программы Calculator
6	AppActivate MyAppID	' активизация программы Calculator
7
8	For I = 1 To 50
9	' послать в программу Calculator цифру и знак "+"
10	SendKeys I & "{+}", True
11	Next
12
13	SendKeys "=", True ' получить результат
14
15
16 End Sub
Доступ к DLL из Visual Basic for Applications
Библиотеки динамической компоновки (Dynamic link libraries, DLL) — это наборы функций и процедур, которые доступны всем приложениям Windows. Windows поставляется с набором DLL-файлов, которые предоставляют разработчикам сотни специализированных (и очень быстрых) функций. Обращение к этим процедурам — простой путь придать вашим VBA-программам исключительную функциональность Windows. Совокупность DLL-библиотек формирует то, что известно
1
Пример взят из справочной системы.
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»497
как Application Programming Interface (API) Windows (интерфейс прикладных программ Windows).
API-функции условно делятся на четыре основные категории: для работы с приложениями (запуск и закрытие, обработка команд меню, перемещение и изменение размеров окон), для управления графическими изображениями, для использования системной информации (определение текущего диска, объема памяти, пользователя и т.д.), для работы с реестром Windows).
Хотя большинство функций API сложны в техническом отношении, вы можете воспользоваться несколькими из них в своих VBA-процедурах. В следующих разделах показано, как обращаться к библиотекам DLL из VBA-кода.
Объявление DLL-процедур
Прежде чем вы сможете использовать функцию из библиотеки DLL, вы должны сообщить VBA, где найти DLL-файл и какие аргументы нужны этой функции. Для этого следует ввести оператор Declare на уровне модуля, то есть перед любыми объявлениями процедур в модуле. В зависимости от того, является ли процедура функцией (Function) или подпрограммой (Sub), используйте одну из следующих форм:
СИНТАКСИС
Declare [Pubic I Private] Function Name Lib "LibName" [Alias AliasName] (Arguments) [As Type]
Declare [Pubic I Private] Sub Name Lib "LibName" [Alias AliasName] (Arguments) [As Type]
Так же как с переменными и константами VBA, вы можете объявить DLL-процедуру либо как Public (чтобы сделать ее доступной всем модулям во всех проектах), либо как Private (чтобы сделать ее доступной только тому модулю, в котором она объявлена).
Name — имя процедуры; LibName — имя DLL-файла, например "USER32". Если имя процедуры совпадает с ключевым словом VBA или с именем переменной, объявленной как Public, вы не сможете использовать оригинальное имя процедуры в своем коде. Вместо этого используйте AliasName (псевдоним) для определения другого имени процедуры.
Arguments — это список аргументов, требующихся процедуре. Этот список имеет следующий синтаксис:
СИНТАКСИС
[Optional][ByVai|ByRef][ParamArray] VarName [As Type]
Ключевое слово Optional указывает на то, что аргумент не является обязательным. Ключевое слово ByVai означает, что аргумент передается по значению (для большей части DLL-процедур). Ключевое слово ByRef означает, что аргумент передается по ссылке. ParamArray используется с массивами данных типа Variant. Аргумент, объявленный как ParamArray, должен быть последним в списке аргументов; нельзя использовать ParamArray в комбинации с Optional, ByVai или ByRef. VarName — имя аргумента, а Туре определяет тип данных аргумента.
Следующий оператор, например, объявляет функцию с именем MessageBeep из DLL User32.exe* 1:
1 Когда имя DLL-файла заканчивается цифрами 32, это означает, что DLL содержит 32-разряд-иый код. Каждый раз, когда у вас есть выбор, вы должны использовать в своем VBA-коде 32-разрядные версии любой библиотеки DLL.
498
Глава 18
Declare Sub MessageBeep Lib "USER32" (ByVai BeepType As Integer)
Сразу после объявления процедуры DLL, вы можете использовать ее в VBA-коде, как любую другую процедуру (Sub или Function).
Примеры DLL
В этом разделе приведены несколько примеров того, г£ак использовать DLL процедуры в VBA-коде. Чтобы узнать больше о DLL и API Windows, вы можете приобрести книгу Джеймса Маккорда (James McCord) Win32 API Desktop Reference. Эта книга полностью освещает данный предмет.
VBA имеет простой оператор Веер, который вы можете использовать для привлечения внимания пользователя. К сожалению, Веер выдает только одиночный звук. В большинстве случаев это не является проблемой, но существует достаточное количество ситуаций, когда вы захотите преодолеть эти ограничения. Например, после завершения долгой операции вы можете привлечь внимание пользователя к экрану звуковым сигналом. Но как быть, если во время этой операции произошла ошибка? Было бы хорошо иметь другой звук, сопровождающий сообщения об ошибках.
Если различные звуки — это то, что вам нужно, используйте DLL-процедуру MessageBeep, которая позволяет воспроизводить пять отдельных звуковых сигналов. Чтобы воспользоваться преимуществами MessageBeep, вы или пользователи вашей VBA-программы должны иметь звуковую плату, которая поддерживается Windows.
DLL-библиотека User32, которая содержит процедуру MessageBeep, находится в файле с именем User32.dll в каталоге \Windows\System. Этот файл поставляется вместе с Windows. В дополнение к MessageBeep библиотека User32.dll содержит другие полезные функции и процедуры, которые являются частью стандартного 32-разрядного API Windows. Чтобы получить полную информацию относительно функций и процедур User32.dll, воспользуйтесь документацией Win32 Software Developer's Kit (Комплект разработчика программного обеспечения Win32).
Оператор Declare, объявляющий функцию MessageBeep:
Declare Sub MessageBeep Lib "USER32" (ByVai BeepType as Long)
Аргумент BeepType принимает одно из пяти значений, приведенных в табл. 18.4.
Таблица 18.4. Значения аргумента BeepType
BeepType	Звук
0	Default beep (Сигнал по умолчанию)
16	Critical stop (Аварийная остановка)
32	Question (Вопрос)
48	Exclamation (Восклицание)
64	Asterisk (Сноска)
Все эти звуки определены в значке Sounds (Звуки) в Control Panel (Панели управления). В листинге 18.8 приведена процедура, которая последовательно воспроизводит все пять звуков, предварительно помещая в строку состояния (для Excel) наименования этих звуков.
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
499
Листинг 18.8. Применение DLL-процедуры MessageBeep
1	Option Explicit
2
3	Const DefaultBeep = 0
4	Const CriticalBeep = 16
5	Const QuestionBeep = 32
6	Const ExclamationBeep =48
7	Const AsteriskBeep = 64
8
9	Declare Sub MessageBeep Lib "USER32" (ByVai BeepType As Long) 10
11	Sub BeepTest()
12	' Воспроизводит звуки посредством MessageBeep
13
14	Application.StatusBar = "Default Beep"
15	MessageBeep DefaultBeep
16 Application.Wait Now + TimeValue("00:00:03")
17
18	Application.StatusBar = "Critical Stop"
19	MessageBeep CriticalBeep
20 Application.Wait Now + TimeValue("00:00:03")
21
22	Application.StatusBar = "Question"
23	MessageBeep QuestionBeep
24	Application.Wait Now + TimeValue("00:00:03")
25
26	Application.StatusBar = "Exclamation"
27	MessageBeep ExclamationBeep
28	Application.Wait Now + TimeValue("00:00:03")
29
30	Application.StatusBar - "Asterisk"
31	MessageBeep AsteriskBeep
32	Application.Wait Now + TimeValue("00:00:03")
33
34
35 Application.StatusBar = False
36
37 End Sub
Конкретные звуки, которые будет воспроизводить процедура BeepTest, зависят от конфигурации вашего компьютера. Если вы не установили все звуковые файлы, поставляемые с Windows, вы можете услышать только один или два различных звука для всех вариантов, которые должна воспроизводить процедура BeepTest. Вы можете заменить звуки, которые Windows воспроизводит для таких событий, как Asterisk, Question и других, запустив апплет Sounds (Звуки) в Control Panel (Панели управления).
Функция CharToOemA конвертирует текстовую строку из Win- в DOS-кодировку. Оператор Declare, объявляющий функцию CharToOemA:
Declare Function CharToOemA Lib "user32" (ByVai IpszSrc As String, _ ByVai IpszDst As String) As Long
Аргумент IpszSrc — строка в Win-кодировке, IpszDst — строка в DOS-кодировке.
В листинге 18.9 содержится код, преобразующий строку из Win- в DOS-кодировку с последующей записью результата в текстовый файл TESTFILE. Этот файл можно прочитать только в системе DOS. В Windows текст будет представлять примерно такую строку "Z iai - 0¥а !" — это можно проверить в окне Immediate, включив в код строку Debug.Print DOSString.
500
Глава 18
Листинг 18.9. Применение DLL-процедуры CharToOemA
1	Option Explicit
2
3	Declare Function CharToOemA Lib "user32" _
4	(ByVai IpszSrc As String, _
5	ByVai IpszDst As String) As Long
6	•
7	Sub CharToOemATest()
8	' Тестирует функцию CharToOemA
9
10	Dim WinString As String
11	Dim DOSString As String
12	Dim code As Long
ДЗ
14	WinString = "Опять - весна!" 'Строка	в Win-кодировке
15	DOSString = Space(Len(WinString))
16	code = CharToOemA(WinString, DOSString)
17	Open "TESTFILE" For Output As #1
18	Write #1, DOSString
19	Close #1
20
21	End Sub
В листинге 18.10 содержится код, преобразующий строку из DOS- в Win-кодировку с использованием функции OemToCharA. Данные для тестирования этой функции считываются из текстового файла TESTFILE (строки 9-12), который был записан кодом листинга 18.9. Для проверки того, что текст действительно записан в DOS-кодировке, он печатается в окне Immediate (строка 18). Преобразованная функцией OemToCharA строка снова печатается (строка 18) в окне Immediate (рис. 18.5).
	Листинг 18.10. Применение DLL-процедуры OemToCharA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27	Sub OemToCharATest() ' Тестирует функцию OemToCharATest Dim DOSString As String Dim WinString As String Dim code As Long ' открыть текстовый файл в DOS-кодировке: Open "TESTFILE" For Input As #1 ' считать строку из файла:	t Input #1, DOSString ' закрыть файл: Close #1 ' убедиться в том, что данные нечитабельны: Debug.Print DOSString ' конвертировать в Win-кодировку: WinString = Space(Len(DOSString)) code = OemToCharA(DOSString, WinString) ' проверить результат: Debug.Print WinString End Sub
Работа с другими приложениями: DDE, DLL и передача «нажатий клавиш»
501
Рис. 18.5
Считанная из файла и преобразованная строки печатаются в окне Immediate
Функция Sleep приостанавливает выполнение программы на определенное аргументом время. Оператор Declare, объявляющий функцию Sleep:
Declare Sub Sleep Lib "kernel32.dll" (ByVai dwMilliseconds As Long)
Аргумент dwMilliseconds — количество миллисекунд для приостановки выполнения программы.
В листинге 18.11 приведен пример использования функции Sleep, хотя наилучшим примером было бы применение этой функции при работе с различного рода строками состояния: помещаете в строку состояния некоторый текст, выполняете «засыпание» приложения, чтобы пользователь успел прочитать текст, а затем убираете запись из строки состояния.
Листинг 18.11. Применение DLL-процедуры Sleep
1	Option Explicit
2
3	Declare Sub Sleep Lib "kernel32.dll" (ByVai dwMilliseconds As Long) 4
5	Sub SleepTestO
6	' Тестирует функцию Sleep
7
8	If MsgBox("Поспим	секунд пять?", _
9	vbQuestion + vbYesNo,	"Тест функции Sleep") = vbYes Then
10	Sleep 5000
11	MsgBox "Поспали!"
12	Else
13	MsgBox "Как хотите	..."
14	End If
15
16	End Sub
В качестве следующего примера DLL-функции рассмотрим GetWindowsDi-rectory, которая определяет путь к папке Windows. Это удобно, если вам нужно выяснить, в какую папку установлена Windows или где расположен один из вспомогательных апплетов Windows. Функция GetWindowsDirectory объявляется следующим образом:
502
Глава 18
СИНТАКСИС
Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "GetWindowsDirectoryA" _
(ByVai Buffer As String, _ ByVai Size As Long) As Long
Аргумент Buffer — строковая переменная, в которую GetWindowsDirectory помещает путь к папке Windows. Вы должны обеспечить такую длину передаваемой строки, чтобы в нее мог уместиться достаточно длинный путь, поскольку библиотеки DLL не могут увеличивать длину переданных им строк. Если строка не имеет достаточной длины, чтобы уместить путь папки, то строка, возвращаемая в аргумент Buffer, может испортить память, не зарезервированную для использования VBA. Последствия этого будут самыми неприятными: от ошибки General Protection Fault (Общая неисправность защиты) до аварийного отказа системы. Аргумент Size — максимальный размер буфера. Вы можете использовать функцию Len для определения длины переменной буфера и использовать результат как аргумент Size.
Функция GetWindowsDirectory возвращает длину строки пути, скопированную в Buffer.
В листинге 18.12 приведен пример использования функции GetWindowsDirectory для поиска и запуска апплета Sol.
Листинг 18.12. Применение функции DLL GetWindowsDirectory
1 Option Explicit
2
3 Declare Function GetWindowsDirectory Lib "kernel32" _
4	Alias "GetWindowsDirectoryA" _
5 (ByVai Buffer As String, _
6	ByVai Size As Long) As Long
7
8 Sub LaunchWordPad()
9 ' Запускает апплет sol
10
11 Dim WinDir As String * 255
12	Dim DirLength As Long
13	Dim FullName As String
14
15	DirLength = GetWindowsDirectory(Buffer:=WinDir,	_
16	Size:=Len(WinDir))
17
18	If DirLength = 0 Then
19	MsgBox "Невозможно определить Windows-папку!"
20	Else
21	FullName = Left(WinDir, DirLength) & _
22	"\system32\dllcache\sol.exe"
23	1 11 запустить апплет Sol:
24	Shell PathName:=FullName, WindowStyle:=vbMaximizedFocus
25 End If
26
27 End Sub
Глава 19
Использование обработчиков событий
Как вы видели из этой книги, Visual Basic for Applications имеет достаточно способов для запуска процедур. Вы можете запустить процедуру из диалога Макрос (Macro), нажатием «быстрой» клавиши, выбором собственной команды меню или кнопки в панели инструментов.
Общая особенность этих методов состоит в том, что вы должны что то сделать, чтобы выполнить процедуру: выбрать команду меню, нажать комбинацию клавиш или щелкнуть кнопку в панели инструментов. VBA также имеет несколько методов, которые дают возможность создавать процедуры, выполняющиеся автоматически в ответ на некоторое событие, например открытие рабочей книги или документа. В этой главе рассматриваются эти автоматические подпрограммы.
События и обработчики событий
Ранее в этой книге вы познакомились с концепцией обработчика события и управляемого событиями программирования. В частности, в главе 14 вы узнали, как создавать обработчики событий для элементов управления, помещенных в форму пользователя. В этой главе вы узнаете, как создавать обработчики для событий, связанных с различными объектами host-приложения VBA. Однако сначала полезно будет сделать обзор некоторых фактов, относящихся к управляемым событиями программам и обработчикам событий.
Управляемая событиями (event-driven) программа — это такая программа, которая вместо линейного выполнения кода от начала до конца циклически выполняет некоторый код, ожидая различные события и отвечая на них. Событие (event) — это то, что происходит в программе, например нажатие определенной клавиши, щелчок мыши, активизация рабочего листа, открытие или закрытие файла документа или рабочей книги. Поскольку во время выполнения программой заданного алгоритма происходят определенные события, считается, что программа управляется этими событиями, и отсюда следует термин управляемая событиями. Когда происходит событие, программа выполняет одну или несколько процедур, связанных с этим событием. Эти процедуры обычно упоминаются как обработчики событий (event handlers) или процедуры обработки событий (event procedures).
Вы уже знаете, что объекты Excel и Word предоставляют доступ к их свойствам и методам, что позволяет управлять ими в VBA-коде. Небольшое количество объектов также делают видимыми некоторые события, например двойной щелчок мыши или открытие и закрытие файла. Вы можете создать свою собственную управляемую событием процедуру для любого события, предоставляемого объектом. Ваши обработчики событий могут (в зависимости от типа события) расширить, заменить или исключить встроенное поведение объекта для этого события. Например, вы можете лишить пользователя возможности изменять размеры окна документа, написав свой собственный обработчик события WindowResize.
Хотя приложения Microsoft, поддерживающие VBA, содержат сотни объектов, только некоторые из этих объектов предоставляют события, которые вы можете перехватить своими собственными процедурами обработки событий. Напри-
504
Глава 19
мер, список объектов Excel, предоставляющих события, которые вы можете перехватить, ограничен объектами Application, Workbook, Worksheet и Chart; в Word имеется только два таких объекта — Application и Document; в PowerPoint — только Application. Чтобы узнать, какие события предоставляются объектом (и есть ли они вообще), используйте Object Browser. События объекта приложения перечисляются в списке Members of "class” и обозначены с левой стороны значком молнии (рис. 19.1).
Рис. 19.1
События объекта приложения перечисляются в списке Members of "class" и обозначены с левой стороны значком молнии
. Object Browser
Classes
ЙЗ DefaultWebOptions
Й4 Diagram
& DiagramNode
<23 DiagramNodeChildren
ЙЗ DiagramNodes
<23 Dialog
<23 Dialogs
ЙЗ Dictionaries
& Dictionary
<23 Documents
йЗ ПгппСяп_____
Class Document
Member of W«h<I
ЙШ
Members of 'Document'
* ManualHyphenation
* Merge
!₽ Name
£ New
I® NoLineBreakAfter
й? NoLineBreakBefore
9 Open
й? OpenEncoding
eff OptimizeForWord97
e£* PageSetup
E₽ Paragraphs ’S? Parent

В дополнение к предоставленным объектами событиям вы можете также создать обработчики событий, которые отвечают на нажатие определенной комбинации клавиш или которые реагируют на наступление определенного времени дня. В Excel вы можете использовать метод ОпКеу, чтобы определить, какая процедура Excel должна выполняться в ответ на данное нажатие клавиш. Например, вы можете использовать метод ОпКеу Excel, чтобы определить, что некоторая процедура будет выполняться при каждом нажатии комбинации клавиш Ctrl+Alt+N.
В Word можно использовать коллекцию KeyBindings, чтобы связать данную процедуру с некоторой комбинацией клавиш. Как Excel, так и Word предоставляют метод OnTime, который дает возможность создать события, связанные с конкретной датой и временем дня.
Где хранится обработчик события
Обработчики событий объекта хранятся не в стандартном модуле, а в модуле класса объекта. Каждый объект Excel, такой как Workbook, Worksheet и Chart, содержит модуль класса, где вы можете сохранять обработчики событий этого объекта. Объекты Document в Word также содержат модуль класса, в котором содержатся обработчики событий этого объекта.
На рис. 19.2 показано открытое окно кода для модуля класса объекта рабочего листа в VBA Excel. Обратите внимание, что в списке объектов окна Code Window выбран объект Worksheet. В списке процедур в Code Window (на рис. 19.2 этот спи-, сок раскрыт) перечислены все события, для которых вы можете создать обработчики событий. Выбор события в списке процедур окна кода приводит к тому, что редактор VB вставляет «пустое» объявление (заголовок и оператор конца процедуры) обработчика этого события, если объявления еще не существует. На рис. 19.2 видно «пустое» объявление процедуры обработки события для события Selection-Change рабочего листа.
Использование обработчиков событий
505
Рис. 19.2
Процедуру обработки события следует создавать в модуле класса объекта
Visual Basic - Events,.ids - [Лист! (Code)]
Fie Edit Ytew Insert Format Qebug Run Tools Add Ins &ndow Help
З’Ц Й&М	U Ln5,Coll
- VBAProject (Events xls)
- *'-» Microsoft Excel Objects
О ЛиСЛ (Лист1)
И) Лист2 (Лист2)
И) ЛистЗ (ЛистЗ)
<0 ЭтаКнка
* %£ VBAProject (PERSONAL XLS)
Option Explicit
Private Sub Worksheet
End Sub
SelectionChange
' Activate
BeforeDoubleChck BeforeRightChck Calculate
Change
’ Deactivate FollowHyperhnk
Исключением из правила, где и как сохраняются обработчики событий, является объект Application. Объект Application не имеет модуля класса, где можно хранить обработчики событий. Вместо этого обработчики событий объекта Application следует сохранять в модуле класса, который вы создаете.
Чтобы отобразить на экране или создать процедуру обработки события для объектов (кроме объекта Application), выполните следующие шаги:
1.	В редакторе VB откройте Project Explorer, если оно еще отображается.
2.	В Project Explorer выберите объект, для которого хотите создать (или модифицировать) обработчик события. На рис. 19.2 выбран объект Лист1 рабочей книги Excel.
3.	В Project Explorer щелкните кнопку View Code, чтобы вывести в окне кода модуль класса выбранного объекта (см. рис. 19.2).
4.	В списке объектов окна Code Window выберите сам объект, т.е. если вы выбрали объект Worksheet (лист) в Project Explorer, вы должны выбрать пункт Worksheet в списке объектов, как показано на рис. 19.2.
5.	В списке процедур выберите процедуру обработки события, которую хотите создать или изменить. Список процедур будет содержать только те процедуры, которые соответствуют событиям, предоставляемым объектом открытого вами модуля класса.
Имена и объявление обработчиков событий
VBA связывает определенную процедуру в модуле класса объекта с конкретным событием, опираясь на имя процедуры. По этой причине обработчики событий, которые вы создаете, должны соответствовать определенным именным соглашениям, а также нескольким другим правилам объявления таких процедур.
В целом процедуры обработки событий должны иметь следующий синтаксис объявления:
СИНТАКСИС
Private Sub Object_EventName(Arguments)
Процедуры обработки событий должны объявляться как закрытые (Private) для модуля класса объекта. В этом синтаксисе Object — имя объектного типа, которому принадлежит процедура обработки события, например Арр (для объекта Application), Workbook или Document. EventName — имя события, которое будет обработано, например, BeforeSave, BeforeDoubleClick и так да
506
Глава 19
лее. Arguments — список аргументов обработчика события. Списки аргументов для обработчиков событий обсуждаются в следующем разделе.
В качестве примера можно привести строку, объявляющую процедуру для Worksheet, которая предназначена для обработки события Activate:
Private Sub Worksheet_Activate()	•
Аргументы обработчика события
Некоторые обработчики событий имеют аргументы. Обычно аргументы обработчика события выполняют одну из двух функций: передают обработчику события информацию, которая может понадобиться для обработки события, и предоставляют способ отмены встроенного в объект ответа на событие.
Например, посмотрите на следующее объявление обработчика события:
Private Sub VJcrkbook BeEoreClose (Cancel As Boolean)
Процедура, созданная в соответствии с этим объявлением, будет вызываться каждый раз при закрытии объекта Workbook. Событие BeforeClose происходит непосредственно перед закрытием рабочей книги, независимо от того, закрывается рабочая книга в вашем VBA-коде или это происходит в результате действий пользователя в интерактивном режиме Excel. Обработчик события Workbook_Before-Close будет, следовательно, выполняться непосредственно перед закрытием рабочей книги. Процедура Workbook_BeforeClose могла бы содержать код, который проверяет правильность новых введенных данных или выясняет, были ли сохранены данные рабочей книги. Если в рабочей книге существуют недопустимые или несохраненные данные, вы можете предупредить ее закрытие. Аргумент Cancel позволяет вам сделать именно это.
На тот момент, когда событие BeforeClose вызывает выполнение процедуры Workbook_BeforeClose, аргумент Cancel установлен в состояние False. Если вы устанавливаете аргумент Cancel в состояние True в некотором месте процедуры Workbook_BeforeClose, то закрытие рабочей книги будет предотвращено. Не каждая процедура обработчика события включает аргумент Cancel.
В качестве еще одного примера рассмотрим следующее объявление процедуры обработки события:
Private Sub Workbook—SheetActivate(ByVai Sh As Object)
Это объявление процедуры обработки события предназначено для события SheetActivate объекта Workbook. Событие SheetActivate происходит каждый раз, когда активизируется любой лист рабочей книги. Аргумент Sh передает ссылку на активизируемый лист (рабочий лист или диаграмму). Поскольку это событие происходит внутри рабочей книги для любого активизируемого листа, ваш обработчик события должен уметь определять, какой лист был активизирован. Аргумент Sh обеспечивает решение этой задачи.
Работа с событиями объекта Application
В предыдущем разделе было показано, что обработчики событий для отдельных объектов приложения (Workbook, Worksheet, Document и т.д.У сохраняются в модуле класса, к которому относятся эти объекты. Однако объект Application не имеет модуля класса. Следовательно, создание обработчика события для объекта Application в Excel и Word — более сложная задача. В этом разделе приведен краткий обзор того, как создать процедуру обработки события для объекта Application.
Использование обработчиков событий
507
Создание процедуры обработки события для объекта Application включает следующие основные шаги:
1.	Создайте новый модуль класса в VBA-проекте. Вы можете дать этому модулю любое имя (в Properties Window) или оставить имя, данное модулю по умолчанию.
2.	Добавьте следующее объявление в общую область модуля класса; объявление должно выглядеть точно так, как приведено ниже:
Public WithEvents Арр As Application
После того как вы введете это объявление, объект Арр появится в списке объектов модуля класса (в окне кода).
3.	Напишите код обработчиков событий для объекта Арр в модуле класса, выбирая нужное событие из списка процедур в окне кода.
4.	Свяжите процедуры обработки событий в модуле класса с объектом Application. Для этого сначала объявите переменную уровня модуля для вашего нового класса, а затем создайте процедуру, которая инициализирует эту переменную так, чтобы она ссылалась на объект Application. Вы можете создать это объявление и процедуру в любом модуле.
Предположим, что ваш модуль класса называется AppEvents. Тогда, чтобы связать процедуру обработки события в модуле класса AppEvents с объектом Application, следует использовать следующее объявление и процедуру:
Dim EventEnabledApp As New AppEvents
Sub InitializeAppEvents()
Set EventEnabledApp = Application
End Sub
На рис. 19.3 показано Code Window модуля класса Excel с именем AppEvents. Обратите внимание на то, что в общей области модуля класса видно объявление Public WithEvents Арр As Application (это объявление частично закрыто раскрывающимся списком процедур). Как только вы введете объявление переменной для объекта Арр в общую область модуля класса, в списке объектов окна кода появится объект Арр. На рис. 19.3 в списке объектов выбран объект Арр, а список процедур раскрыт и показывает, что модуль класса теперь автоматически перечисляет все события, доступные для объекта Application, точно так же, как это происходит для любого другого объекта.
Рис. 19.3
Для создания процедуры обработки событий уровня приложения, следует создать специальный модуль класса, в котором они будут храниться
508
Глава 19
Если хотите, чтобы ваши процедуры обработки событий объекта Application всегда находились в работе, следует создавать модули класса для событий объекта Application в рабочей книге Personal.xls или в шаблоне документа Normal.dot.
Работа с событиями объектов Excel
Несмотря на то, что число объектов Excel, которые предоставляют события, довольно мало, вам доступно около 50 событий. В таблице 19.1 приведен список нескольких наиболее часто используемых событий объектов Excel, объектов, к которым они относятся, и описание этих событий. Разделы, следующие после таблицы 19.1, дают конкретную информацию относительно использования наиболее важных событий, приведенных в этой таблице.
Таблица 19.1. Часто используемые события объектов Excel
Событие	Относится к	Когда происходит
Activate	Chart, Workbook, Worksheet	Когда объект активизируется VBA-кодом или действиями пользователя.
Addininstall	Workbook	Когда рабочая книга устанавливается как надстройка (add-in).
AddinU ninstall	Workbook	Когда выгружается рабочая книга-надстройка.
BeforeClose	Workbook	Перед тем, как закрывается рабочая книга и перед тем, как пользователю выдается запрос о сохранении изменений.
BeforeDoubleClick	Chart, Worksheet	При выполнении двойного щелчка внедренной диаграммы или рабочего листа, но перед заданным по умолчанию ответным действием на двойной щелчок.
BeforePrint	Workbook	Перед печатью рабочей книги или ее части.
BeforeRightClick	Chart, Worksheet	При выполнении правого щелчка внедренной диаграммы или рабочего листа, но перед заданным по умолчанию ответным действием на правый щелчок.
| BeforeSave	Workbook	Перед сохранением рабочей книги.
Calculate	Chart, Worksheet	После того как рабочий лист повторно вычислен или после рисования диаграммы по новым или обновленным данным.
Change	Worksheet	Когда свойство Value ячейки изменяется либо кодом VBA, либо в результате действий пользователя.
Deactivate	Chart, Workbook, Worksheet	Когда объект деактивизируется либо кодом VBA, либо в результате действий пользователя.
NewSheet	Workbook	При создании в рабочей книге нового листа (диаграммы или рабочего листа).
New W orkbook	Application	Когда создается новая рабочая книга.
Использование обработчиков событий
509
Событие	Относится к	Когда происходит
Open	Workbook	Когда открывается рабочая книга.
SelectionChange	Worksheet	При изменении выделенного фрагмента в рабочем листе.
SheetActivate	Application, Workbook	Когда активизируется любой лист.
SheetBefore- DoubleClick	Application, Workbook	При выполнении двойного щелчка рабочего листа, но до ответного действия по умолчанию на двойной щелчок.
SheetBefore-RightClick	Application, Workbook	При выполнении правого щелчка рабочего листа, но до ответного действия по умолчанию на правый щелчок.
SheetCalculate	Application, Workbook	Когда рабочий лист перерасчитывается или изменяются данные на диаграмме.
Sheetchange	Application, Workbook	Когда ячейка в рабочем листе изменяется пользователем или внешней связью.
SheetDeactivate	Application, Workbook	Когда лист (рабочий лист или диаграмма) деактивизируется.
SheetSelection- Change	Application, Workbook	При изменении выделенного фрагмента в рабочем листе.
Window Activate	Application, Workbook	Когда активизируется любое окно рабочей книги.
Window Deactivate	Application, Workbook	Когда деактивизируется любое окно рабочей книги.
WindowResize	Application, Workbook	При изменении размеров любого окна рабочей книги.
W orkbook Activate	Application	При активизации любой рабочей книга.
WorkbookAddin-Install	Application	Когда любая рабочая книга устанавливается как надстройка (add-in).
Workboo kAddin- Uninstall	Application	Когда выгружается любая рабочая книга-надстройка.
WorkbookBefore- Close	Application	Непосредственно перед закрытием любой рабочей книги.
WorkbookBefore-Print	Application	Непосредственно перед печатью любой рабочей книги (или ее части).
WorkbookBefore- Save	Application	Непосредственно перед сохранением любой открытой рабочей книги.
Workbook-Deactivate	Application	Когда любая открытая книга деактивизируется.
WorkbookNewSheet	Application	При создании в любой открытой рабочей книге нового листа (рабочего листа или диаграммы).
WorkbookOpen	Application	При открытии рабочей книги.
510
Глава 19
Событие Open
Для правильного функционирования большинства VBA-программ приходится вносить некоторые изменения в среду host-приложения. Эти изменения могут включать добавление специальных команд меню, отображение специальной панели инструментов или установку опций host-приложения. В большинстве случаев эти изменения host-приложения должны быть сделаны сразу после запуска пользователем вашей VBA-программы, чтобы ее команды меню и панели инструментов были доступны с самого начала работы программы.
Если вы хотите, чтобы ваша VBA-программа хорошо воспринималась, вы не должны перекладывать на пользователя работу по добавлению меню, линеек инструментов или по изменению состояния опций. Вы должны автоматически выполнить эти корректировки при запуске с помощью обработчика события Open рабочей книги. Событие Open генерируется каждый раз, когда открывается рабочая книга. Следовательно, код вашего обработчика события Open будет выполняться при каждом открытии рабочей книги, что дает идеальную возможность для установки любых специальных условий, необходимых для данной рабочей книги.
Некоторые из элементов, которые вы можете включить в процедуру обработчика события Open, перечислены ниже:
	Код, который устанавливает или настраивает панель команд, чтобы создать меню и панели инструментов вашей VBA-программы.
	Такие установки программы, как режим вычислений, заданный по умолчанию путь файла, стандартный шрифт, объекты, которые будут выведены на экран (включая строку состояния и строку формул).
	Инициализация обработчиков событий ОпКеу и OnTime.
	Специальный диалог для установки опций вашей программы.
Разумеется, вы можете включить любое другое действие, если вам нужно, чтобы оно выполнялось при каждом открытии рабочей книги.
В листинге 19.1 показан пример процедуры обработки события Open.
Для того чтобы процедура Workbook_Open из листинга 19.1 работала правильно, вы должны ввести ее в модуль класса объекта ThisWorkbook. В редакторе VB откройте Project Explorer и раскройте папку Microsoft Excel Objects, чтобы увидеть элемент ЭтаКнига (ThisWorkbook). Выполните двойной щелчок элемента ЭтаКни-га, чтобы вывести Code Window для модуля класса объекта ЭтаКнига. Затем выберите рабочую книгу в списке объектов окна кода и выберите в списке процедур пункт Open. Редактор VB автоматически введет объявление процедуры события Open; после этого вы можете ввести код из листинга 19.1.
Листинг 19.1. Применение события Open рабочей книги
1	Private Sub Workbook_Open()
2	' Запускается при каждом открытии рабочей книги
3
4	Application.StatusBar	= "Загрузка VBA приложения..."
5	,
6	' Инициализация среды
7	With Application
8	.AlertBeforeOverwriting = True
9	.Calculation = xlManual
10	.Caption = "Ореп-тест!"
11	.DisplayRecentFiles = False	,
12	.MoveAfterReturn = False
13	.PromptForSummarylnfo = False
14	.SheetsInNewWorkbook = 8
15	.UserName = InputBox(prompt:^"Введите ваше имя:", __
16	Title:="Событийная процедура открытия файла",
Использование обработчиков событий
511
17	Default:=.UserName)
18	End With
19
20	' Отобразить панель инструментов	WordArt
21	With Application.CommandBars("WordArt")
22	.Visible = True
23	.Position =	msoBarFloating
24	.Left = 400	.
25	.Top = 200
26	End With
27	Application.StatusBar = False
28
29	End Sub
Процедура обработки события Open рабочей книги начинается с обращения к свойству StatusBar объекта Application для отображения в строке состояния сообщения, информирующего пользователя о том, что происходит (строка 4). Вы можете использовать свойство StatusBar в любой процедуре. Это — более простой способ информирования пользователя и не такой навязчивый, как функция MsgBox.
Строки 7-18 содержат оператор With, который устанавливает несколько свойств объекта Application Excel. Большинство из этих свойств доступно в диалоге Параметры (Options); вы могли бы использовать команду Сервис | Параметры (Tools | Options), чтобы установить эти свойства вручную. Однако свойство Caption (строка 10) отличается от других свойств. Оно управляет текстом, который появляется в заголовке главного окна host-приложения. В Excel, например, обычно появляется текст Microsoft Excel, но вы можете заменить его любым другим текстом.
В строках 15-17 устанавливается имя пользователя файла при помощи функции InputBox (рис. 19.4).
Рис. 19.4
При открытии Excel-файла событийная процедура запрашивает имя пользователя
Следующий оператор With (строки 21-26) отображает и позиционирует панель инструментов WordArt (рис. 19.5). Процедура заканчивается установкой свойства StatusBar в состояние False (строка 27), что очищает сообщение в строке состояния и возвращает управление строкой состояния Excel.
Рис. 19.5
При открытии Excel-файла событийная процедура выводит на экран панель WordArt
файл Правка Вид
Вставка Фориат Сервис Данные Окно Оправка
В1 Орел-тест! - Events
Готово
NUM
512
Глава 19
Для того чтобы Excel не выполнял процедуру обработки события Workbo-ok_Open, удерживайте нажатой клавишу Shift во время открытия рабочей книги.
Событие BeforeClose
Когда вы закрываете рабочую книгу, вам может понадобиться вернуть среду приложения Excel в исходное состояние, особенно в тех случаях, когда процедура Workbook_Open добавила команды меню или панели инструментов. Чтобы упростить эту работу, вы можете создать обработчик события Workbook_BeforeClose. Событие BeforeClose происходит непосредственно перед закрытием рабочей книги. В листинге 19.2 показан пример процедуры Workbook_BeforeClose.
-	Листинг 19.2. Применение события BeforeClose рабочей книги
1	Private Sub Workbook_BeforeClose(Cancel As Boolean)
2	' Выполняется перед закрытием рабочей книги
3
4	Dim answ
5
6	answ = MsgBox("Вы действительно хотите закрыть книгу?", _
7	vbCritical + vbYesNo, "Выход из Excel")
8
9	If answ = vbNo Then
10	Cancel = True 'отменить закрытие книги
11	End If
12
13	Application.StatusBar	=	"Отмена	установок	пользователя..."
14
15	' Вернуть Excel-среду	в	исходное	состояние
16	With Application
17	.Caption = Empty
18	.DisplayRecentFiles = True
19	.RecentFiles.Maximum = 5
20	.Calculation = xlAutomatic
21	.MoveAfterReturn = True
22	.PromptForSummarylnfo = True
23	.SheetsInNewWorkbook = 3
24	.CommandBars("WordArt").Visible = False
25	End With
26
27	' сохранить новые	установки	рабочей книги	4
28	ThisWorkbook.Save
29	Application.StatusBar	=	False
30
31 End Sub
Эта процедура «сбрасывает» многие параметры среды, которые изменились в предыдущей процедуре обработчика события Workbook_Open (строки 16-25). Обратите внимание, что в строке 17 свойству Caption присваивается значение Empty. Присвоение специального значения Empty свойству Caption восстанавливает заголовок главного окна оригинального приложения. Поскольку эта процедура изменяет параметры рабочей книги (набор опций, установленных этим кодом, сохраняется вместе с рабочей книгой), строка 28 сохраняет рабочую книгу перед ее закрытием; в ином случае Excel выведет сообщение, спрашивающее пользователя, нужно ли сохранять изменения в рабочей книге.
Обратите внимание на то, что процедура Workbook_BeforeClose имеет аргумент Cancel. Вы можете отменить закрытие рабочей книги, установив Cancel в состояние True (строка 10).
Использование обработчиков событий
513
Событие Activate
Процедура Workbook_Open, приведенная ранее в этой главе, полезна для установки меню из VBA-программы, панелей инструментов и глобальных параметров, используемых каждой рабочей книгой и рабочим листом. Однако во многих программах, которые используют несколько рабочих книг и несколько листов в каждой рабочей книге, требуются различные установки для каждой рабочей книги и каждого листа. Например, у вас может возникнуть необходимость отображать специальный диалог ввода данных каждый раз, когда пользователь выбирает определенный рабочий лист. В другой ситуации вам может понадобиться настроить меню или вывести другую панель инструментов, когда пользователь переходит в определенную рабочую книгу.
В этих случаях пользователь активизирует различные объекты: рабочие листы и рабочие книги. Активизация определенного объекта — это событие, и вы можете перехватывать такое событие, написав процедуру обработчика события Activate. Событие Activate доступно для объектов Chart, Workbook и Worksheet и происходит каждый раз, когда объект активизируется независимо от того, происходит это в VBA-коде или в результате взаимодействия пользователя с Excel. Объект активизируется тогда, когда он отображается в активном окне.
В листинге 19.3 показан пример использования события Activate. Запись этой процедуры в модуль класса листа с именем Лист1 приведет к тому, что при активизации этого листа пользователю выдается предупреждение о том, что лист содержит важные данные.
Листинг 19.3. Применение события Activate рабочего листа
1	Private Sub Worksheet_Activate()
2	' Выполняется при каждой активизации листа Лист1
3
4	MsgBox prompt:="Важные данные! " & Chr(13) & Chr(10) &
5	"Перед изменением убедиться в наличии копии", _
6	Title:="Внимание"
7
8	End Sub
Событие Deactivate
Как вы видели ранее в этой главе, обработчик события BeforeClose полезен для отмены любых изменений, сделанных в среде Excel обработчиком события Open. Точно так можно использовать событие Deactivate для создания обработчика события, который восстанавливает меню, проверяет правильность данных или выполняет другие задачи, когда деактивизируются объекты Worksheet, Chart или Workbook. Событие Deactivate происходит каждый раз, когда объект прекращает отображаться в активном окне.
Листинг 19.4 показывает пример процедуры обработчика события Deactivate.
Листинг 19.4. Применение события Deactivate рабочего листа
1	Option Explicit
2
3	Private Sub Worksheet_Activate()
4	' Подготовить лист Счет к использованию
5	With Application.CommandBars("PivotTable")
6	.Visible = True
7	.Left = 100
8	.Top = 200
17 Программирование на VBA 2002
514
Глава 19
9	End With
10	End Sub
11
12
13	Private Sub Worksheet_Deactivate()
14	' Удалить панель инструментов, выведенную для листа Счет
15	With Application.CommandBars("PivotTable")
16	.Visible = False	,
17	End With
18	End Sub
Листинг 19.4 содержит законченный модуль класса объекта Worksheet. Процедура Worksheet_Activate (строки 3-10) — это обработчик события Activate рабочего листа; он имитирует установку специальных условий для рабочего листа, отображая панель инструментов Pivot Table.
Строки 13-18 содержат процедуру Worksheet_Deactivate, которая является обработчиком события Deactivate рабочего листа. Процедура Worksheet_De-activate предназначена для удаления любой специальной конфигурации, примененной процедурой обработчика события Activate. В данном случае процедура Worksheet_Deactivate просто скрывает панель инструментов Pivot Table.
Не следует использовать объекты ActiveWorkbook или ActiveSheet внутри процедуры обработки события Deactivate. Excel переключится на новую рабочую книгу или лист до того, как выполнит процедуру обработки события. Следовательно, любой код, который ссылается на активную рабочую книгу или активный лист, может быть выполнен неправильно.
Событие BeforeDoubleClick
Двойной щелчок мыши в Excel приводит к различным результатам в зависимости от объекта, на котором выполняется щелчок. Например, двойной щелчок ячейки активизирует редактирование «по-месту» содержимого ячейки, а двойной щелчок диаграммы отображает диалог Формат области диаграммы (Format Chart). Любое из этих действий может быть «опасным», поскольку оно дает пользователю возможность редактировать ячейки или объекты, которые, быть может, не должны редактироваться. Чтобы перехватывать двойные щелчки в объектах Worksheet или Chart, вы можете использовать событие BeforeDoubleClick. Событие BeforeDoubleClick происходит непосредственно перед тем, как объект должен выполнить встроенный код в ответ на событие двойного щелчка.
Событие BeforeDoubleClick содержит два аргумента: Target и Cancel. Используйте аргумент Target (ссылка на Excel-объект Range), чтобы определить, в какой ячейке рабочего листа был выполнен двойной щелчок. Аргумент Cancel используется для отмены встроенного кода объекта в ответ на событие двойного щелчка. В листинге 19.5 показан пример обработчика события BeforeDoubleclick для объекта рабочего листа, который использует оба доступных аргумента.
Листинг 19.5. Применение события BeforeDoubleClick рабочего листа
1	Private Sub Worksheet_BeforeDoubleClick( _
2	ByVai Target As Excel.Range, Cancel As Boolean)
3	' Предотвращает редактирование ячеек в нечетных столбцах и строках 4
5	With Target
6	If ((.Column Mod 2) < 0) Or _
7	((.Row Mod 2)	0) Then
8	MsgBox prompt:“"Нельзя редактировать данные " & _
9	"в нечетных колонках и строках!",
10	Title:“"Демонстрация обработки BeforeDoubleClick"
Использование обработчиков событий
515
11	Cancel = True
12	End If
13	End With
14	End Sub
Листинг 19.5 содержит только одну процедуру, которая является обработчиком события BeforeDoubleClick рабочей книги. Строки 1 и 2 содержат объявление процедуры Worksheet_BeforeDoubleClick (объявление было записано с символом продолжения оператора, чтобы оно уместилось в формат страницы этой книги). Обратите внимание на то, что процедура имеет два аргумента: Target и Cancel. Эти аргументы передаются автоматически объектом Worksheet, когда выполняется процедура обработки события. Аргумент Target —ссылка на ячейку, в которой был выполнен двойной щелчок мыши, а аргумент Cancel сохраняет значение типа Boolean, указывающее на то, необходимо ли, чтобы объект Worksheet игнорировал свой встроенный обработчик события двойного щелчка.
В строке 5 начинается оператор With, который использует объектную переменную Target. В строках 6 и 7 содержится условное выражение оператора If, который проверяет, является ли номер строки или столбца ячейки нечетным числом. (Оператор Mod возвращает остаток операции целочисленного деления; если после деления на 2 имеется остаток, то данное число является нечетным.) Если номер столбца или строки ячейки — нечетное число, в строках 8-10 вызываются функция MsgBox, которая выводит сообщение, объясняющее, почему редактирование «по месту» содержимого ячейки не будет происходить.
Обратите внимание на код в строке 11. Этот оператор устанавливает аргумент Cancel события BeforeDoubleClick в состояние True. Оператор в строке 11 отменяет вызов обработчика события двойного щелчка, встроенного в объект Workbook; в результате это запрещает редактирование «по месту» содержимого ячейки, для которой выполняется процедура обработки события BeforeDoubleClick.
Событие двойного щелчка представлено также на уровне Application и Workbook как событие SheetBeforeDoubleClick; это событие генерируется в тех случаях, когда был выполнен двойной щелчок любого листа рабочей книги (для объектов Workbook) или когда был выполнен двойной щелчок любого листа в любой рабочей книге (для объекта Application).
События Change и Selectionchange
Чтобы гарантировать точность ваших данных в рабочем листе, можно проверять содержимое каждой ячейки. Например, вы могли бы проверить, что содержимое поля даты, действительно, является датой или что введенное число удовлетворяет определенным условиям, например, является положительным числом. Вы можете сделать это, написав процедуру обработки события Change. Событие Change содержит один аргумент — Target, который является ссылкой на Excel-объект Range.
Листинг 19.6 показывает пример того, как использовать событие Change для проверки данных.
Листинг 19.6. Применение события Change рабочего листа
1	Private Sub Worksheet_Change(ByVai Target As Excel.Range)
2	' Использует событие Change для проверки данных рабочего листа 3
4	Static InError As Boolean 5
6	If InError Then
7	InError = False
8	Else
1’’ \
516
Глава 19
9	If Not VerifiedData(Target) Then
10	InError = True
11	Target.Select
12	Target.ClearContents
13	End If
14	End If
15
16 End Sub
17
18 Private Function VerifiedData(ByVai SourceRef As Excel.Range)
19 ' Проверяет допустимость данных в определенной ячейке":
20 ' в столбце 1 должны быть даты, в столбце 2 должны быть
21 ' положительные числа
22
23
'24
25
26'
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Const strTitle = "Проверка данных ячейки"
VerifiedData = False ' предположим несоответствие данных
With SourceRef
Select Case .Column
Case 1	' поле даты
If Not IsDate(.Value) Then
MsgBox prompt:“"Недопустимые данные " & _ "в поле Date", Title:“StrTitle
Exit Function
Else
.NumberFormat = "mmmm d, yyyy"
End If
Case 2	' поле суммы
If IsNumeric(.Value) Then
If .Value < 0 Then
MsgBox prompt:“"Отрицательное значение!", Title:“StrTitle
Exit Function
Else
.NumberFormat = "$#,##0.00_); ($#,##0.00)"
End If
Else
MsgBox prompt:“"Вводите числовые значения", _ Title:“StrTitle
Exit Function
End If
End Select	।
End With
' если "мы" в этой точке, то значения допустимы VerifiedData = True
56 End Function
Листинг 19.6 содержит код модуля класса рабочего листа. В строках 1-16 записан код обработчика события Change рабочего листа (Worksheet_Change); в строках 18-56 — функция проверки допустимости данных (VerifiedData). Сначала мы обсудим процедуру Worksheet_Change.
Процедура обработки события Worksheet_Change выполняется каждый раз, когда изменяется свойство Value любой ячейки рабочего листа, независимо тот того, проведено изменение VBA-кодом или пользователь ввел изменения с клавиатуры. Обратите внимание на аргумент Target в строке 1; этот аргумент автоматически передается объектом Worksheet каждый раз, когда выполняется процедура Worksheet_Change. Аргумент Target содержит ссылку на ячейку, свойство Value которой было изменено.
В строке 4 объявляется статическая переменная InError типа Boolean, которая отслеживает, обрабатывается ли в данный момент ошибка в ячейке.
Использование обработчиков событий
517
В строке 6 проверяется значение переменной InError; если оно равно значению False, код в строке 9 вызывает функцию VerifiedData, которая возвращает значение True, если данные в ячейке, на которую ссылается Target, допустимы. В ином случае возвращается значение False. Если функция VerifiedData возвращает значение False, код в строке 10 присваивает переменной InError значение True для указания того, что в данный момент обрабатывается ошибка. Затем в строке 11 выбирается ячейка рабочего листа, на которую ссылается Target; это действие возвращает курсор вставки в ячейку, так чтобы пользователь мог легко исправить ошибочно введенные данные. Код строки 12 удаляет ошибочное значение из ячейки.
При выполнении строки 12 процедура обработчика события Worksheet_Chan-ge вызывается снова, поскольку свойство Value ячейки рабочего листа изменилось; следовательно, процедура Worksheet_Change выполняется рекурсивно. Если здесь не будет предусмотрен какой-либо способ остановить рекурсию, обработчик события Worksheet_Change будет выполняться бесконечно. Статическая переменная In-Error используется для определения того, находится ли Worksheet_Change в рекурсивном вызове. Когда ошибка обнаружена в первый раз, InError присваивается значение True. Когда Worksheet_Change выполняется рекурсивно, значение In-Error равно значению True, и выполняется строка 7, сбрасывая переменную InError в состояние False. Рекурсивный вызов завершается, и также завершается первоначальный вызов Worksheet_Change.
Таким образом, обработчик события Worksheet_Change проводит проверку допустимости значения ячейки. Если ячейка содержит недопустимые данные, курсор вставки возвращается в эту ячейку, выводится соответствующее сообщение об ошибке, ошибочное значение удаляется из ячейки.
Функция VerifiedData получает единственный аргумент SourceRef, который является ссылкой на проверяемую ячейку. Когда процедура Worksheet_Change вызывает функцию VerifiedData, она передает диапазон Target в функцию VerifiedData посредством аргумента SourceRef. Функция VerifiedData использует оператор Case (строки 28-51), чтобы проверить правильность данных ячейки, основываясь на номере столбца данной ячейки. Ячейки первого столбца рабочего листа должны содержать значения типа Date, а ячейки второго столбца — положительные числовые значения. Если значение не соответствует заданному формату, VerifiedData выводит сообщение, описывающее, что неверно в данном значении, и возвращает значение False; в ином случае VerifiedData возвращает значение True.
Рассмотрим следующую задачу. Необходимо при помощи сканера, читающего штрих-коды, например, сканера модели PS-700E, считывать номер изделия, помещать этот номер в рабочий лист Excel (для, быть может, дальнейшего перенесения данных в некоторую базу данных) и печатать этот номер и текущую дату в некоторый заранее подготовленный бланк, т.е. в определенную ячейку другого листа для дальнейшей печати.
Листинг 19.7 содержит код обработчика события SelectionChange листа Лист1 для выполнения поставленной задачи, а на рис. 19.6 представлено «рабочее место», состоящее из принтера компьютера, сканера PS-700E, которым уже считано несколько штрих-кодов, записанных при помощи обработчика Worksheet_Se-lectionChange в Excel-лист.
Листинг 19.7. Применение события Selectionchange рабочего листа
1	Private Sub Worksheet_SelectionChange(ByVai Target As Range) 2
3	On Error GoTo yyy
4
5	If Target.Column > 1 Then
6	Exit Sub
518
Глава 19
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
' 22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
End If
1 введенный сканером код в ячейку: current = ActiveWorkbook.Worksheets("Лист1"). _
Cells (Target.Row - 1, Target.Column) .Value
If Len(current) > 0 Then	•
1 записать дату внесения кода:
ActiveWorkbook.Worksheets("Лист1"). _
Cells(Target.Row - 1, Target.Column + 1).Value = _ Format(Now(), "dd/mm/yy")
1 записать код в ячейку для печати:
ActiveWorkbook.Worksheets("Лист2").Cells(4, 8) = current & " / " & Format(Now(), "dd/mm/yy")
If Trim(ActiveWorkbook.Worksheets("Лист1"). _ Cells (1, 6) .Value) = "Print" Then ' печать:
ActiveWorkbook.Worksheets("Лист2") Printout Else
' предварительный просмотр области печати:
ActiveWorkbook.Worksheets("Лист2").PrintPreview End If
End If
yyy:
End Sub
Рис. 19.6
Пользователь уже успел считать сканером PS-700E несколько штрих кодов изделий, которые записаны при помощи обработчика
Worksheet_SelectionChange в Excel-л ист
Событие Calculate
Изменение одной переменной в рабочем листе с большой и сложной структурой может влиять на множество формул. Если вы не можете следить за всеми формулами (например, каждый раз проверять выполнение некоторого условия), то можно использовать событие Calculate, чтобы выполнить процедуру, которая проведет нужную проверку. Событие Calculate не имеет никаких аргументов. Листинг 19.8 показывает пример использования события Calculate.
Использование обработчиков событий
519
Листинг 19.8. Применение события Calculate рабочего листа
1	Option Explicit
2
3	Private Sub Worksheet—Calculate()
4	' Выполняется каждый раз, когда перерасчитывается рабочий лист
5	If Range("Прибыль") < 0.2 Then
б	MsgBox prompt*: ="Прибыль менее 20%", _
7	Title:="Демонстрация события Calculate"
8	End If
9	End Sub
Процедура обработки события Worksheet_Calculate в листинге 19.8 демонстрирует простейший вариант использования события Calculate. Эта процедура выполняется каждый раз, когда производятся вычисления рабочего листа, независимо от того, сделано ли это вручную или автоматически. Процедура обработки события Worksheet_Calculate в листинге 19.7 принимает, что в рабочем листе имеется некоторый диапазон, названный Прибыль, который отображает результат формулы, вычисляющей значение порога валовой прибыли. Когда рабочий лист вычислен, выполняется процедура Worksheet_Calculate, которая проверяет значение диапазона Прибыль; если это значение меньше 0.2 (то есть меньше 20 процентов), то выводится соответствующее сообщение.
Другие события
Как вы видели из таблицы 19.1, вам доступно намного больше событий, чем рассмотрено в предыдущих разделах. Событий Excel настолько много, что привести примеры для каждого из них в этой книге не представляется возможным. Однако вы должны знать о нескольких других событиях Excel-объектов, которые могут быть очень полезны. В следующем списке приведены эти события, сгруппированные по функциональному признаку.
Печать
Для объекта Workbook доступно событие BeforePrint, а для объекта Application — событие WorkbookBeforePrint. Используйте событие BeforePrint для выполнения любых задач, которые вы хотите выполнить непосредственно перед началом печати. Например, вы могли бы использовать обработчик события BeforePrint объекта Workbook, чтобы убедиться в том, что все рабочие листы были просчитаны, а отчет отформатирован, или чтобы выбрать специальные виды для печати. Обработчик события BeforePrint может помочь автоматизировать установку печати для сложных отчетов: пользователь просто выбирает команду Print, а затем ваш обработчик события BeforePrint может выбрать виды или листы для печати.
Сохранение рабочих книг
Для объекта Workbook доступно событие BeforeSave, а для объекта Application — событие WorkbookBeforeSave. Эти события происходят непосредственно перед сохранением рабочей книги (или, для объекта Application, перед сохранением любой рабочей книги). Используйте событие BeforeSave, чтобы выполнить проверку правильности данных, удалить временные рабочие листы или выполнить другие задачи до сохранения рабочей книги. Процедура обработки события BeforeSave имеет следующий заголовок:
Private Sub Workbook_BeforeSave(ByVai SaveAsUi As Boolean, Cancel As Boolean)
SaveAsUi — это значение типа Boolean; если оно равно True, то Excel отображает диалог Save As. Аргумент Cancel — это также значение типа Boolean; если вы уста
520
Глава 19
навливаете этот аргумент в состояние True, то операция сохранения отменяется после завершения работы вашей процедуры обработки события.
Создание новых объектов
Для объекта Workbook доступно событие NewSheet с заголовком процедуры обработки события:
Private Sub Workbook_NewSheet(ByVai Sh As Object)
Это событие происходит каждый раз, когда в рабочую книгу добавляется новая диаграмма или рабочий лист. Аргумент Sh — новый лист, который может быть объектом Worksheet или Chart.
Объекту Application доступны события WorkbookNewSheet и NewWorkbook. Событие WorkbookNewSheet происходит каждый раз, когда в любую открытую рабочую книгу добавляется новый лист и имеет следующий заголовок процедуры обработки события:
Private Sub Ojbject_WorkbookNewSheet(ByVai Wb As Workbook,
ByVai Sh As Object)
Аргумент Wb — рабочая книга, Sh — новый лист.
Событие NewWorkbook происходит каждый раз, когда создается новая рабочая книга и имеет только аргумент Wb (рабочая книга).
Используйте события NewSheet и NewWorkbook для добавления предопределенных элементов в созданную рабочую книгу или лист: заголовки столбцов, имена листов, именованные диапазоны и т.д.
Изменение выделенного фрагмента
Объекту Worksheet доступно событие Selectionchange, которое происходит каждый раз, когда изменяется выделенный фрагмент в рабочем листе, и имеет следующий заголовок процедуры обработки события:
Private Sub Worksheet_SelectionChange(ByVai Target As Excel.Range)
Здесь Target — новый выделенный диапазон.
Объектам Application и Workbook доступно событие SheetSelectionChange с заголовком процедуры обработки события:
Private Sub ojbject_SheetSelectionChange(ByVai Sh As Object, ByVai Target As Excel.Range)
Используйте событие SelectionChange, чтобы предоставить пользователю варианты выделения ряда предопределенных элементов на рабочем листе или проверить правильность содержимого ячейки, когда выделенный фрагмент переместится из этой ячейки в другое место.
Работа со свойствами и методами Excel, связанными с событиями
В дополнение к доступным для объектов событиям, обсужденным в предыдущих разделах этой главы, Excel также имеет несколько свойств и методов, связанных с событиями. Вы можете использовать эти свойства и методы для создания процедур обработки таких событий, которые не предоставляются объектами Excel непосредственно. Например, вы можете использовать метод ОпКеу, чтобы создать свои собственные специальные командные клавиши; ваши процедуры командных клавиш будут вызываться каждый раз, когда на клавиатуре нажата соответствующая клавиша. Следовательно, метод ОпКеу предоставляет вам способ косвенного создания процедур, которые отвечают на определенные события клавиатуры.
Использование обработчиков событий
521
Свойство OnWindow Excel
Свойство OnWindow играет роль, аналогичную событию WindowActivate; OnWindow определяет процедуру обработки события, которая выполняется каждый раз, когда пользователь активизирует определенное окно. Используйте свойство OnWindow, если хотите выполнять определенную процедуру каждый раз, когда любое окно данного рабочего листа становится активным окном. Другое применение свойства OnWindow — если вам нужно оценить содержимое текущего окна и в зависимости от этого включить или отключить определенные команды меню или панели инструментов вашего приложения. (Не забудьте, что для одного рабочего листа вы можете иметь несколько открытых окон.) Свойство OnWindow доступно для объектов Application и Window. Синтаксис для установки свойства OnWindow имеет следующий вид:
СИНТАКСИС
Object.OnWindow = "ProcedureName"
Здесь Object является объектной ссылкой или на объект Window, или на объект Application. Если Object ссылается на объект Window, то процедура обработки события выполняется каждый раз, когда пользователь переключается на определенное окно. Если Object ссылается на объект Application, процедура обработчика события выполняется каждый раз, когда пользователь переключается на любое окно.
Чтобы процедура обработки события, связанная с окном посредством свойства OnWindow, не выполнялась, присвойте свойству OnWindow строку нулевой длины:
Object.OnWindow = ""
В листинге 19.9 показан пример применения свойства OnWindow.
Листинг 19.9. Применение свойства OnWindow
1	Option Explicit
2
3	Sub SetWindowHandler()
4	' Устанавливает обработчик события для OnWindow
5	'
6	Windows("Events.XLS:2").OnWindow = "WindowHandler"
7	End Sub
8
9
10	Sub WindowHandler()
11	' Обработчик события - открытие Окна Events.XLS:2
12
13	With Windows("Events.XLS:2" )
14	.Splitvertical	= 100
15	.DisplayFormulas = True	,
16	.DisplayGridlines = False
17	.Displayzeros = False
18	.FreezePanes =	True
19	.Windowstate =	xlMaximized
20	End With
21	End Sub
22
23
24	Sub ClearWindowHandler()
25	' Отменяет обработчик события для OnWindow
26
27	Windows("Events.XLS:2").OnWindow = ""
28	End Sub
522
Глава 19
Листинг 19.9 содержит весь стандартный модуль. В этом примере процедура с именем SetWindowHandler (строки 3-7) устанавливает свойство OnWindow для окна с именем Events.xls:2 (строка 6). Процедура обработки события Window-Handler устанавливает несколько свойств окна в блоке оператора With (строки 13-21). Окно делится вертикально (строка 14), отображаются формулы (строка 15), отменяется сетка (строка 16), скрываются нули (строка 17), закрепляются подокна (строка 18) и окно максимизируется (строка 19). (Процедура Window-Handler работает только в том случае, если лист, выведенный в данный момент в окно, является рабочим листом; в иных случаях процедура будет генерировать ошибку времени исполнения программы.)
Для того чтобы процедура WindowHandler работала правильно, вы должны сначала выполнить процедуру SetWindowHandler после открытия второго окна рабочей книги Events.xls. Чтобы удалить обработчик события WindowHandler, выполните процедуру ClearWindowHandler.
Имейте в виду, что процедуры обработки событий, которые вы создаете, присваивая их свойству OnWindow, могут сохраняться в любом модуле.
Если хотите, чтобы некоторый ряд шагов выполнялся каждый раз, когда активизируется или деактивизируется любое окно, отображающее рабочий лист или рабочую книгу, используйте объектные события WindowActivate и Window-Deactivate вместо свойства OnWindow.
Метод OnKey Excel
Для запуска VBA-процедур в Excel вы можете устанавливать специальные комбинации клавиш в VBA-коде, используя метод ОпКеу. Как правило, комбинации клавиш имеют вид Ctrl + клавиша, где клавиша — символ алфавита. Excel «рассматривает» символы верхнего регистра и символы нижнего регистра раздельно. Хотя ваш выбор символов ограничен (тем более что Excel использует некоторые символы для встроенных комбинаций клавиш, например Ctrl+C для команды Правка | Копировать (Edit | Сору)), эта методика хорошо работает в большинстве приложений.
Метод ОпКеу также полезен в тех случаях, когда вы хотите отключить определенные нажатия клавиш. Предположим, например, что вы хотите, чтобы пользователь не мог ничего удалить. Для решения этой задачи можно было бы использовать VBA-код, чтобы удалить кнопку Вырезать (Cut) из панели инструментов и команды Вырезать (Cut) и Удалить (Clear) из меню. А как быть с клавишей Delete? Вы можете использовать метод ОпКеу для создания собственного обработчик события для клавиши Delete или любых других нажатий клавиш:
СИНТАКСИС
Application.ОпКеу(Key, [Procedure] )
Обязательный аргумент Key — строка, определяющая клавишу или комбинацию клавиш, которую вы хотите перехватывать. Для букв, чисел или знаков препинания просто заключите символ в кавычки, например "а". Для других клавиш используйте текстовые строки, приведенные в таблице 19.2. Вы можете также создать комбинации клавиш, объединив клавишу символа или одну из клавиш таблицы 19.2 с одним или несколькими предшествующими кодами клавиш Alt, Ctrl и Shift, приведенными в таблице 19.3. (Значения клавиш, показанные в таблицах 19.2 и 19.3, аналогичны значениям клавиш, которые используются для метода SendKeys, рассмотренного в предыдущей главе.) Необязательный аргумент Procedure — строка, определяющая имя процедуры, которая должна выполняться каждый раз, когда пользователь нажимает определенную клавишу. Если вы используете в качестве значения аргумента
Использование обработчиков событий
523
Procedure строку с нулевой длиной то данная клавиша будет заблокирована. Если вы опускаете аргумент Procedure, Excel переустанавливает клавишу в нормальное состояние.
Таблица 19.2. Текстовые строки, использующиеся для аргумента Key метода ОпКеу
Клавиша	Строка
BACKSPACE	{BACKSPACE}, {BS} или {BKSP}
BREAK	{BREAK}
CAPS LOCK	{CAPSLOCK}
DEL или DELETE	{DELETE} или {DEL}
DOWN ARROW	{DOWN}
END	{END}
ENTER	{ENTER} или -
ESC	{ESC}
HELP	{HELP}
HOME	{HOME}
INS или INSERT	{INSERT} или {INS}
LEFT ARROW	{LEFT}
NUM LOCK	{NUMLOCK}
PAGE DOWN	{PGDN}
PAGE UP	{PGUP}
PRINT SCREEN	{PRTSC}
RIGHT ARROW	{RIGHT}
SCROLL LOCK	{SCROLLLOCK}
TAB	{TAB}
UP ARROW	{UP}
F1-F16	{F1}-{F16}
Таблица 19.3. Коды для клавиш Alt, Ctrl и Shift
Клавиша	Строка
Alt	% (процент)
Ctrl	
Shift	+ (плюс)
В листинге 19.10 приведен пример использования метода ОпКеу.
524
Глава 19
Листинг 19.10. Использование метода ОпКеу
1	Option Explicit
2
3	Sub SetShortcutKeys ()
4	' Установка процедур для Ctrl+Shift+O и Ctrl+Shift+G
5
6	With Application
7	.ОпКеу Кеу:="л+0", Procedure:“"DisplayGenOptions"
8	.ОпКеу Кеу:="л+С", Procedure:“"ToggleGridlines"
9	End With
10
11	End Sub
12
13
14	Sub DisplayGenOptions()
15	' Выводит вкладку Общие (General) диалоговой	z
16	' панели Параметры (Options)
17
18	Application.Dialogs(xlDialogOptionsGeneral).Show
19
20	End Sub
21
22	Sub ToggleGridlines()
23	' Переключает Сетку в состояние вкл. и откл.
24
25	With ActiveWindow
26	DisplayGridlines = Not .DisplayGridlines
27	End With
28
29	End Sub
30
31	Sub ResetShortcutKeys()
32	' Отключение действий для Ctrl+Shift+O и Ctrl+Shift+G
33
34	With Application
35	.ОпКеу Кеу:="л+О"
36	.ОпКеу Key:="A+G"
37	End With
38
39	End Sub
Листинг 19.10 содержит модуль с четырьмя различными процедурами. Первая процедура — SetShortcutKeys — два раза вызывает метод ОпКеу для установки двух комбинаций клавиш. Первый оператор ОпКеу (строка 7) определяет, что процедура DisplayGenOptions будет выполняться каждый раз, когда нажимается комбинация клавиш Ctrl+Shift+O. Второй оператор ОпКеу (строка 8) определяет комбинацию клавиш для процедуры ToggleGridlines — Ctrl+Shift+G.
Процедура DisplayGenOptions (строки 14-20) вызывает метод Show (строка 18), для отображения вкладки Общие (General) диалоговой панели Параметры (Options) (определяется константой xlDialogOptionsGeneral). Процедура ToggleGridlines (строки 22-29) просто переключает свойство DisplayGridlines для ActiveWindow (строка 26).
Процедура ResetShortcutKeys (строки 31-39) восстанавливает оригинальные действия двух комбинаций клавиш (для Ctrl+Shift+G оригинальное действие отсутствует), используя метод ОпКеу без аргумента Procedure (строки 35 и 36).
Использование обработчиков событий
525
Метод OnTime Excel
Метод OnTime Excel дает возможность выполнить процедуру VBA в указанное время и даже в определенный день. Этот метод полезен для создания процедур обработки событий, имеющих отношение ко времени и дате и решающих задачи следующего типа:
	Резервное копирование данных рабочей книги в определенные моменты времени.
	Если вы отходите на время от своего рабочего стола, вы могли бы запланировать выполнение нескольких длительных операций, например пересчет большого рабочего листа или печать отчета.
	Вы могли бы выводить в Excel напоминания относительно встреч, приглашений, перерывов и т.д.
	Вы могли бы выполнить другие действия в определенное время, чтобы проверить электронную почту или запустить какую-либо другую задачу.
Общий синтаксис метода OnTime выглядит следующим образом:
СИНТАКСИС
Application.OnTime(EarliestTime, Procedure, [LatestTime], [Schedule])
Обязательный аргумент EarliestTime — число, представляющее время, когда должно начаться выполнение обозначенной процедуры. Для аргумента EarliestTime следует использовать последовательные значения даты. Обязательный аргумент Procedure — это строка, содержащая имя процедуры, которую необходимо выполнить при наступлении момента времени, заданного аргументом EarliestTime.
Если Excel не «готов» выполнить определенную процедуру в момент времени EarliestTime, т.е. если Excel не находится в режимах Готов (Ready), Вырезать (Cut), Копировать (Сору) или Поиск (Find), он будет «пробовать» выполнить процедуру до наступления момента времени, определенного необязательным аргументом LatestTime. Аргумент LatestTime — это также значение даты. Если вы опускаете LatestTime, Excel выполняет заданную процедуру как можно быстрее после наступления момента времени EarliestTime.
Необязательный аргумент Schedule — значение типа Boolean, которое указывает Excel, выполнить ли определенную процедуру в заданное время. Если аргумент Schedule имеет значение True или опущен, Excel выполнит обработчик события в планируемое время. Если аргумент Schedule имеет значение False, то Excel отменяет установку OnTime.
Excel выполняет процедуру обработчика событие OnTime только один раз. Если вы выполните процедуру сегодня в полдень, та же самая процедура не будет выполнена завтра, даже если вы оставите компьютер включенным с загруженным Excel. Листинг 19.11 показывает пример работы метода OnTime.
Листинг 19.11. Применение метода OnTime Excel
1	Sub SetOnTimeReminder()
2	' Устанавливает событие OnTime
3
4	Application.OnTime EarliestTime:=TimeValue("7:57 AM"),
5	Procedure:="Events.XLS!RemindMe"
6	End Sub
7
8
526
Глава 19
9	Sub RemindMeO
10	' "Напоминает" о встрече
11
12	Веер
13	MsgBox prompt:="Сейчас "4
14	Format(Time, "h:mm AM/PM") &	& _
15	vbCr & "He забудьте о встрече с клиентом!"
16	End Sub
Листинг 19.11 содержит две процедуры. Первая процедура, SetOnTimeRemin-der (строки 1-6), вызывает метод OnTime, чтобы определить процедуру Remind-Ме, которая будет выполнена в 7:57 утра (строки 3 и 4). Процедура RemindMe (строки 9-16) подает звуковой сигнал через динамик компьютера (строка 12) и выводит сообщение, напоминающее о встрече (строки 13-15).
Работа с событиями объектов Word
Число объектов в Word, которые предоставляют доступ к событиям, намного меньше, чем в Excel. Word имеет только два таких объекта — Application и Document. В таблицах 19.4 и 19.5 приведен список событий объектов Word. Далее рассматриваются некоторые из событий, приведенных в этих таблицах.
Таблица 19.4. События Word-объекта Application
Событие	Когда происходит
DocumentBeforeClose	Перед тем, как закрывается любой документ.
DocumentBeforePrint	Перед тем, как печатается любой открытый документ.
DocumentBeforeSave	Перед тем, как сохраняется любой открытый документ.
Documentchange	Когда изменяется открытый документ.
DocumentOpen	Когда открывается документ.
EPostageinsert, EPostagePropertyDialog, MailMergeAfterMerge, MailMergeAfterRecordMerge, MailMergeBeforeMerge, MailMergeBeforeRecordMerge, MailMergeDataSourceLoad, MailMergeDataSourceValidate, MailMergeDataSource Validate, MailMergeWizardSendToCustom, MailMerge WizardStateChange	При возникновении событий, связанных с использованием аппарата рассылки писем. % /
NewDocument	При создании нового документа.
Quit	Когда пользователь завешает работу с Word.
Window Activate	Когда любое окно документа становится активным.
Использование обработчиков событий
527
Событие	Когда происходит
W indowBeforeDoubleClick	Когда в редактируемой области окна документа выполняется двойной щелчок, перед выполнением действия по умолчанию.
WindowBeforeRightClick	Когда в редактируемой области окна документа выполняется правый щелчок, перед выполнением действия по умолчанию.
WindowDeactivate	Когда любое окно документа перестает быть активным.
WindowSelectionChange	Когда в окне активного документа изменяется выделенный фрагмент.
WindowSize	Когда окно приложения изменяется в размерах или перемещается.
Таблица 19.5. События Word-объекта Document
Событие	Когда происходит
Close	Когда закрывается документ.
New	Когда новый документ создается на основе шаблона.
Open	При открытии документа.
Событие Open
Как и событие Open в Excel, событие Open объекта Document в Word используется для настройки среды вашего приложения: меню, панели инструментов, а также для установки параметров Word. Типичные действия, выполняемые внутри процедуры обработки события Open документа, перечислены ниже:
	Установка или настройка панели команд, чтобы создать меню и панели инструментов для программы VBA Word
	Настройка общих параметров программы, таких как загрузка глобальных шаблонов, установка стандартного шрифта и других.
	Добавление новых связанных клавиш или присвоение процедуры обработчика события OnTime.
	Вывод специального диалога для настройки параметров для программы.
Вы можете включить в обработчик события Open любое действие, которое хотите выполнить или которое необходимо выполнить при каждом открытии документа. Событие Open для шаблона Normal.dot происходит тогда, когда вы открываете первый документ, основанный на шаблоне Normal, а не во время загрузки в память шаблона Normal.
В листинге 19.12 приведен пример процедуры обработчика события Open для документа Word. Для того чтобы процедура Document_Open листинга 19.12 работала правильно, ее следует ввести в модуль класса объекта ThisDocument. В редакторе VB откройте Project Explorer и раскройте (в случае необходимости) ветвь Microsoft Word Objects, чтобы увидеть элемент списка ThisDocument. Выполните двойной щелчок элемента ThisDocument, чтобы открыть окно кода для модуля класса объекта ThisDocument. Затем выберите Document в списке объектов окна кода и выберите в списке процедур пункт Open. Редактор VB автоматически введет объявление процедуры события Open; после этого вы можете ввести код из листинга 19.12.
528
Глава 19
Кроме того, необходимо создать модуль для этого документа и поместить в него объявление функции GetUserNameA из DLL-файла:
Declare Function GetUserNameA Lib "advapi32.dll" _ (ByVai IpBuffer As String, nSize As Long) As Long
Листинг 19.12. Применение события Open документа
1	Private	Sub Document_Open()
2	Dim	username As String	'	имя пользователя
3	Dim	slength As Long	'	длина строки
4	Dim	retval As Long	'	возвращаемое	значение
5
6	' отводим место для получения строки в буфере:
7	username = Space(255)
* 8	slength = 255
9
10	’ получаем имя пользователя:
11	retval = GetUserNameA(username, slength)
12
13	' извлекаем информацию из буфера,отбрасывая Null:
14	username = Left(username, slength - 1)
15
16	' сообщение пользователю с указанием его имени:
17	MsgBox username & "! Вы начинаете работу с файлом " & _
18	Application.ActiveDocument.Name
19
20	' установить необходимые для работы панели:
21	CommandBars("Standard").Visible = True
22	CommandBars("Drawing").Visible = True
23
24	End Sub
Процедура обработки события Document_Open демонстрирует возможность обработки события Open для документа. Она определяет имя работающего с компьютером пользователя и имя открываемого файла. Сообщает пользователю эту информацию и устанавливает необходимые для работы панели инструментов.
Для того чтобы Word не выполнял процедуру обработки события Docu-ment_Open, во время открытия документа удерживайте нажатой клавишу Shift. Word откроет документ, не выполняя обработчик события Open.
Событие Close
Когда вы закрываете документ, вам может потребоваться восстановить среду приложения Word, особенно в том случае, если процедура Document_Open настроила интерфейс пользователя. Вы можете создать процедуру обработчика события Document_Close; событие Close происходит непосредственно перед закрытием документа. Событие Close в Word доступно только для Document. Word всегда выполняет процедуру обработки события Document_Close, закрываете ли вы документ в VBA-коде или используете команды меню Word.
В листинге 19.13 показан пример процедуры Document_Close.
Листинг 19.13. Применение события Close документа |
1	Private Sub Document_Close()
2	' Отменить панели инструментов:
3
4	CommandBars("Standard").Visible = False
Использование обработчиков событий
529
5	CommandBars("Drawing").Visible = False
6
7 End Sub
Событие New
Событие New предоставляется объектом Document, но действительно полезно только в тех случаях, когда используется в документах, сохраненных как шаблоны. Хотя стандартный объект Document может содержать процедуру обработки события New, он никогда не генерирует событие New. Событие New генерируется только в том случае, когда новый документ создается из конкретного шаблона. Поэтому следует использовать событие New в документе, который предполагается преобразовать в шаблон. Типичные примеры применения обработчика события New — создание конвертов, установка адреса получателя и приветствия, а также другие действия, связанные с созданием нового документа.
Событие Documentchange
Объект Word Application предоставляет доступ к событию Documentchange. Это событие происходит каждый раз, когда изменяется активный документ; Word переключается на новый документ, а затем генерирует событие Documentchange. Вы можете использовать событие Documentchange для проверки того, был ли активизирован определенный документ, после чего можно предпринять какие-либо действия.
Используйте событие Documentchange для запуска задачи, касающейся конкретного документа, чтобы предупредить действия пользователя, собравшегося переключиться на определенный документ до того, как было завершено выполнение задачи, а также, чтобы помочь пользователю пройти через определенный ряд документов. В листинге 19.14 приведен пример процедуры обработки события Documentchange.
Листинг 19.14. Применение события Documentchange объекта Application Word
1	Option Explicit
2
3	Public WithEvents App As Application 4
5	•
6	Private Sub App_DocumentChange()
7	1 Если новый активный документ - это
8	' "Глава 19.doc",
9	' то перейти на закладку с именем "LastBookmark"
10	' Если закладка не существует, то перейти
11	' в конец документа
12
13	On Error Resume Next	,
14
15	With ActiveDocument
16	If UCase(.Name) = _
17	UCase("Глава 19.doc")	Then
18	Selection.GoTo	what:=wdGoToBookmark,	_
19	Name:="LastBookmark"
20	If Err.Number	0 Then
21	Selection.WholeStory
22	Selection.Collapse direction:=wdCollapseEnd
23	End If
24	End If
530
Глава 19
25	End With
26
27 End Sub
Листинг 19.14 содержит модуль класса, поскольку процедуры обработки событий уровня Application должны находиться в модуле класса вашего VBA-проек-та. Чтобы процедура обработки события App_DocumentChange листинга 19.14 работала правильно, вы должны ввести код листинга 19.14 в модуль класса (модули класса были описаны в главе 10). Вы должны также создать объявление переменной уровня модуля, которая создает новый экземпляр вашего модуля класса, и процедуру, которая присваивает этой переменной ссылку на объект Application. Если вы ввели код листинга 19.14 в модуль класса с именем ApplicationEvents, вы должны добавить следующий код в любой другой модуль:
Dim WordApp As New ApplicationEvents
Sub InitializeAppEvents))
Set WordApp.App = Application
End Sub
Теперь выполните процедуру InitializeAppEvents, чтобы создать связь между обработчиком события в модуле класса ApplicationEvents и объектом Application. После того как вы завершили все эти шаги, ваши обработчики событий уровня приложения будут выполняться при возникновении связанных с ними событий.
Строки 1-3 листинга 19.14 представляют собой общую область модуля класса. Объявление открытой переменной в строке 3 создает дескриптор, который VBA может использовать для связывания обработчика события в этом модуле класса с объектом Application. Переменная в этом объявлении должна иметь имя Арр, иначе VBA не сможет использовать дескриптор для подключения вашего обработчика событий к объекту Application.
Строки 6-27 содержат процедуру App_DocumentChange, которая будет выполняться каждый раз при возникновении события Documentchange.
Строки 15-25 содержат оператор With, упрощающий работу с ActiveDocument. Word генерирует событие Documentchange после переключения на новый документ, так что ActiveDocument ссылается на документ, который только что стал активным. Строки 16-17 содержат оператор If...Then, который проверяет, произошло ли переключение на документ Глава 19.doc. (Функция UCase используется для преобразования сравниваемых строк в верхний регистр.)
Если документ, на который только что произошло переключение, имеет имя Глава 19.doc, то код строк 18-19 вызывает метод GoTo объекта Selection для перехода к закладке документа с именем LastBookmark. Если закладки не существует, то обработчик ошибок предотвращает ошибку во время выполнения программы и выполнение кода продолжается со следующего оператора (строка 20), независимо от того, произошла ошибка или нет.
Код строки 20 проверяет значение свойства Number объекта Err. Если во время выполнения программы произошла ошибка (т.е. значение Err.Number не равно нулю), то закладки не существует. В этом случае код строк 21 и 22 переводит курсор вставки в конец документа.
Событие Quit
Событие Quit происходит каждый раз, когда заканчивается текущий сеанс работы Word, независимо от того, выбрал ли пользователь команду Файл | Выход (File | Exit) или вы вызвали метод Quit в VBA-коде. Вы можете использовать событие Quit для автоматического сохранения всех открытых документов, записи переменных в коллекцию Variables документа или для выполнения любой вспомогательной задачи, которую хотите выполнять при каждом выходе из Word.
Использование обработчиков событий
531
Событие Quit происходит при выходе из Word и не имеет аргумента Cancel, так что вы не можете его использовать, чтобы помешать пользователю закончить сеанс работы Word.
В листинге 19.15 показан пример обработчика события Quit.
Листинг 19.15. Применение события Quit объекта Application Word
1	Option Explicit
2
3	Public WithEvents App As Application	1
4
5
6	Private Sub App_Quit()
7	' поместить закладку с именем "LastBookmark"
8	1 в каждый открытый документ
9	Dim aDoc As Document
10	Dim Ans As Integer	’
11
12	' для всех документов
13	For Each aDoc In Application.Documents
14	With aDoc
15	Ans=MsgBox(prompt:="Вставить закладку 'LastBookmark'?"
16	, Title:=.Name, _
17	buttons:=vbYesNo +	vbQuestion)
18	If Ans = vbYes Then
19	.Activate
20	Selection.Collapse	direction:=wdCollapseEnd
21	.Bookmarks.Add Name:^"LastBookmark"
22	,	.Save
23	End If	,	'
24	End With
25	Next aDoc
26
27	End Sub
Листинг 19.15, как и листинг 19.14, содержит полностью весь модуль класса — тип модуля, обязательный для сохранения процедуры обработки события уровня Application. Строки 1-3 листинга 19.15 должны быть введены в общую область объявлений модуля класса. Обратите внимание, что этот модуль класса, как и в листинге 19.14, содержит объявление открытой переменной в строке 3, чтобы создать дескриптор, который VBA может использовать для связывания процедур обработки событий в этом модуле класса с объектом Application.
Процедура обработки событий App_Quit «перебирает» все открытые документы и предлагает пользователю вставить закладку на текущем выделенном фрагменте. Вставка закладки на текущий выделенный фрагмент перед закрытием документа может помочь вам быстро найти место последнего редактирования. Если пользователь выбирает вставку закладки, то документ также и сохраняется.
В строке 13 начинается цикл For Each, который «перебирает» все открытые документы и выдает запрос (строки 15-17) на вставку закладки для каждого документа. Имя документа отображается в заголовке диалогового окна функции InputBox (строка 16). Объект Selection (строка 20) всегда ссылается на выделенный фрагмент в активном документе. В строке 21 вызывается метод Add коллекции Bookmarks документа для вставки закладки. В заключение код строки 22 сохраняет документ без обращения к пользователю. Сохранение документа здесь необходимо потому, что Word уже задавал пользователю вопрос о сохранении документов, содержащих несохраненные изменения. Если вы изменяете документ в процедуре события Quit, вы также должны его сохранить.
532
Глава 19
Работа с коллекциями и методами, связанными с событиями Word
Как и Excel, Word предоставляет несколько различных способов, которыми вы можете установить процедуры обработки событий для тех событий, к которым Word не предоставляет прямой доступ, в частности, к событиям клавиатуры и времени. Для сохранения процедур обработки событий специальных нажатий клавиш следует использовать коллекцию Key Bindings Word. Для создания процедур, которые должны выполняться в конкретный момент времени дня или при наступлении конкретной даты, используйте метод OnTime Word. Следующие несколько разделов этой главы описывают коллекцию KeyBindings и метод OnTime Word более подробно.
Коллекция KeyBindings
Вы можете присвоить комбинацию клавиш вашей процедуре VBA в Word в интерактивном режиме, выбрав команду Сервис | Настройка (Tools | Customize) для отображения диалога Настройка (Customize) и щелкнув кнопку Клавиатура (Keyboard) для вывода диалога настройки клавиатуры. Вы можете также установить специальные комбинации клавиш в вашем VBA-коде Word, используя коллекцию KeyBindings и объекты KeyBinding, которые она содержит.
Свойство KeyBindings объекта Application возвращает коллекцию всех команд клавиатуры Word как объект KeyBindings. Как вы можете предполагать, коллекция KeyBindings содержит объекты KeyBinding. Каждый объект KeyBinding хранит информацию, которая связывает конкретную клавишу или комбинацию клавиш с соответствующей процедурой.
На основе объектов KeyBinding и коллекции KeyBindings вы можете создавать процедуры, обрабатывающие определенные нажатия клавиш. Вы можете также использовать коллекцию KeyBindings для отключения определенных нажатий клавиши, вызывая метод Clear или Disable отдельного объекта KeyBinding.
Для создания нового обработчика события нажатия клавиши, используйте метод Add коллекции KeyBindings со следующим синтаксисом:
СИНТАКСИС
Objесt.Add(КеуСаtegory, Command, KeyCode, [KeyCode2], [Commandparameter])
Здесь Object является ссылкой на объект KeyBindings; обычно для ссылки на коллекцию KeyBindings (в Word) следует использовать свойство Application.Key Bin dings.
Обязательный аргумент KeyCategory —число типа Long, которое указывает категорию нового обработчика события нажатия клавиши: макрос, выделение шрифта, выделение стиля, элемент AutoText и т.д. Используйте константу wdKeyCategoryMacro для аргумента KeyCategory, если хотите присвоить одной из ваших VBA-процедур данное нажатие клавиши. KeyCategory может быть любой из констант класса WdKeyCategory: wdKeyCategoryAutoText, wdKeyCategoryCommand, wdKeyCategoryDisable, wdKeyCategoryFont, wdKeyCategoryMacro, wdKeyCategoryNil, wdKeyCategoryPrefix, wdKeyCate-goryStyle или wdKeyCategorySymbol.
Обязательный аргумент Command — строковое выражение, определяющее имя процедуры VBA, которая будет выполняться в ответ на данное нажатие клавиши. В качестве альтернативы строка аргумента Command может опреде
Использование обработчиков событий
533
лять встроенную команду Word, которая будет выполняться в ответ на данное нажатие клавиши.
Аргумент KeyCode также обязательно должен присутствовать; это — число типа Long, соответствующее конкретной комбинации клавиш, которую будет представлять данный объект KeyBinding. Самый лучший способ задания аргумента KeyCode состоит в вызове метода Application.BuildKeyCode, описанного ниже в этом разделе.
Аргументы KeyCode2 и CommandParameter необязательны. KeyCode2 — вторая комбинация клавиш, a CommandParameter — дополнительные данные, используемые некоторыми встроенными командами Word, которые вы можете присвоить KeyBinding.
В описании синтаксиса метода KeyBindings.Add было упомянуто, что самый лучший способ конструирования аргумента KeyCode состоит в том, чтобы применить метод BuildKeyCode. Аргумент KeyCode может представлять не только одиночную клавишу, но и клавишу, объединенную с клавишами Ctrl, Shift и/или Alt. Метод BuildKeycode предоставляет простой способ определить числа, соответствующие нужным нажатиям клавиш:
СИНТАКСИС:
Object.BuildKeycode(Argl, [Arg2] , [АгдЗ], [Arg4])
Object в этом синтаксисе — необязательная ссылка на объект Application. Аргумент Argl — обязателен и является числом типа Long, представляющим конкретную одиночную клавишу. Чтобы определить значения аргументаArgl, используйте класс встроенных констант WdKey. Необязательные аргументы от Arg2 до Arg4 — также числа, представляющие конкретные одиночные клавиши; значение этих аргументов также определяются через константы WdKey. Метод BuildKeycode возвращает число типа Long, которое является числовым кодом для комбинации клавиш, которую вы определили в Argl-Arg4.
В листинге 19.16 содержится пример работы метода BuildKeycode.
Существует более сотни констант WdKey — слишком много, чтобы привести их здесь. Полный список доступных констант WdKey можно увидеть в окне Object Browser. Выберите Word в раскрывающемся списке Project/Library окна Object Browser, а затем выберите WdKey в списке Classes. Теперь список Members of WdKey отображает доступные встроенные константы клавиш.
Листинг 19.16. Применение коллекции KeyBindings Word
1 Option Explicit
2
3 Sub SetShortcutKeys()
4 1 11 Устанавливает комбинации клавиш Ctrl+Shift+S и Ctrl+Shift+F
5
6 With Application.KeyBindings
7	.Add KeyCategory:=wdKeyCategoryMacro, _
8	Command:="DisplayInfo", _
9	KeyCode:=BuildKeyCode(wdKeyControl,wdKeyShift,wdKeyS)
10	.Add KeyCategory:=wdKeyCategoryMacro, _
11	Command:="ViewFooter", _
12	KeyCode:=BuildKeyCode(wdKeyControl,wdKeyShift,wdKeyF)
13 End With
14
15 End Sub
16
534
Глава 19
17
18	Sub Displayinfo ()	'((
19	' Выводит диалог "Сведения"
20
21	Application.Dialogs(wdDialogFileSummarylnfo).Show
22
23	End Sub	.
24	'	•'
25	Sub ViewFooter()
26	' Переключает вид на нижний колонтитул документа
27
28	If ActiveWindow.ActivePane.View.Type wdPageView Then
29	ActiveWindow.ActivePane.View.Type = wdPageView
30	End If
31
32	ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageFooter
33
34	End Sub
35
36	Sub ResetShortcutKeys()
37	' Сбросить комбинации клавиш Ctrl+Shift+S и Ctrl+Shift+F
38	Dim aKey As KeyBinding
39
40	For Each aKey In Application.KeyBindings
41	If UCase(aKey.Command) = UCase("DisplaySummarylnfo") Or _
42	UCase(aKey.Command) = UCase("ViewFooter") Then
43	aKey.Clear
44	End If
45	Next aKey
46
47	End Sub
Листинг 19.16 содержит модуль с четырьмя процедурами. Первая процедура, SetShortcutKeys (строки 3-15), устанавливает два обработчика событий нажатия клавиш. Вторая процедура — Displayinfo (строки 18-23) — это обработчик первой комбинации клавиш; она отображает диалог Сведения документа. Третья процедура — ViewFooter (строки 21-29) — это обработчик второй комбинации клавиш; она переключает текущий вид окна, отображая нижний колонтитул документа. Последняя процедура, ResetShortcutKeys (строки 32-42), сбрасывает обработчики событий нажатия клавиш в исходное состояние.
Метод OnTime Word
Метод OnTime Word дает возможность выполнить процедуру VBA в определенное время и в определенный день. Этот метод полезен для установки обработчиков событий, имеющих отношение ко времени и датам и решающих следующий круг задач: автоматическое резервное копирование; выполнение плановых действий, отнимающих много времени, в те моменты, когда вы не работаете на рабочем месте (например, печать длинных документов); вывод напоминаний о приглашениях, встречах и т.д.
Метод OnTime Word немного отличается от метода OnTime Excel. Если вы вызываете метод OnTime в VBA Excel и VBA Word, то убедитесь в том, что вы уделили внимание различиям синтаксиса этих двух методов.
Общий синтаксис для метода OnTime Word имеет следующий вид:
СИНТАКСИС
Application.OnTime(When, Name, [Tolerance])
Обязательный аргумент When — это число, определяющее дату и время запуска обозначенной процедуры. Аргумент When может быть строкой, например
Использование обработчиков событий
535
"15/4 12:00", или последовательным значением даты. Обязательный аргумент Name — это строка, содержащая имя процедуры, которую вы хотите выполнить при наступлении момента времени, определенного аргументом When. Необязательный аргумент Tolerance определяет промежуток времени, в секундах, в течение которого Word будет «пытаться» выполнить процедуру Name, если он не может это сделать в момент времени, определенный аргументом When. Это происходит в тех случаях, когда в момент времени When на экране находится диалог или выполняется некоторая операция (например, сортировка).
В листинге 19.17 показан пример вызова метода OnTime Word.
Листинг 19.17. Применение метода OnTime Word
1	Sub SetOnTime ()
2	' Установить событие OnTime
3	Application.OnTime When:=Now + TimeValue("00:15:00”), _
4	Name:="RemindMe"
5
6 End Sub
7
8
9	Sub RemindAboutFone ()
10	1 Эта процедура выводит напоминание
11	MsgBox prompt:="Сейчас " & _
12	Format(Time, "h:mm AM/PM") &	_
13	vbCr & _
14	"Вы должны позвонить клиенту!"
15	End Sub
Листинг 19.17 содержит две процедуры. Первая процедура, SetOnTime (строки 1-6), вызывает метод OnTime, чтобы установить процедуру RemindAboutFone, которая будет выполнена через 15 минут после текущего момента времени. Процедура RemindAboutFone (строки 9-15) выводит текст напоминания (строки 11-14).
часть iv
Доступ к базам данных из приложений Microsoft Office
Глава 20
Введение в базы данных
Так уж повелось, что практически в каждой книге по Visual-системе программирования имеется глава (иногда и более), в которой уделяется немного внимания достаточно важному явлению современной жизни — работе с базами данных. Это связано и с попытками привлечь внимание читателя к данному изданию, и с возрастающей ролью баз данных в развитии современного общества, и с увеличением возможностей Visual-систем по обработке информации, организованной в виде баз данных. Учитывая это, мы также уделим некоторое внимание вопросам разработки VBA-приложений, использующим базы данных. Тем более что принципы применения баз данных в VBA являются общими для Microsoft-приложений.
Что такое «базы данных»?
Начнем с краткого введения в терминологию, в дальнейшем используемую в этой и следующих главах. Что такое «базы данных», какие бывают типы баз данных? Базы данных — это системы, цель которых — та же, что и у файловых систем (различных операционных систем), а именно, сохранение данных конечного пользователя и управление этими данными. В отличие от файловых систем системы управления базами данных (СУБД) сохраняют не только сами данные (структуры данных), но и связи между этими данными, а также способы доступа к этим данным. Базы данных — это системы, содержащие множество различных объектов (в некоторых системах вместе с процедурами обработки объектов), объединенных таким образом, чтобы клиенты этих баз (пользователи и приложения) имели возможность быстрого и эффективного доступа к этим объектам. Иногда базами данных называют не только сами данные, но и СУБД.
В общем случае под базой данных понимают систему, состоящую из пяти основных частей: аппаратных средств, программного обеспечения, бизнес-правил, данных и специалистов. Конечно, в книге, имеющей отношение к программному обеспечению, можно было бы не останавливаться на аппаратных средствах, но об этом следует обязательно помнить, если вам нужно объяснить, например, руководителю фирмы, что необходимо для создания базы данных, предназначенной для повышения эффективности управления фирмой.
К аппаратным средствам относятся все физические устройства, которые обеспечивают ввод, обработку, хранение и представление данных. Конечно, наиболее идентифицируемым устройством базы данных является компьютер (микрокомпьютер, миникомпьютер или универсальная ЭВМ). Большое значение имеют (и часто определяются спецификой базы данных) различные устройства ввода информации и представления обрабатываемых данных. Например, если база данных предназначена для поддержки бизнес-процессов магазина или склада, то в качестве устройств ввода информации часто используются разного рода сканеры, считывающие, например, заводские номера изделий и позволяющие таким образом «следить» за движением товаров. Если к данным базы необходим доступ с удаленных компьютеров, то важным компонентом базы является компьютерная сеть (например, в системе заказа железнодорожных или авиабилетов).
Под термином «программное обеспечение базы данных» обычно понимают СУБД. Правильнее было бы считать, что это — и программное обеспечение операционной системы, и СУБД, и прикладные программы и утилиты. Программное обеспечение операционной системы управляет всеми аппаратными компонентами
Введение в базы данных
539
и делает возможным выполнение всех других программ вычислительной системы. Известными операционными системами являются DOS, OS/2, Windows 2000/NT/ ХР, UNIX; не очень известными — VMS, MVS. Программное обеспечение СУБД (под управлением операционной системы) обрабатывает данные базы данных. Примерами наиболее известных СУБД являются Microsoft Access, Microsoft Fox Pro, Microsoft SQL Server, Oracle, Sybase SQL Anywhere и DB2. Прикладные программы и утилиты необходимы для доступа и манипулирования данными в базе в некоторой компьютерной среде и обычно используются для непосредственного вода данных и генерации отчетов, упрощающих процесс принятия решений.
Язык Visual Basic (как и многие другие языки Visual-систем программирования) не является языком баз данных в том смысле, что он не содержит команд и функций обработки записей файлов данных. Однако Visual Basic для управления базами данных использует процессор баз данных (database engine), т.е. систему «отвечающую» за хранение и выборку данных1. Процессор баз данных для Visual Basic, называется Microsoft Jet и представляет собой систему, используемую несколькими программными продуктами фирмы Microsoft.
Бизнес-цравила — это инструкции и правила, которые оказывают влияние на проектирование и использование базы данных. Бизнес-правила играют важную роль для компании, так как они налагают стандарты, в соответствии с которыми ведется бизнес, и определяют способы контроля как данных, вводимых в базу данных, так и информации, которая генерируется на основе этих данных.
Под данными понимают коллекцию фактов, сохраняемых в базе данных. Это — важнейшая составляющая базы данных. Поэтому особенно важно при создании базы данных определить, какие данные как будут храниться и обрабатываться базой.
Большое значение имеет состав специалистов, участвующий в работе с базой данных. Обычно выделяют пять типов таких специалистов: системные администраторы, администраторы баз данных, разработчики баз данных, системные аналитики/программисты и «конечные» пользователи. Системные администраторы следят за общими операциями баз данных. Администраторы баз данных обеспечивают надлежащее функционирование баз данных. Разработчики баз данных разрабатывают структуру базы данных и являются, фактически, архитекторами баз данных. Системные аналитики и программисты разрабатывают и реализуют прикладные программы, проектируют и создают экранные формы ввода данных и отчеты в соответствии с бизнес-правилами компании. Именно этими экранными формами и отчетами пользуются «конечные» пользователи для выполнения ежедневных операций компании и принятия стратегических решений.
Типы баз данных
Базы данных можно классифицировать в соответствии с числом пользователей, местоположением базы, ожидаемым типом и степенью использования. В зависимости от числа пользователей базы данных классифицируются как однопользовательские или многопользовательские. Однопользовательская база данных одновременно поддерживает только одного пользователя; другие пользователи не могут получить доступ к данным, если в данный момент времени какой-либо пользователь работает с базой данных. Если однопользовательская база данных установлена на персональном компьютере, она называется также настольной (desktop).
Многопользовательская база данных одновременно обеспечивает доступ к данным нескольким пользователям. Такая база данных может называться коллективной, если она используется относительно небольшим количеством пользовате
1 Программисты на языке С, в незапамятные времена «увлекавшиеся» базами данных, могут помнить первые версии подобных систем для работы с базами данных Paradox.
540
Глава 20
лей (не менее 50) или предназначена для работы некоторого отдела внутри компании. Если же база данных используется целым предприятием с большим количеством пользователей (более 50) нескольких отделов, то ее называют базой данных предприятия.
База данных может быть централизованной (centralized), т.е. находящейся в одном рабочем месте (на одной компьютерной системе), и распределенной (distributed), если находится на нескольких рабочих местах.
В настоящее время наиболее часто применяется классификация баз данных, которая отражает тип и степень использования базы. Например, информационная система может поддерживать сбыт продуктов или услуг, платежи и т.д. Такие транзакции являются критическими по времени и должны регистрироваться точно и немедленно. База данных, предназначенная для поддержки таких транзакций (непосредственного отклика), называется транзакционной (transactional). В такой базе данных очень важно поддерживать целостность и непротиворечивость данных.
База данных, которая используется для получения информации, необходимой для тактических и стратегических решений на среднем или высшем уровне управления компанией, называется системой поддержки принятия решений (decision support system). Для такой системы временной фактор обычно не является критически важным. Здесь обычно используются «исторические» данные или данные, полученные в результате предварительной обработки данных из различных источников (в том числе и агрегированные данные). Эти обстоятельства позволяют предположить, что структура системы поддержки принятия решений должна существенно отличаться от структуры данных транзакционной базы.
Функции систем управления базами данных
Системы управления базами данных выполняют много важных функций, большая часть из которых невидима «конечному» пользователю. Эти функции, включают управление хранением данных, их преобразование и презентацию, обеспечение безопасности, управление мультидоступом, резервное копирование и восстановление, интерфейсы прикладного программирования и взаимодействия с базой данных.
Средства СУБД позволяют создавать сложные структуры данных, освобождая разработчика базы данных от программирования физической организации данных, и обеспечивают хранение не только самих данных, но также форм для ввода данных, описаний отчетов, правил проверки корректности данных, кода с биз-нес-правилами и т.п. СУБД предоставляет процедуры резервного копирования и восстановления данных.
СУБД преобразует вводимые пользователями данные для их соответствия структурам данных, которые необходимы для хранения данных, т.е. освобождает пользователя от необходимости делать различие между логическим и физическим форматом данных. СУБД транслирует логические запросы в команды, которые локализуют и выбирают запрашиваемые данные, находящиеся на физических носителях.
Функцией СУБД является управление системой безопасности, которая обеспечивает конфиденциальность данных пользователя. Правила безопасности определяют, какие пользователи могут иметь доступ к базе данных, к каким именно данным и какие операции по обработке данных (чтение, добавление, удаление или модификацию) доступны тому или иному пользователю. Это особенно важно в многопользовательских базах данных, где одновременно к базе могут иметь доступ сразу несколько пользователей. Для обеспечения многопользовательского доступа СУБД / создает сложные структуры данных и использует сложные алгоритмы.
Введение в базы данных
541
Модель данных
В представлении информации в базах данных можно выделить два уровня абстракции: информационную модель, которая обычно бывает понятна пользователю этой базы, и физическую модель данных, которая связана с подробностями физического хранения данных в дисковых файлах. Информационная модель отображает программное обеспечение в терминах фактов, явлений, событий и предметов (а также связей между ними). Описание абстрактной информационной модели для представления в компьютере выполняется средствами модели данных, которую поддерживает СУБД. Средствами модели данных строится логическая схема информационной модели для внутреннего представления. При этом модель данных, которую поддерживает СУБД, определяется: допустимой структурой данных (разнообразием и количеством типов описываемых с помощью модели объектов), множеством допустимых операций над данными и ограничениями, необходимыми для обеспечения контроля за целостностью данных.
Модели данных, поддерживаемые СУБД, делят на сетевые, иерархические и реляционные. В этой связи различают сетевые, иерархические и реляционные СУБД. В настоящее время ведутся активные работы над созданием объектно-ориентированных СУБД, но эти работы существенно тормозятся отсутствием теории соответствующей модели данных.
Реляционная модель данных
На персональных компьютерах наибольшее применение нашли СУБД, поддерживающие реляционную модель данных, концепция которой была предложена Коддом Е.Ф., сотрудником компании IBM, при решении им задачи обеспечения независимости представления и описания данных от прикладных задач. В основе этой концепции — понятие отношения (relation), которое удобно описывается обычной таблицей. Кодд показал, что совокупность отношений может быть использована для хранения данных об объектах реального мира.
Например, некоторая фирма в качестве информационной системы имеет базу данных, состоящую из справочников товаров, торговых точек (складов, магазинов), таблиц наличия товаров. Для описания объекта «товар» можно построить следующее отношение (Товары):
Код	Наименование	Цена оптовая	Цена розничная
49019114414	Сабвуфер BSD 01	115	140
79019144420	Комплект акуст.МА-8008	100	130
49019142121	Усилитель АВ-209	250	270
46901923232	Громк.фронтальн. BS 809	190	230
39019105900	Громк.окруж.звука BSC 09	105	130
Колонки (столбцы) отношения называются атрибутами. Атрибуты имеют имена — заголовки. Каждая реализация объекта «товар» — строка в таблице — называется кортежем. Реляционная база данных — это совокупность взаимосвязанных отношений. Отношения реализуются посредством дисковых файлов. Между файлами, таблицами, отношениями и отображаемыми посредством отношений объектами имеются следующие соответствия:
файл	—►	таблица	—►	отношение	—►	объект
запись поле		строка колонка		кортеж атрибут		экземпляр свойство
542
Глава 20
Операции над отношениями
Кодд предложил применять к отношениям систему операций, позволяющую получать одни отношения из других, что позволяет делить информацию базы на хранимую и вычисляемую. Основными операциями над отношениями реляционной базы данных являются обычные операции над множествами: объединение (UNION), пересечение (INTERSECT), вычитание (DIFFERENCE), декартово произведение (PRODUCT), деление (DIVIDE); реляционные операции: проекция (PROJECT), соединение (JOIN) и выбор (SELECT). Эффективность конкретной СУБД определяется наличием и удобством использования тех средств, которые реализуют операции над отношениями. При рассмотрении операций над отношениями мы будем использовать следующие понятия:
	степень отношения — число входящих в отношение атрибутов;
	мощность отношения — число кортежей отношения;
	совместимые отношения — отношения, имеющие одинаковые степени и типы соответствующих атрибутов (можно также говорить, что они имеют совместимые схемы).
Объединение
Операция объединения (UNION) выполняется над совместимыми отношениями и имеет результатом отношение, которое включает все кортежи первого отношения и недостающие кортежи второго. Пример:
Отношение 1:
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	115	140
Комплект акуст.МА-8008	100	130
Отношение 2:
Наименование	Цена оптовая	Цена розничная
Усилитель АВ-209	250	270
Громк.фронтальн. BS 809	190	230
Громк.окруж.звука BSC 09	105	130
Результат операции объединения:
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	115	140
Комплект акуст.МА-8008	100	130
Усилитель АВ-209	250	270
Громк.фронтальн. BS 809	190	230
Громк.окруж.звука BSC 09	105	130
Введение в базы данных
543
Пересечение
Операция пересечения (INTERSECT) выполняется над совместимыми отношениями и имеет результатом отношение, содержащее только те кортежи первого отношения, которые имеются во втором. Пример:
Отношение 1:
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	115	140
Усилитель АВ-209	250	270
Комплект акуст.МА-8008	100	130
Отношение 2:
Наименование	Цена оптовая	Цена розничная
Громк.фронтальн. BS 809	190	230
Сабвуфер BSD 01	115	140
Комплект акуст.МА-8008	100	130
Громк.окруж.звука BSC 09	105	130
Результат операции пересечения:
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	115	140
Комплект акуст.МА-800в	100	130
Вычитание
Операция вычитания (DIFFERENCE) выполняется над совместимыми отношениями и имеет результатом отношение, содержащее только те кортежи первого отношения, которых нет во втором. Пример:
Отношение 1:
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	115	140
Усилитель АВ-209	250	270
Комплект акуст.МА-8008	100	130
Отношение 2:
Наименование	Цена оптовая	Цена розничная
Громк.фронтальн. BS 809	190	230
Сабвуфер BSD 01	115	140
Комплект акуст.МА-8008	100	130
Громк.окруж.звука BSC 09	105	130
544
Глава 20
Результат операции вычитания отношения 2 из отношения 1:
Наименование	Цена оптовая	Цена розничная
Усилитель АВ-209	250	270
Декартово произведение
Операция декартова произведения (PRODUCT) выполняется над отношениями, которые могут иметь разные схемы, и имеет результатом отношение, степень которого равна сумме степеней отношений-операндов, а мощность — произведению их мощностей. Пример:
Отношение 1:
Наименование
Сабвуфер BSD 01
Усилитель АВ-209
Комплект акуст.МА-8008
Отношение 2:
Цена оптовая	Цена розничная
190	230
115	140
Результат операции декартова произведения:
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	250	270
Сабвуфер BSD 01	115	140
Усилитель АВ-209	250	270
Усилитель АВ-209	115	140
Комплект акуст.МА-8008	250	270
Комплект акуст.МА-8008	115	140
Деление
Операция деления (DIVIDE) выполняется над отношениями, одно из которых — делитель — должно содержать подмножество атрибутов отношения-делимого. Результирующее отношение содержит только те атрибуты делимого, которых нет в делителе, и включает только те кортежи, декартовы произведения с делителем которых содержатся в делимом. Пример:
Отношение 1 (делимое):
Наименование	Цена оптовая	Цена розничная
Сабвуфер BSD 01	250	270
Сабвуфер BSD 01	115	140
Усилитель АВ-209	250	270
Введение в базы данных
545
Наименование	Цена оптовая	Цена розничная
Усилитель АВ-209	115	140
Комплект акуст.МА-8008	250	270
Комплект акуст.МА-8008	115	140
Отношение 2 (делитель):
Наименование
Сабвуфер BSD 01
Комплект акуст.МА-8008
Результат операции деления:
Цена оптовая	Цена розничная
190	230
115	140
Проекция
Операция проекции (PROJECT) выполняется над одним отношением. Результирующее отношение не имеет дублируемых кортежей и включает часть атрибутов исходного отношения, на которые выполняется проекция. Пример — проекция на атрибуты Наименование и Дата поступления (с целью, например, узнать даты поступления на фирму определенных товаров):
Подразделение	Наименование	Цена	Количество	Дата поступления
Склад №1	Сабвуфер BSD 01	6500	2000	01.08.2002
Склад №1	Усилитель АВ-209	5000	1000	01.12.2002
Склад №2	Сабвуфер BSD 01	6500	3000	01.10.2002
Склад №2	Комплект акуст.МА-8008	7000	2000	01.08.2002
Склад №2	Усилитель АВ-209	5000	1500	01.12.2002
Магазин №2	Усилитель АВ-209	5000	1230	01.12.2002
Результат выполнения проекции на атрибуты Наименование и Дата поступления:
Наименование	Дата поступления
Сабвуфер BSD 01	01.08.2002
Усилитель АВ-209	01.12.2002
Сабвуфер BSD 01	01.10.2002
Комплект акуст.МА-8008	01.08.2002
18 Программирование на VBA 2002
546
Глава 20
Соединение
Операция соединения (JOIN) выполняется над двумя или более отношениями, в каждом из которых должен присутствовать атрибут для соединения. Результирующее отношение включает все атрибуты первого и второго отношений. Пример:
Отношение 1:
Наименование	Код
Сабвуфер BSD 01	49019114414
Комплект акуст.МА-8008	79019144420
Усилитель АВ-209	49019142121
Громк.фронтальн. BS 809	46901923232
Громк.окруж.звука BSC 09	39019105900
Отношение 2:
Подразделение	Код	Цена	Количество	Дата поступления
Склад №1	49019114414	6500	2000	01.08.2002
Склад №1	46901923232	5000	1000	01.12.2002
Склад №2	49019114414	6500	3000	01.10.2002
Склад №2	79019144420	7000	2000	01.08.2002
Склад №2	49019142121	5000	1500	01.12.2002
Магазин №2	49019142121	5000	1230	01.12.2002
Результат операции соединения:
Подразделение	Наименование	Код	Цена	Количество	Дата поступления
Склад №1	Сабвуфер BSD 01	49019114414	6500	2000	01.08.2002
Склад №1	Громк. фронтал ьн. BS 809	46901923232	5000	1000	01.12.2002
Склад №2	Сабвуфер BSD 01	49019114414	6500	3000	01.10.2002
Склад №2	Комплект акуст.МА-8008	79019144420	7000	2000	01.08.2002
Склад №2	Усилитель АВ-209	49019142121	5000	1500	01.12.2002
Магазин №2	Усилитель АВ-209	49019142121	5000	1230	01.12.2002
Выбор
Операция выбора (SELECT) выполняется для всех кортежей, найденных в отношении. Результирующее отношение содержит подмножество выбранных кортежей. Пример:
Введение в базы данных
547
Исходное отношение:
Подразделение	Наименование	Цена	Количество	Дата поступления
Склад №1	Сабвуфер BSD 01	6500	2000	01.08.2002
Склад №1	Громк.фроцтальн. BS 809	5000	1000	01.12.2002
Склад №2	Сабвуфер BSD 01	6500	3000	01.10.2002
Склад №2	Комплект акуст.МА-8008	7000	2000	01.08.2002
Склад №2	Усилитель АВ-209	5000	1500	01.12.2002
Магазин №2	Усилитель АВ-209	5000	1230	01.12.2002
Результат выбора всех строк:
Подразделение	Наименование	Цена	Количество	Дата поступления
Склад №1	Сабвуфер BSD 01	6500	2000	01.08.2002
Склад №1	Громк.фронтальн. BS 809	5000	1000	01.12.2002
Склад №2	Сабвуфер BSD 01	6500	3000	01.10.2002
Склад №2	Комплект акуст.МА-8008	7000	2000	01.08.2002
Склад №2	Усилитель АВ-209	5000	1500	01.12.2002
Магазин №2	Усилитель АВ-209	5000	1230	01.12.2002
Результат выбора всех строк, для которых в поле Подразделение содержится значение «Склад №2»:
Подразделение	Наименование	Цена	Количество	Дата поступления
Склад №2	Сабвуфер BSD 01	6500	3000	01.10.2002
Склад №2	Комплект акуст.МА-8008	7000	2000	01.08.2002
Склад №2	Усилитель АВ-209	5000	1500	01.12.2002
Следует отметить, что большинство СУБД поддерживают только такие ключевые операции, как SELECT, PROJECT и JOIN. Существует очень мало СУБД, которые поддерживают все восемь рассмотренных операций.
Языки для выполнения операций над отношениями в реляционной СУБД делят на два основных класса: языки реляционной алгебры и реляционного исчисления. Первые из них основываются на реляционной алгебре и являются процедурными, так как, записывая последовательности операций над отношениями в соответствующем порядке, можно получать желаемый результат. Языки реляционного исчисления, не являясь процедурными, основываются на классическом исчислении предикатов и предоставляют набор правил для записи запросов к базе данных. Запрос содержит информацию о желаемом результате.
Первый язык реляционного исчисления Alfa был разработан самим Коддом. В настоящее время широко используется язык структурированных запросов SQL (Structured Query Language), разработанный фирмой IBM.
18*
548
Глава 20
Связи между отношениями
Отношения реляционной базы данных в зависимости от содержания подразделяют на объектные1 и связные. Объектные отношения предназначены для хранения информации об экземплярах, в то время как связные отношения имеют целью связывать между собой экземпляры, хранящиеся в объектных отношениях.
В объектном отношении один из атрибутов всегда однозначно идентифицирует отдельный экземпляр сущности (объекта реального мира). В соответствующем этому атрибуту поле (дискового) файла хранится неповторяющаяся информация. Такой атрибут чаще всего используется в качестве ключевого и называется ключом отношения. Например, в отношении Товары в качестве ключевого, конечно же, следует выбрать атрибут Код_товара. Ключ отношения может включать несколько атрибутов и даже являться результатом выражения (в которое могут входить различные атрибуты). Далее будут приведены примеры с использованием подобных ключей.
В качестве еще одного примера объектного отношения приведем таблицу-справочник складов и магазинов фирмы, где могут находиться товары. Назовем ее Подразделения:
Подразделения
Код_подразделения	Наименование_подразделения	Телефон
1518	СКЛАД №01	222-35-33
1346	СКЛАД №02	320-90-90
0220	МАГАЗИН №01	241-09-09
0240	РОЗН.МАГ.№10	333-44-44
Ключом этого отношения, конечно же, должен быть атрибут Код_подразделения.
Связное отношение содержит ключи двух или более отношений для связи отношений. Например, используя отношения Товары и Подразделения можно определить связное отношение для хранения данных о количестве товаров в различных подразделениях фирмы (Запасы).
Товары
Наименование	Код_товара
Сабвуфер BSD 01	49019114414
Комплект акуст.МА-8008	79019144420
Усилитель АВ-209	49019142121
Громк.фронтальн. BS 809	46901923232
Громк.окруж.звука BSC 09	39019105900
Запасы
Код_подразделения	Код_товара	Количество	Дата_поступления
0220	49019114414	2000	01.01.2000
0220	79019144420	2332	01.12.1999
0220	49019142121	11222	01.10.2000
Здесь этот термин не имеет отношения к концепции объектно-ориентированного программирования.
Введение в базы данных
549
Код_подразделения	Код_товара	Количество	Дата_поступления
0240	49019114414	12343	01.11.2000
0240	79019144420	23	08.11.2000
1346	49019114414	22343	07.12.2000
1346	79019144420	1133	07.09.2000
1346	49019142121	77666	10.08.2000
1346	39019105900	12321	11.10.2000
1518	49019114414	778891	11.11.2000
1518	79019144420	34	21.11.2000
Как видно из последнего примера, код одного и того же склада, как и код товара, могут встречаться в отношении Запасы несколько раз. Каждая строка этого отношения отображает наличие определенного товара на некотором складе. Например, первая строка отображает тот факт, что в магазине с кодом 0220 [МАГАЗИН №01 — см. отношение Подразделения] находится товар с кодом 049019114414 [Сабвуфер BSD 01 — см. отношение Товары] в количестве 2000 единиц, поступивший в магазин 01.01.2000 (дата). Вторая строка сообщает о том, что в этом же магазине имеется товар с кодом 079019144420 [Комплект акуст.МА-8008] в количестве 2332 единиц. И так далее.
Как вы уже могли заметить, связное отношение, кроме связываемых ключей, может иметь и другие атрибуты (в примере Запасы — это Количество, Дата_по-ступлеиия). Ключи в связных отношениях называются внешними, поскольку являются первичными ключами других отношений.
Самой простой связью между отношениями (таблицами) является связь «одии-к-одиому», при которой одному кортежу первого отношения соответствует только один кортеж во втором. Такая связь обычно используется при разделении отношений, имеющих большое количество атрибутов.
Наиболее часто в программировании приложений баз данных используется связь «один-ко-многим», которая позволяет поставить в соответствие один кортеж первого отношения нескольким кортежам второго отношения при помощи первичного ключа первого отношения и внешнего ключа второго отношения. Последний пример с использованием отношений Товары, Подразделения и Запасы — это типичный пример связи «один-ко-многим». Здесь отношение Товары связано с отношением Запасы при помощи первичного ключа Код_товара, а отношение Подразделения связано с отношением Запасы при помощи первичного ключа Код_подраз-деления. При этом в отношении Запасы атрибуты Код_подразделения и Код_това-ра являются внешними ключами. Обычно связи, о которых идет речь, схематично обозначаются так, как показано на рис. 20.1 (получена в Microsoft Access) или на рис. 20.2 (получена в ERWin).
Рис. 20.1. Схема связей таблиц базы данных в Access
550
Глава 20
Подразделения___________
Код_подразделения
Наименование_подразделе Телефон
Запасы_________
Код_товара (FK) Код_подразделения (FK)
Количество
Дата_поступления
Рис. 20.2. Схема связей таблиц базы данных в ERWin
Товары_____________
КодТовара
НаименованиеТовара
В поле таблицы базы данных могут храниться различные типы данных. Обычно в момент создания таблицы для каждого поля указываются наименование, тип хранимых в нем данных, длина данных (число знаков после десятичной точки для действительных чисел). В некоторых системах (к ним относится и Access) указывается дополнительная информация, в том числе и форматирование данных при отображении. Кроме того, реляционные СУБД имеют механизмы (разные у разных СУБД) задания ключевых полей и связей между таблицами (при помощи ключевых полей). Если при этом СУБД позволяет представлять связи между таблицами графически, разработчик базы данных получает дополнительные преимущества.
Ограничения реляционной модели
На внешние ключи реляционной моделью накладывается ограничение, называемое ссылочной целостностью. Оно состоит в том, что каждому внешнему ключу должна соответствовать строка какого-либо объектного отношения. В противном случае внешний ключ не будет ссылаться ни на какой объект в базе данных.
Другое, не менее важное, ограничение реляционной модели — отношения должны быть нормализованы. Это, в частности, означает, что каждый атрибут отношения должен быть простым. Например, недопустимо следующее отношение:
Код товара	Наименование товара	Цена	
		оптовая	розничная
049019114414	Сабвуфер BSD 01	115,0	140,0
079019144420	Комплект акуст.МА-8008	100,0	130,0
049019142121	Усилитель АВ-209	250,0	270,0
469019145021	Громк.фронтальн. BS 809	190,0	230,0
039019105900	Громк.окруж.звука BSC 09	105,0	130,0
Это отношение содержит сложный атрибут Цена.
Нормализация отношений
Рассмотренные ранее отношения можно демонстрировать не только в качестве объектных и связных отношений, но и как пример нормализованных отношений реляционной базы данных. Эти отношения получились не сразу. Сначала для решения задачи о хранении товаров на складах и магазинах должна была появиться, например, следующая таблица (здесь не указан столбец с датами поступления товаров):
Наименование подразделения	Телефон	Наименование товара	Кол-во	Цена оптовая	Цена розничная
МАГАЗИН №01	241-09-09	Сабвуфер BSD 01	2000	115,0	140,0
МАГАЗИН №01	241-09-09	Комплект акуст.МА-8008	2332	100,0	130,0
Введение в базы данных
551
Наименование подразделения	Телефон	Наименование товара	Кол-во	Цена оптовая	Цена розничная
МАГАЗИН №01	241-09-09	Усилитель АВ-209	11222	250,0	270,0
Р03Н.МАГ.№10	333-44-44	Сабвуфер BSD 01	12343	115,0	140,0
РОЗН.МАГ.№10	333-44-44 ,	Комплект акуст.МА-8003	23	100,0	130,0
СКЛАД №02	320-90-90	Сабвуфер BSD 01	22343	115,0	140,0
СКЛАД №02	320-90-90	Комплект акуст.МА-8003	1133	100,0	130,0
СКЛАД №03	320-90-90	Сабвуфер BSD 01	77666	115,0	140,0
СКЛАД №03	320-90-90	Громк.фронтальн. BS 809	12321	190,0	230,0
СКЛАД №01	222-35-33	Сабвуфер BSD 01	778891	115,0	140,0
СКЛАД №01	222-35-33	Комплект акуст.МА-8003	34	100,0	130,0
Представьте, что вы ведете учет не на компьютере, а на бумажном носителе информации. У вас, имеется 5-10 складов и магазинов и 50-100 наименований товаров. Не очень ленивый сотрудник напечатал таблицу, подобную вышеприведенной, а кто-то другой аккуратно меняет значения количеств товаров по мере их продажи и закупки. Кстати, это можно делать и при помощи, например, Excel.
А потом некто (видимо, один из менеджеров) решил изменить все и сразу, наименования (даже хотя бы одно!) складов или магазинов, наименования товаров и цены.
Простой вопрос: в каком случае даже на бумаге легче и без ошибок можно было бы исправить данные — при учете с одной (последней) таблицей или с тремя, ранее рассмотренными?
Этот пример предваряет введение в понятие нормализации отношений в реляционной базе данных. Отношения в реляционной базе данных должны удовлетворять двум основным требованиям:
	между атрибутами не должно быть нежелательных функциональных зависимостей;
	группировка атрибутов должна обеспечивать минимальное дублирование данных.
Для выполнения этих требований используется нормализация отношений — пошаговый обратимый процесс декомпозиции исходных отношений базы данных на более простые отношения. С процессом нормализации связаны нормальные формы, каждая из которых ограничивает типы допустимых функциональных зависимостей отношений.
	Если для некоторых атрибутов А и Б всегда каждому значению А соответствует не более одного значения Б, то говорят, что атрибут Б функционально зависит от А.
	Если неключевой атрибут зависит только от части ключа, то говорят о частичной зависимости.
	Если неключевой атрибут зависит от всего составного ключа и не находится в частичной зависимости от его частей, то говорят о его полной функциональной зависимости от составного ключа.
552
Глава 20
	Если для некоторых атрибутов А, Б и В выполняются условия: Б функционально зависит от А и В функционально зависит от Б, а обратная зависимость отсутствует, то говорят, что В транзитивно зависит от А. Например, цена товара транзитивно зависит от кода товара.
	Если в отношении каждому значению атрибута А соответствует множество значений атрибута Б, не связанных с другими атрибутами (этого же отношения), то говорят, что атрибут Б многозначно зависит от А.
Кодд выделил три нормальные формы1 и предложил правила последовательного приведения отношений к нормализованному виду.
Отношение находится в первой нормальной форме, если все неключевые атрибуты функционально зависят от ключа. Для приведения к первой нормальной форме исходные данные (самая общая таблица с данными) разделяются на логически связанные таблицы, в большинстве из которых определяются первичные ключи. В такой совокупности таблиц не должно содержаться повторяющихся данных.
Отношение находится во второй нормальной форме, если оно находится в первой нормальной форме и каждый неключевой атрибут функционально полно зависит от составного ключа. Таким образом, для приведения отношения к этой форме нужно поместить в отдельную таблицу данные, которые только частично зависят от первичного ключа. По Кодду следует построить проекцию1 2 без атрибутов, которые находятся в частичной функциональной зависимости от составного ключа, а затем построить проекцию на часть составного ключа и атрибуты, зависящие от этой части.
Отношение находится в третьей нормальной форме, если оно находится во второй нормальной форме и в нем отсутствуют транзитивные зависимости неключевых атрибутов от ключа. Целью приведения отношения к третьей нормальной форме является устранение из него данных, не зависящих от первичного ключа.
В рамках этой книги мы не будем далее углубляться в теоретические «лабиринты» реляционных баз данных, поскольку на полках книжных магазинов можно найти достаточно специализированной литературы по базам данных. К тому же на практике часто удается сразу сформировать базу из нескольких отношений, отвечающих третьей нормальной форме. С другой стороны, работая с таким языком, как SQL, иногда приходится думать о том, что отношения в базе данных излишне нормализованы, что влияет на производительность СУБД.
Базы данных в Excel
Простые (состоящие из одной таблицы) базы данных можно создавать в среде Excel. Например, заполните в качестве заголовков полей будущей таблицы базы данных три ячейки листа Excel, как показано на рис. 20.3.
Выделите зти три ячейки и выберите Файл | Сохранить как. В окне Сохранение документа в текстовом окне Тип файла выберите, например, DBF 4 (Dbase IV). Закройте Excel-файл без сохранения выполненных изменений.
Практически, вы только что получили, быть может, вашу первую базу данных, хотя и в очень «стареньком» для отрасли программирования формате.
При помощи двойного щелка на значке записанного dbf-файла запустите Excel3. Обратите внимание (рис. 20.4) на заголовки полей таблицы: они содержат не более 10-ти символов. Это связано с тем, что в формате DBF заголовок поля не
1 В настоящее время определены семь нормальных форм.
2 Проекция — операция реляционной алгебры, создающая новую таблицу путем исключения «ненужных» столбцов из имеющейся таблицы.
3 Для этого нужно, конечно, чтобы Windows «понимал», что dbf-файлы вызывают запуск Excel, а не, например, FoxPro или какое либо другое приложение, обрабатывающее файлы в DBF формате.
Введение в базы данных
553
Рис. 20.3
Заголовки будущей таблицы базы данных
Е2 Microsoft Excel Книга!
Файл Правка £ид Вставка Формат Сервис Данные
£>кно ^правка	- S X
«> ’ Г ’ н Й Щ V К » f* Цена
В ~“
1 [Наименование Количество 2 3
4 '
5 6 7
8
9 ‘
к < ► >i\Лист1/Лист2/ЛистЗ/| < *
Готое	NUM
С1_____
А
может включать более 10-ти символов. Кроме того, заметьте, что все символы заголовков — прописные, и, наконец, книга Excel содержит только один лист: одна таблица — один лист.
Рис. 20.4
Заголовки полей таблицы содержат не более 10-ти символов
Сразу после загрузки dbf-файла выберите Данные | Форма. На экране появится окно, приведенное на рис. 20.5, которое позволяет добавлять, редактировать и удалять (при помощи кнопок Добавить, Удалить) записи таблицы из трех полей, осуществлять «навигацию» по записям (при помощи кнопок Далее, Назад), использовать фильтрацию данных (при помощи кнопки Критерии).
Рис. 20.5
Окно, которое позволяет добавлять и удалять записи таблицы из трех полей, осуществлять «навигацию» по записям, использовать фильтрацию данных
554
Глава 20
Введите в каждое текстовое поле какую-либо информацию и щелкните на кнопке Добавить. Сразу после этого во второй строке Excel-листа появятся введенные вами данные, как показано на рис. 20.6.
Рис. 20.6
При введении первой записи во второй строке Excel-листа появятся введенные вами данные
Mi*| £аил Оравка Вид Встарка Форцат Сервис Данин X Ч» ‘Ч • <
А НАИМЕНОВАН
В	С
^КОЛИЧЕСТВО ЦЕНА
100	115
Кни1*1
А1
_1 [НАИМЕНОВАН
2 Сабвуфер BSD 01
3
НАИМЕНОВАН f
КОЛИЧЕСТВО f
ЦЕНА f
Новая запись
Добавить
Назад
Далее
9
10'
Критерии
2акрь ть
12
13
и 1 » »|\Книга1/ Готово
Если вы введете более одной строки (в терминологии баз данных — записи), ваши данные могут быть такими, как приведены на рис. 20.7. Обратите внимание на то, что в верхнем правом углу формы отображается номер текущей записи и общее количество записей ("1 из 14").
Рис. 20.7
В верхнем правом углу формы отображается номер текущей записи и общее количество записей ( 1 из 14")
файл Правка Вид
56
НАИМЕНОВАН
Сабвуфер BSD 01
Комплект акуст MA800S
Усилитель АВ 209
Громк фронтальн BS809
5 Гг.....тг------- ....
£ (Player 903KBS
" Player АВ 908S CD RW SONY PS 7002 (RP) SONY PS MX чип 7002 SONY PS MX чип 9002 SONY PS NTSC (chip) SONY PS PAL SONY PS PAL MX чип
8 9
10
12 13
и « » >\«нига1/
Готово
Вставка Формат С^еис
* Ъ ’ W 5» 1000 в с
КОЛИЧЕСТВО ЦЕНА 115 100 250 190 195 165 128 120 165 175 175 160
Данные | я
KjiMiel
НАИМЕНОВАН
КОШТ-ЕСТВО
(ZDOO
2000 2332
11222 12231
loooi 1000 1000
900
900
800
900 1900
ЦЕНА
Удалить j
Назад
Далее |
2
3
D

При помощи кнопок Назад и Далее вы можете перемещаться по записям таблицы. Причем, это очень похоже на перемещение по записям базы данных. Еще больше на работу с записями базы данных похоже использование фильтрации при помощи кнопки Критерии. Щелкните на ней и в текстовом окне КОЛИЧЕСТВО введите > 1000, что означает вывод в форме только тех записей, для которых значения поля КОЛИЧЕСТВО больше 1000.
Импорт данных в Excel из баз данных
Если мы имеем возможность создавать dbf-файлы в Excel, значит, мы можем также загружать из Excel базы данных (таблицы) формата DBF. Таким образом, Excel очень хорошо «понимает» формат данных такой СУБД, как dBASE, и может как считывать, так и записывать таблицы в формате DBF. С большинством других баз данных Excel имеет одностороннюю связь, т.е. может только импортировать таблицы.
Введение в базы данных
555
Для импорта данных в Microsoft Excel следует использовать команду Импорт внешних данных меню Данные, при выборе которой на экран выдается диалоговое окно Выбор источника данных, приведенное на рис. 20.8. В этом окне уже могут находиться элементы подключения, которые вы (или ваши товарищи по совместному использованию персонального компьютера) определяли ранее (см. рис. 20.17).
Рис. 20.8
Диалоговое окно для выбора источника данных
Для подключения к базе данных Access необходимо в этом окне выделить элемент +Подключение к новому источнику данных и щелкнуть кнопку Открыть (можно, конечно, просто дважды щелкнуть этот элемент). Затем в окне Мастер подключения данных (рис. 20.9) следует выбрать в списке Выберите тип источника данных, к которому нужно подключиться элемент Дополнительно и щелкнуть кнопку Далее. Эти источники могут включать источники данных OLE DB и любые источники данных, поставляемые системным администратором. В мастере подключения данных нельзя фильтровать или объединять данные.)
Рис. 20.9
В списке Выберите тип источника данных, к которому нужно подключиться следует выделить элемент Дополнительно и щелкнуть кнопку Далее
Мастер „ОДИЛ10ЧСНИЯ данных
Мастер подключения данных
Мастер поможет подключить удаленный источник данных
lW[
выберите тип источника даннык которому нужно подключиться
Microsoft SQL Server
Службы OLAP Microsoft SQL Server
ODBC DSN
Oracle

Отмена
Далее >
Остается в появившемся окне Data Link Properties (рис. 20.10) выделить Microsoft Jet 4.0 OLE DB Provider и щелкнуть кнопку Next», чтобы, наконец, увидеть на экра-
556
Глава 20
не окно (в котором можно указать имя mdb-файла1), с одной из таблиц которого необходимо установить связь (рис. 20.11).
Рис. 20.10
Для подключения к базе данных Access следует выделить Microsoft Jet 4.0 OLE DB Provider и щелкнуть кнопку Next»
W*i Data Link Properlies...	fx!
Provider | Connection | Advanced AH |
S elect the data you want to connect to:
MediaCatalogDB OLE DB Provider MediaCatatogMergadDB OLE DB Provider MediaCatalogWebDB OLE DB Provider Microsoft ISAM 11 OLE DB Provider Microsoft Jet 3 51 OLE DB Provider
;м=ск>?*гЫ-н OLE de: Pi.%~
Microsoft OLE DB Provider For Date Mmg Services Microsoft OLE DB Provider for Indexing Service Microsoft OLE DB Provider for Internet Publishing Microsoft OLE DB Provider for ODBC Drivers Microsoft OLE DB Provider for OLAP Services 8 0 Microsoft DLE DB Provider for Oracle Microsoft OLE DB Provider for SQL Server Microsoft OLE DB Smple Provider MSDalaShape OLE DB Provider for Microsoft Directory Services
| Hext» 1
OK i Отмена Справка
Рис. 20.11
Окно, в котором можно указать имя mdb-файла
Data Link Properties
fx:
Provider Connection Advanced Al!
S elect the data you want to connect to
OLE 0B Providers)
MediaCatalogDB OLE DB Provider MediaCatalogMergedDB OLE DB Provider MeciaCatatogWebOB OLE DB Provider Microsoft ISAM 1 1 OLE DB Provider Microsoft Jet 3 51 DLE DB Provider
[Mr 40 fO vB hcAnw
Microsoft OLE DB Provider For Data Mining Services Microsoft OLE DB Provider for Indexing Service Microsoft OLE DB Provider for Internet Publishing Microsoft OLE DB Provider for ODBC Drivers Microsoft OLE DB Provider for OLAP Services В 0 Microsoft DLE DB Provider foi Oracle Microsoft OLE DB Piovidet for SQL Server Microsoft OLE DB Smple Provider MSDalaShape
OLE DB Provider for Microsoft Directory Services
OK , Отмена j Справка
Чтобы убедиться в том, что подключение выполнено успешно, необходимо щелкнуть кнопку Test Connection. Если на экране появится окно, похожее на приведенное на рис. 20.12, то все — в порядке.
Рис. 20.12
Так Microsoft сообщает пользователю об успешном подключении к источнику данных
Microsoft Data Link ... Д
Test connection succeeded
1
Файлы Microsoft Access имеют расширение mdb.
Введение в базы данных
557
Проверив успешность подключения, следует щелкнуть кнопку ОК и в следующем окне (рис. 20.13) указать таблицу, которая будет загружаться в лист Excel при данном подключении.
Рис. 20.13
Здесь следует указать таблицу, которая будет загружаться в лист* Excel при данном подключении
i
Мастер подмшвчения данных выбор данных
Выбор базы данных и таблицы
Выберите базу данных и таблицу или куб содержащие нужные данные
Выберите базу данных, содержащую нужные сведения
Р” Подключение к определенной таблице
Имя	Описание
□T1NACL2C
Q T1NC	Временная таблица для записи инвентаризациннои ведомости и
□	tlnc_temp
О t2_dop
ПТ2С
Отз
□	TGROUP
Г	>
Отмена
< Назад
Готово ।
В окне Мастер подключения данных-выбор данных можно закрепить за выбранным набором данных некоторое описание. Щелчком на кнопке Готово выбор данных завершается.
Рис. 20.14
В окне Мастер подключения данных - выбор данных можно закрепить за выбранным набором данных некоторое описание
Mdcicp подключения данных Готово

Сохраните файл подключения данных и завершите работу
Введите имя и описание файла подключения данных, а затем нажмите кнопку Готово" для его сохранения
Обзор
Имя файла
|(по умолчанию) tmpOl ode
Г* Сохранить пароль в файле
Описание
Поиск ключевых слов
Отмена < Назад (
Готово
Окно Импорт данных, приведенное на рис. 20.15 позволяет указать место, куда следует поместить данные из выбранного источника.
Рис. 20.15
Окно позволяет указать место, куда следует поместить данные из выбранного источника
558
Глава 20
Как можно видеть из рис. 20.16, в mdb-файле хранится обыкновенная таблица, которую мы легко можем расположить в ячейках листа Excel.
Рис. 20.16
В следующий раз, когда будет необходимо подключиться к этой же таблице, уже не нужно проходить такой длинный путь Достаточно выбрать Данные | Импорт внешних данных и в окне Выбор источника данных найти результат предыдущих стараний
О Microsoft Excel Книга!	I* liHjfXj
&*| £анл Правка Вид Вставка Формат		Сервис	Данные Окно Справка	- S X	
D	айн SB?	&	’ «1 tt XI “	ж к ”
	А1	-	А			
	А	в	С	‘	0	Е —
 1	|Наиненование	)л во Олтов цена Закуп цен		а
2	(ЗОС) Cool Boarders BURRRN	100	60	0
3	(3DC) Evolution	200	50	0
4	(3DC) Cool Boarders BURRRN	345	50	0
5	(A) DROM SonyPS30 blocks	200	3	0
6	(A) OROM SonyPS Naki	200	165	0
 7	(PC CD) Корабль похищенных душ	290	4	0
I 8	(PC CD) Корлевство снов	200	25	0
9	(PC CD) Красная Шапочка	300	25	0
} 10	(PC CD) Макс и секретная форму	200	25	0
111	(VCD) Белые волки	300	35	0
I 12	ffll Bal 002 (Tuf/Ch&/Ch&2/Ch3r	300	1 9	о
К	► и \Лист1 X ЛистЗ X ЛистЗ /		HI	I	► г
Г отово			CAPS	
Следует отметить, что мы не открыли mdb файл, как это возможно с dbf файлом Речь идет о том, что из некоторой таблицы mdb-файла можно считать данные в Excel-лист
Рис. 20.17
В следующий раз, когда будет необходимо подключиться к этой же таблице, достаточно выбрать Данные | Импорт внешних данных и указать источник в списке
При создании нового источника данных Excel-приложением был создан ODC-файл, который можно открыть для просмотра в обозревателе Microsoft Internet Explorer, а для редактирования использовать Microsoft Excel, блокнот (приложение Notepad) и другие приложения Microsoft Office, если файл не указывает на источник данных OLAP.
Папка, в которой находится ODC-файл (вместе с другими файлами'для подключения к источникам данных) указывается в поле Папка диалогового окна Выбор источника данных
На рис. 20.18 приведено окно с текстом ODC-файла (частью текста), который только что был создан для импорта таблицы из MDB-файла.
Введение в базы данных
559
Рис. 20.18
ODC-файл можно редактировать при помощи текстовых редакторов Microsoft
Как видно из рис. 20.18, для редактирования такого файла нужно вообще-то знать его структуру (и язык XML), но чтобы убедиться в том, что это действительно возможно, можно вместо имени таблицы tmpOl, записать имя t2c. После такой замены можно увидеть, что при выборе источника с именем (по умолчанию) tmpOl из окна Выбор источника данных в Excel будет загружаться именно таблица t2c.
Аналогичным образом можно выполнить подключение к таблице некоторой базы данных, хранящейся на SQL Server удаленного компьютера. При этом, конечно, у вас должны быть соответствующие полномочия. Следующий пример показывает последовательность подключения к базе данных ServiceCenter, находящейся на сервере с именем VOVA (это — не имя пользователя, но — имя сервера).
В окне Выбор источника данных (рис. 20.17) следует выбрать +новое подключение к SQL-серверу. В появившемся на экране окне (рис. 20.19) остается указать имя сервера и пользователя, а также — пароль. Если вы еще не являетесь пользователем SQL Server, то можете установить эту систему даже на свой компьютер или обратиться к системному администратору, если, конечно, это каким-либо образом связано с вашей служебной деятельностью (вряд ли системный администратор сделает вас пользователем SQL Server для удовлетворения вашего любопытства).
Рис. 20.19
Здесь необходимо указать имя сервера и пользователя, а также — пароль

MdGinp подключения данных
Подключение к серверу баз данных
Введите сведения, требуемые для подключения серверу баз данных
1 Дмя сервера, Гуо'уд'
2 Учетные сведения
Г" Использовать систему безопасности windows 2000 (• Использовать следующие имя пользователя и пароль
Имя пользователя |6нм"' Пароль' [♦***
Отмена
< Назад | Далее »
После щелчка на кнопке Далее (в окне Мастер подключения данных) в следующем окне (рис. 20.20) можно увидеть все таблицы указанной базы данных.
560
Глава 20
Рис. 20.20
В этом окне можно увидеть все таблицы базы данных и выбрать ту, данные из которой будут помещаться Excel-лист
Мастер подключения данных -выбор данных
Выбор базы данных и таблицы
Выберите базу данных и таблицу или куб, содержащие нужные данные.
Выберите базу данных, содержащую нужные сведения:
IserviceCenter ..................... .........
$7 Подключение к определенной таблице1	*
Владелец Описание Изменен Создан dbo dbo dbo dbo dbo dbo dbo
Имя
Ш Детали
О Доступ
О Изделия
ШП Инвентаризация! Ей Инвентаризация2 ЕЙ Неисправности
10/29/2002 5 16 58 РМ
9/11/2002 10.28 28 AM
10/30/2002 5.39:58 РМ
9/10/2002 7.29.52 РМ
9/10/2002 7 29:54 РМ
10/30/2002 12:29.01 РМ
10/19/2002 6'28.55 РМ
Тип л
TABLE TABLE TABLE TABLE TABLE TABLE
TABLE v
Отмена
< Назад I ^алее >
Готово
1
В следующем окне можно изменить имя ODC-файла, если имя по умолчанию недостаточно «красиво», и описать созданное подключение.
Рис. 20.21
В этом окне можно изменить имя ODC-файла и описать созданное подключение
Мастер подключения данных -1 отово
Сохраните файл подключения данных и завершите работу
Введите имя и описание файла подключения данных, а затем нажмите кнопку "Готово" для его сохранения.
Обзор ..
Имя файла:
|¥О¥А ServiceCenter ОрганПродаж.одс
Описание:
>угш поОзВагВяям понять, к чему ьыгЩкййтЙ
Сохранить пароль в файле
Поиск ключевых слов:
Отмена |	< Назад ;	Готово
Окно Импорт данных уже не относится к созданию нового подключения и просто помогает указать место для размещения импортируемых данных.
Рис. 20.22
Окно Импорт данных помогает указать место для размещения импортируемых данных
На рис. 20.23 показан результат импорта данных из таблицы базы данных, находящейся на SQL Server локальной сети.
Введение в базы данных
561
Е? Microsoft Excel - Книга!			-НГх-
Файл	Прайса Вид Вставка Формат Сервис Данные	Окно Справка	’ - Я X
□ в а "4 v	'J «> - < ь - 4.		ДО ” ю - | ж к чк - <*» -	д v v
А1	▼	А		
	А	В	CD	Е	—‘
1 |КодИ|>гПрод|НдиОргП1>од	АдрИндекс АдрКраиОоласгь АдрГород			АдрУл
2	1 Нет сведении о продаже		
3	759343 000 ТЕЛЕТЕХНИКА"	Новосибирск	ул Дик
4	759502 ИП Савенко Сергеи Васильевич	Росто на Дону	ул Фр
1 5	759585 ПБОЮЛ Каменский А Ю	Ростов на Дону	ул Фр
6	759780 ПБОЮЛ Валерьянова Л Г	Ростов на Дону	ул Нел
7	760067 Нет сведении о продаже		
8	760169 ПБОЮЛ Першуков Игорь Викторович м	Новомосковск	ул Мос
9	760336 ООО "Навигатор В’	Москва	ул Дор
10	760410 Аэлита	Таганрог	ул фр'
11	760568 м н Дюал	Новосибирск	Пр KL
12	760694 ЗАО РИККОН	Москва	
13	760773 ТЦ Электронный Раи ПБОЮЛ Удоденко	Москва	
14	760861 000 ВИКТОРИЯ (отдел компьютеров)	Санкт Петербур	
; 15	761006 Предприниматель Колесников А М	Калуга	ул Либ
И 4 ► ►	\Лист1/Пист2 ^ПистЗ /	1<|	 1	иг
Готово			
Рис. 20.23. Результат импорта данных из таблицы базы данных, находящейся на SQL Server локальной сети
Как вы можете заметить, кроме создаваемых вами источников данных, в окне имеются дополнительные источники: Курсы валют MSN MoneyCentral Investor, Биржевые индексы MSN MoneyCentral Investor и Биржевые котировки MSN MoneyCentral Investor.
Рис. 20.24
В Excel-лист можно загрузить данные, используя встроенный источник Курсы валют MSN MoneyCentral Investor
О Microsoft Excel - КнигИ
файл Правка Вид Вставка Формат Сервис Данные Окно Справка
- в X
DB
Currency Rates Provided by MSN MoneyCentral Investor
Cl ck here t j vibit MSN Mo ~ieyOr tial i westor
2
3
ElName	In USS	Per USS
5	r j ntire Г г	0 28249	3 54
6 z нЧ alnn Dollar	0 5642	1 772
7 A jc-triar ~'rhill nej	0 07387	13 538
BjiWaiibanfi	0 0252	39 60[
9 Bahraini D nar	2 6525	0 377
10 Bolivian Boliviano	013558	7 376
11 Brazilian Real	0 28265	3 538
12 Bt t oh Pjund	1 5913	0 628
13 C anadtan Pollcti	0 63894	1 565
14 Chilean Peso	0 00141	(	711 2
и < ► н\Лист 1/ли:т2/Листа/ Готово		l«'
А
А
С
D
Е
В
Создание базы данных в Access
Обычная технология разработки приложений для баз данных с использованием систем программирования, не являющихся системами управления базами данных (СУБД), заключается в том, что собственно база данных (таблицы, связи между ними) создается при помощи интегрированной среды одной из СУБД, а интерфейс и код управления данными — при помощи Visual-системы программирования. Для Visual Basic более «родным» является mdb-формат, который поддержи вается СУБД Access. Поэтому в этом разделе мы рассмотрим вопросы создания баз данных в интегрированной среде Access.
562
Глава 20
bj Microsoft Ixc ol

Файл Правка £ид Вставка Формат Сервис Данные Окно справка
П О R*. X <?	< И 3 ” 18 ’ [*'*
А1 ▼	£ Stock Quotes Provided by MSN Money
MStock Quotes Provided by MSN Mone
2	Click here tn \isit MSN Morey
3
DOW JONES INDUSTRIAL
4	AVERAGE INDEX
5	DOW JONES COMPOSITE IN^FX . 6 UoyNpnosW^rort Идк
7	Dow Jones Utility lrde<
i 9 Frankfurt
9	SEISE.
10	Hong Kong Hang Seng AMEX INTERACTIVE WEEK
11	INTERNET lNDEX
II « > и\Лист1 \Лист2/ПистЗ/
Chart
Chart Chart ОШ Chart
Chart Ch&l
News
Mews News News News News News News
Last
8537 13
2378 79
2346 88
195,87
3079,1
4034 6
9770 6
81,34
Previous
Close
8586 24
2400 65
2350 62
202 28
3155 66
4081 3
9844 3
82 49
High
8668 91
2420,64
2382 21
201 95
3174 39
4091 6
9796 4
83,74
Low
8498 92
2371 84
2331 31
195,84
3072 81
4026 2
9708 1
80,86
Volume
250 130 000
_0 0. Cl _0
_0 0
Готово
Рис. 20.25. В Excel-лист можно загрузить данные, используя встроенный источник
Биржевые индексы MSN MoneyCentral Investor
СУБД Access позволяет разрабатывать законченные приложения с использованием баз данных. При этом и таблицы со всеми связями между ними, и код для обработки данных в этих таблицах находятся в одном mdb-файле. Кто-то считает, это удобным, а кто-то — наоборот. Мне больше нравится хранить данные отдельно от кода. Например, если база содержит данные, зависящие от текущего месяца и года (накладные продаж и прочее), то удобно хранить такие данные не только отдельно от кода, но и отдельно от других таблиц в отдельном файле. Представьте себе файл с базой данных, которая будет непрерывно расти с каждым месяцем. Ее трудно архивировать, переносить на съемных носителях, ну а если уж файл «разрушится», так со всеми данными за все месяцы и годы.
Кроме недостатка, связанного с хранением данных и обрабатывающего кода в одном месте, не совсем удобен способ создания этого кода в Access. Эта система изобилует специальными приемами и конструкторами, которыене только создают не всегда понятный код, но и требуют постоянной тренировки. Это очень похоже на программирование с использованием машинных команд. В случае длительного перерыва в работе можно потерять навыки, приобретенные упорным трудом. Хотя следует отметить, что разрабатывать приложение в рамках Access можно и без использования встроенных конструкторов, а просто писать код на языке Visual Basic, как это делается для Excel и Word. В этом случае VB-код будет отличаться от VB-кода для Excel и Word (и других приложений Microsoft Office) только в методах доступа к базам данных, поскольку Access — это СУБД.
Бизнес-задача: разработка базы данных для учета движения товаров на складе
В этом разделе мы рассмотрим вопрос создания базы данных, как набора взаимосвязанных таблиц, но предварительно попытаемся как можно лучше понять предметную область.
Итак, у нас имеется склад, с товарами которого выполняются следующие операции: 1) регистрация (как нового), 2) прием с другого склада, 3) прием из магазина (оптового или розничного), 4) возврат от (оптового) покупателя, 5) оптовая продажа, 6) отпуск на другой склад, 7) отпуск в магазин (оптовый или розничный). При отпуске (приеме) товара создаются накладные, с которыми производятся манипуляции, такие как аннулирование с восстановлением состояния склада, удале
Введение в базы данных
563
ние (без восстановления состояния склада), выделение части накладных (за указанный период времени) из общей базы для передачи в центральный офис, выделение накладных отпуска на некоторые склады для передачи их на эти склады с целью автоматической регистрации. Система должна также создавать определенные отчеты, например, по денежным суммам в накладных, инвентаризационную1 ведомость и, быть может, товарный отчет о движении товаров согласно накладным.
Структурное описание бизнес-процессов1 2, выполняемых на складе, приведено на рис. 20.26.
Рис. 20.26. Структурное описание бизнес-процессов, выполняемых на складе
Согласно этой схеме, полученной при помощи системы BPWin3 * * * * В, основными функциями бизнес-процессов на складе: являются отпуск и принятие товаров, а также учет товаров в виде инвентаризационной ведомости и накладных. Эти функции (в соответствии с правилами функциональных SADT-диаграмм) изображены в виде блоков. На диаграмме, кроме блоков с основными функциями, имеются дуги, которые определяют для бизнес-процессов: слева — входы, справа — выходы, снизу — средства (на данной диаграмме не указаны) и исполнителей, сверху — управление. Например, для формирования инвентаризационной ведомости необходимо иметь некоторую таблицу с наименованиями (и, может быть, ценами) товаров и знать о том, какие именно товары в данный момент имеются на складе. В процессе же отпуска товаров можно воспользоваться инвентаризационной ведомостью, чтобы, во-первых, зря не искать отсутствующий товар и, во-вторых, оформить выдачу товара в соответствии с его точным наименованием и ценой. При
1 Вместо этого термина в книге иногда используется термин «инвентарная» с целью сокращения длины названия таблиц.
2 К сожалению, автор не является специалистом в области структурного анализа и проектирования, поэтому представленная структура может содержать ошибки.
3 BPWin — система описания и моделирования бизнес процессов, являющаяся одним из инстру-
ментальных средств Методологии структурного анализа и проектирования (SADT — Structu-
red Analysis & Design Technique). Согласно исследованиям разработчиков SADT — Дэвида А.
Марка и Клемента МакГоуэна, наибольший процент ошибок при разработке программных
систем возникает в процессе анализа и проектирования и гораздо меньший — при реализации.
В тоже время исправление ошибки на стадии проектирования стоит в 2 раза, на стадии тестирования — в 10 раз, а на стадии эксплуатации — в 100 раз дороже, чем на стадии анализа.
564
Глава 20
этом также необходимо однозначно указать место, куда товар отправляется, для чего желательно иметь некоторый справочник, обозначенный на диаграмме как Таблица контрагентов. Процесс отпуска товара может иметь следствием создание накладной, которая является одним из документов о том, что товар не просто «ушел» со склада и исчез из инвентаризационной ведомости, а был передан в известное место в указанном количестве и с соответствующей ценой. После каждой операции с товарами требуется корректировка инвентаризационной ведомости, на что указывают дуги, связывающие выходы блоков 2 и 3 с управлением блока 1.
Далее мы будем рассматривать блоки диаграммы более подробно, а сейчас нас интересуют таблицы базы данных, которые необходимы для разработки информационной системы, поддерживающей бизнес-процессы, выполняемые на складе. Сейчас можно четко обозначить следующие из них: Таблица товаров, Инвентаризационная ведомость, Таблица контрагентов и Накладные (Заголовки накладных и Спецификации накладных).
Перед созданием базы данных хорошо было бы представить графически ее таблицы и связи между ними. Современные средства разработки баз данных не только позволяют представлять таблицы, но и ограждают разработчика от некоторых ошибок. На рис. 20.27 (логический уровень) и 20.28 (физический уровень) представлена схема базы данных1, состоящая из 6-ти таблиц, причем некоторые из них связаны при помощи ключевых полей.
Инвентаризационная ведомость
Рис. 20.27. Схема базы данных (логический уровень) из 6-ти таблиц
Таблица товаров (Товары) включает поле Код товара, которое будет содержать уникальное для каждого товара значение, однозначно определяющее товар (первичный ключ)1 2. Для этого поля нам достаточно 12-ти символов. Поле Наименование товара описывает товар; его длина зависит от действительных наименований товаров. Будем считать, что 30-ти символов нам достаточно.
Таблица Инвентаризационная Ведомость (Инвентарная_ведомость) содержит два внешних ключа3 (Код товара, Код склада) для связи с таблицами Товары и Склады и поле для указания количества товара. Поле Код склада необходимо для обслуживания одной базой данных нескольких складов. Если склад — один, в этом поле нет необходимости.
1 Схема создана в системе ERWin.
2 Система ERWin отделяет ключевые поля от не ключевых одинарной разделительной линией.
3 Система ERWin помечает внешние ключи символами (FK) — Foreign Key, — а блоки, обозначающие таблицы, содержащие внешние ключи, отображаются с закругленными углами.
Введение в базы данных
565
Инвентарная_ведомость
КодТовара VARCHAR(12)
КодСклада SMALLINT
Товары_________________________
КодТовара VARCHAR(12)__________
НаименованиеТовара VARCHAR(30) ЦенаОптовая DOUBLE PRECISION ЦенаРозничная DOUBLE PRECISION
НаклСпецификации________________
КодТовара VARCHAR(12)___________
Дата DateiTirne
Номер INTEGER
Количество Long Integer
ЦенаОлерации DOUBLE PRECISION
N.....—........-.......... ......
Количество INTEGER
НаклЗаголовки
КодКАгента SMALLINT КодСклада SMALLINT
Дата DateTTime Номер INTEGER ТипНакладной INTEGER
>	............. t ..Л
Склады
КодСклада SMALLINT____________
НаименованиеСкпада VARCHAR(4 Адрес Text(18)
Контрагенты____________________
КодКАгента SMALLINT____________
НаименованиеКАгента SMALLINT
Адрес Text(20)
Рис. 20.28. Схема базы данных (физический уровень) из 6-ти таблиц
Таблицы Склады и Контрагенты содержат подобные поля (включая первичные ключи) и при некоторых дополнительных строках кода в программном обеспечении разрабатываемой системы могли бы быть объединены в одну таблицу.
Для учета накладных удобно1 иметь две таблицы (Заголовки накладных и Спецификации накладных), в одной из которых могут храниться списки товаров (количества, цены) — спецификации, а в другой — общая для каждой накладной информация (коды складов и контрагентов, тип накладной) — заголовки. На рис.20.28 для этой цели изображены блоки с таблицами НаклЗаголовки и НаклСпецификации. В этих таблицах, как и в таблице Инвентарная_Ведомость, поле КодСклада необходимо для обслуживания одной базой данных нескольких складов. Если склад — один, в этом поле нет необходимости.
Создание таблицы в Access
Запустите Access, укажите, что создается новая база данных, и введите имя файла, в котором она будет сохранена (например, dbs.mdb). Если вы все сделаете правильно, то получите на экране окно, изображенное на рис. 20.29.
Выберите пункт Создание таблицы в режиме конструктора, и на экране появится окно, показанное на рис. 20.30.
Теперь можно создать таблицу в открытой базе данных. В столбце Имя поля укажите имя поля, в столбце Тип данных — тип. Для начала создадим таблицу Товары (рис. 20.31). В нижней части диалогового окна имеются настройки для дополнительного описания свойств атрибутов. Обратите внимание на изображение ключа слева от имени поля КодТовара. Это означает, что поле КодТовара является первичным ключом. В Microsoft Access очень просто указать ключевое поле: достаточно сделать в режиме конструктора нужное поле текущим и щелкнуть кнопку Ключевое поле на панели инструментов, которая, как вы можете заметить, меняет набор своих кнопок при смене режима работы Access.
Если вы не указываете ключевое поле, Access преложит создать специальное ключевое поле. Чаще всего следует отказываться от такого предложения.
1
Удобно для хранения наименьшего количества невычисляемой информации, но не очень удобно для обработки базы с использованием SQL запросов.
566
Глава 20
Рис. 20.29
Новая база данных в Access
Ы Microsoft Access
файл Правка Вид Вставка Сервис Окно Справка
п к? «а '?	- ил -	®.
dbs ; Раза ;цшных (с|х>рм<11 Access 7000)
£ЦОткрыть ^Конструктор □Создать -а > j';’
коздант табл»w в режиме конструктора!
Q Таблицы | Создание таблицы с помощью мастера _ея _	® j Создание таблицы путем ввода данных
запросы “*
з Формы я Отчеты 4j) Страницы 2 Макросы
Модули	'
Г руппы >1 Избранное
Г отово
Рис. 20.30
Создание таблицы в режиме конструктора

На рис. 20.32 приведена таблица Инвентарная_ведомость в режиме конструктора Access. Подобно выглядят и остальные таблицы, которые здесь не приводятся.
В Access имеется замечательная возможность связывания таблиц базы данных. После того как разработчик укажет необходимые связи (в том числе и их типы), СУБД будет не только более эффективно «работать» с записями в таблицах, но и будет защищать данные от неправильного их использования.
Для установления связей между таблицами можно щелкнуть кнопку Схема данных на панели инструментов или выполнить команду Сервис | Схема данных (или воспользоваться контекстным меню). Если ранее для данного набора таблиц схема данных не создавалась, на экране появится пустое окно Схема данных, в которое сначала следует помесить необходимые таблицы. Хотя для установки связей
Введениевбазь1даннь1х
567
Рис. 20.31
Только что созданная таблица в режиме конструктора Microsoft Access
Имя поля Я----------
i__ НаименованиеТовара
|__ЦенаОптовая
:_ЦенаРозничная
кодТова^
_____I Тип данных | Описание | л Текстовый
। Текстовый Денежный Денежный	v
Свойства поля
। Подстановка | 12
Общие Размер поля Формат поля Маска ввода Подпись Значение по умолчанию Условие на значение Сообщение об ошибке Обязательное поле Пустые строки Индексированное поле Сжатие Юникод Режим ХМЕ Режим предложений IME
Нет
Да
Да (Совпадения не допуо
Да
Нет контроля
Нет

можно помещать в окно Схема данных только связываемые таблицы, следует в целях документирования разработки помещать все таблицы базы в это окно. Поместить таблицы в окно позволяет диалог Добавление таблицы, который можно вызвать из контекстного меню окна Схема данных (рис. 20.33).
Рис. 20.32
Таблица без ключевых полей
После добавления всех таблиц к окну Схема данных оно может быть похоже на то, которое приведено на рис. 20.34.
Для установления связей между таблицами, следует расположить таблицы в окне Схема данных так, чтобы связные таблицы (отношения) располагались между связываемыми объектными, например, как это представлено на рис. 20.35.
Чтобы установить связь с таблицами Товары и Инвентарная_ведомость, щелкните на атрибуте КодТовара таблицы Товары и при нажатой левой кнопке мыши протащите курсор до аналогичного атрибута таблицы Инвентарная_ведомость (форма курсора должна заметно измениться). После этого отпустите кнопку мыши. На экране появится диалоговое окно Изменение связей (рис. 20.36), в котором вам следует (как минимум) установить флажок Обеспечение целостности данных.
На рис. 20.37 представлен результат установления связи между таблицами Товары и Инвентарная_ведомость, а на рис. 20.38 — результат установления всех необходимых связей (см. также рис. 20.27 и 20.28).
568
Глава 20
Рис. 20.33. Поместить таблицы в окно позволяет диалог Добавление таблицы, который можно вызвать из контекстного меню окна Схема данных
Рис. 20.34. Так может выглядеть окно Схема данных после добавления к нему всех таблиц рассматриваемой базы данных
Рис. 20.3S
Для установления связей между таблицами, следует расположить таблицы в окне Схема данных так, чтобы связные таблицы (отношения) находились между связываемыми объектными
Ej Microsoft Access [Схем* данных]
Файл Правка £ид Связи Сервис фено Справка
°П 8° §81 х С а ’ ©
D а#И «

I
•КодТовара
[Количество
- s х
:КодСклада
^НаименованиеСклада :Адрес
I КодТовара
НаймемсваниеТовара ЦенаОптовая |ЦенаРозничная
Дата
Номер КодСклада КодТоеера Количество

|Д<зта Номер КодСклада КодКАгента ТипНакладной
[КодКАгента
[НаимемованиеКАгента !
;АДрес
Готово
Введение в базы данных
569
Рис. 20.36
В окне Изменение связей вам следует (как минимум) установить флажок Обеспечение целостности данных
Рис. 20.37
Результат установления связи между таблицами
Товары и Инвентар-ная_ведомость
Рис. 20.38
Результат установления всех необходимых связей (см также рис 20 27 и 20 28)
Готово
Другие способы создания базы данных
Для создания базы данных Jet можно воспользоваться программой Visual Data Manager, которая поставляется в изданиях Visual Basic Professional и Enterprise и позволяет создать базу данных, совместимую с Microsoft Access. При этом этот пакет позволяет также на основе структур баз данных создавать интерфейсные формы для использования с Visual Basic.
570
Глава 20
В последнее время появляется все больше средств автоматизации проектирования и разработки баз данных, которые позволяют сопровождать проект от этапа проектирования до создания кода для приложения баз данных. Несмотря на значительные преимущества этих систем по сравнению с традиционным кодированием, чтобы научиться работать с такими системами, следует сначала освоить обычную технику (по крайней мере, для понимания того, какого результата следует ожидать от автоматизированного средства).
Самым эффективным способом создания базы данных, конечно, является создание базы при помощи кода, в том числе и VB-кода. Этого не нужно делать в процессе начального изучения баз данных, но, когда вы научитесь работать с ними достаточно уверенно, обязательно освойте технику создания баз данных из VB-кода.
Занесение данных в таблицы баз данных
В таблицы базы данных формата mdb вносить данные можно либо при помощи какой-либо СУБД, либо посредством кода. Проще всего занести данные в mdb-файл, если использовать Microsoft Access, в котором, как мы уже выяснили, легко и создаются таблицы базы данных. Даже когда вы научитесь заносить данные в таблицы при помощи специализированных приложений или из кода на языке Visual Basic (или каком-либо другом), все равно при разработке того или иного приложения вам часто придется заносить (или редактировать) данные при помощи Microsoft Access. Иногда нужно будет просто просмотреть данные, чтобы понять, почему приложение «не хочет» работать.
Для внесения данных при помощи Microsoft Access дважды щелкните в главном окне (рис. 20.39) на имени нужной таблицы, например, Склады. При этом появляется окно Склады: таблица (рис. 20.40), в котором и производится добавление, удаление и редактирование данных (рис. 20.41). Работа с таблицей в этом окне проста и интуитивно понятна, поэтому мы не будем подробно ее рассматривать.
Рис. 20.39
Для внесения данных дважды щелкните в главном окне на имени нужной таблицы
 dbs : бдел данных (({юрмат Access 2000)
Объекты		^Создать	-о	§!!		23 Склады 3 Товары
		а] 1	Создание таблицы в режиме конструктора 1 Создание таблицы с помощью мастера	'	
1 в	Таблицы			
	Запросы	 ! 	Создание таблицы путем ввода данных Инвентарная_ведомость КонтрКдгента	
13	Формы			
и	Отчеты	. 	НаклЗаголовки	
	Страницы	: 	НаклСпецификации	
	Г руппы	<		>
Рис. 20.40
Здесь и производится добавление, удаление и редактирование данных
Введение в базы данных
571
Рис. 20.41
Работа с таблицей в этом окне проста и интуитивно понятна
В Сн'Пщы: таблица
	| КодСклада	^Наименование	Адрес
	* 0001 ♦ 0002	Первый склад Второй склад	ул Ленина, 95 ул Советская, 77
►	* 0003	Третий склад	ул Гайдара 122
Запись И |	11		« ....».1 .и	> | из 4
В следующей главе нам понадобятся заполненные таблицы Товары, Склады, Инвентарная_ведомость и другие. Там же и будет приведена информация, которую можно занести в них для демонстрации примеров.
Гйвю 21
Основы языка SQL
•
Конечно, описать язык SQL в рамках одной главы невозможно. Ему посвящено много книг — и больших, и небольших. Эта глава предназначена для того, чтобы показать, насколько полезен язык SQL при работе с базами данных, разрабатываемыми в рамках Microsoft Office. Вам в дальнейшем нужно будет обязательно приобрести хорошее пособие по SQL для углубленного изучения этого языка, необходимого для разработчика баз данных.
SQL — это язык структурированных запросов (Structured Query Language) к реляционным базам данных. История SQL тесно связана с историей развития реляционных баз данных. В 1974-1975 годах был создан первый прототип реляционной СУБД. Кроме разработки самой СУБД, в рамках проекта System/R в компании IBM проводилась работа над созданием языка запросов к базам данных. Первый язык запросов получил название SEQUEL — Structured English Query Language. Вторая реализация проекта System/R была установлена на компьютерах нескольких заказчиков IBM с целью опытной эксплуатации в 1978-1979 гг. В этой реализации язык запросов имел уже название SQL, но до сих пор еще можно услышать от пользователей старое название этого языка.
В 1982 году компания IBM начала поставки на рынок коммерческого продукта SQL/Data System, а в 1983 году объявила о создании версии SQL/Data System для операционной системы VM/CMS. В 1983 году IBM выпустила новую реляционную СУБД — Database 2 (DB2). Благодаря влиянию компании IBM на рынок вычислительных систем SQL DB2 стал фактическим стандартом языка баз данных.
Во второй половине восьмидесятых годов резко увеличилась производительность реляционных СУБД и с развитием реляционных технологий связывались большие надежды. Появились, в частности, новые версии СУБД Ingress и Oracle с производительностью, в два-три раза превышающей производительность предыдущих версий. Росту производительности СУБД способствовало и увеличение общего быстродействия компьютеров.
Опубликование в 1986 году стандарта SQL (ANSI/ISO) официально утвердило SQL как стандартный язык реляционных СУБД. С появлением более мощных персональных компьютеров и объединением их в локальные сети возникла необходимость в новых СУБД. Поставщики таких СУБД снова стали ориентироваться на SQL-технологии. И, наконец, SQL стал ключевой частью архитектуры клиент/сервер.
Первоначально SQL фирмы IBM имел простой синтаксис, но на протяжении нескольких лет производители программного обеспечения в области систем управления базами данных добавляли к своим реализациям новые возможности, многие из которых вошли в стандарты ANSI SQL. Версия языка ANSI SQL была принята организацией International Standards Organization (ISO), отделением ООН со штаб-квартирой в Женеве и комитетом International Electrotechnical Commission (IEC) как продукт ISO/IEC9075:1992 или язык баз данных SQL (SQL-92). Отдельный стандарт ANSI X.3.168-1989 определяет встроенный язык баз данных SQL(SQL-89). Современные СУБД поддерживают SQL-89 и многие дополнения из SQL-92. Кроме того, большинство СУБД имеют свои ключевые SQL-слова для создания патентованных диалектов SQL, таких как Transact-SQL (сервера SQL Server) или SQL Jet. В этой и следующей главе мы будем использовать SQL Jet и Transact-SQL, не уделяя внимания их отличиям от ANSI SQL-92.
Отметим, что историческое название SQL не совсем точно отражает суть этого языка, поскольку он предназначен не только для построения запросов (если, ко
Основыязыка SQL
573
нечно, под «запросом» понимать только извлечение информации из базы данных). Сейчас SQL позволяет реализовать все функции СУБД: организацию данных, извлечение информации, модификацию данных, управление доступом, совместное использование данных, обеспечение целостности данных.
Типы команд SQL .
В ANSI SQL имеется шесть основных типов команд:
	команды языка определения данных [data definition language — DDL) позволяют создавать новые таблицы в базе данных, добавлять индексы и т.д.; основными командами языка определения данных являются:
CREATE TABLE	Создать таблицу
ALTER TABLE	Модифицировать таблицу
DROP TABLE	Удалить таблицу
CREATE INDEX	Создать индекс
ALTER INDEX	Модифицировать индекс
DROP INDEX	Удалить индекс
	команды языка обработки данных [data manipulation language — DML) используются для добавления, корректировки и удаления строк в таблицах и включают:
INSERT	Вставить данные в таблицу
UPDATE	Обновить данные
DELETE	Удалить данные
 команда языка запросов данных {data query language — DQL) (единственная команда) используется для получения данных из таблиц и определения формы представления этих данных:
SELECT	Выполнить запрос из таблиц базы
 команды языка управления данными {data control language — DCL) определяют доступ отдельных пользователей и групп пользователей к объектам базы данных посредством полномочий, предоставляемых и отменяемых командами:
GRANT	Предоставить привилегии
REVOKE	Отменить привилегии
 команды языка обработки транзакций {transaction processing language — TPL) обеспечивают обновление всех строк, используемых в операторе DML, и включают следующие команды:
BEGIN TRANSACTION	Начать транзакцию
COMIT TRANSACTION	Завершить транзакцию
SAVE TRANSACTION	Создать точку сохранения внутри транзакции
574
Глава 21
	команды языка управления курсорам (cursor control language — CCL) выполняют операции с отдельными строками одной или нескольких таблиц и включают: DECLARE CURSOR, FETCH INTO и UPDATE WHERE CURRENT. Создатели СУБД, в общем-то, не обязаны поддерживать все команды SQL-92, и можно с уверенностью утверждать, что, практически, нет ни одной коммерческой СУБД, которая реализовала все команды SQL-92. В частности, в SQL Jet не поддерживаются никакие зарезервированные слова команд DCL и CCL.
SQL в Visual Basic
В Visual Basic (и Microsoft Access) SQL применяется в основном для выполнения запросов. Используя SQL-запросы можно выбирать из таблиц базы данных только необходимые записи, можно манипулировать структурой базы данных. При этом мы можем получить доступ не просто к одной таблице, а к сложной выборке из связанных между собой таблиц или наборов данных.
SQL-запросы можно также применять в приложениях, использующих объектные модели DAO, RDO1 или ADO. Кроме того, SQL как стандартный способ управления базами данных реализован во многих СУБД, включая Microsoft Access и SQL Server.
Конечно, у нас нет возможности в этой книге для систематического изложения языка SQL, поэтому мы рассмотрим только некоторые аспекты использования SQL-запросов в VBA приложениях с целью пробудить у читателя интерес к изучению SQL.
Инструкция SELECT
Для работы с базами данных в Visual Basic используется язык запросов, включающий единственную инструкцию SELECT. Рассмотрим некоторые вопросы, связанные с ее использованием. Синтаксис (неполный) инструкции (команды) SELECT в SQL Jet следующий:
SELECT [ALL | DISTINCT | DISTINCTROW | TOP] { * I table.* |
,	[table.]fieldl [AS aliasl] [, [table.]field2 [AS alias2] [, ...]])
FROM tablel [tablelAlias] [, table2 [table2Alias] [, ...]
[WHERE criteria]
[GROUP BY groupfieldlist]
[HAVING groupcriteria]
[ORDER BY fieldl [ASC I DESC ][, field2 [ASC | DESC ]][, ...]]] [WITH OWNERACCESS OPTION]
Инструкция SELECT включает следующие основные элементы:
	SELECT означает, что из некоторых таблиц базы данных необходимо выбрать набор (таблицу данных).
	Необязательные слова ALL, DISTINCT, DISTINCTROW и TOP называются предикатами (predicates) и определяют выбор следующим образом: ALL указывает, что в набор передаются все строки (даже с дублируемыми значениями); DISTINCT указывает, что в набор передаются только недублированные строки; DISTINCTROW указывает, что в результирующий набор будет включена каждая строка, в которой есть отличие в значении любого из полей исходных таблиц (а не только полей, указанных для отображения в операторе SELECT); ТОР используется для отображения некоторого количества (точного или в процентном отношении) начальных или конечных записей из результирующего набора.
1
Модель RDO в данной книге не рассматривается.
Основы языка SQL
575
	Список { * | table.* | [table.Jfieldl [AS aliasl] [, [table.]field2 [AS alias2] [, ...]]} (фигурные скобки здесь обозначают список) состоит из имен полей таблиц(ы) запроса. Звездочка (*) означает выбор всех полей таблицы. Если в запросе указывается несколько таблиц, то для определения поля используется наименование таблицы, отделяемое от имени поля точкой (.). Поле может получать «алиасное» имя при помощи ключевого слова As.
•	После слова FROM указываются таблицы, из которых выбираются ранее указанные поля. Здесь tableexpression — это имя таблицы (или таблиц), содержащей данные, externaldatabase — имя базы данных, если не используется текущая база.
Остальные элементы инструкции SELECT мы будем рассматривать по мере изучения более сложных запросов к таблицам.
Для примеров использования SELECT будем работать с базой данных, которую мы рассматривали в конце предыдущей главы. Для изучения работы SELECT, как и других инструкций, легче всего использовать Access, тем более что именно в нем мы и создали нашу базу данных. Заметим, что при работе с Visual Basic мы будем использовать инструкции SQL немного по-другому.
Чтобы начать работу с инструкциями языка SQL, необходимо заполнить таблицы некоторой информацией. Причем, пока мы не рассматривали возможности СУБД по вводу данных при помощи специально разработанных диалоговых окон, следует сделать это при помощи Access. (О том, как можно заполнить таблицы в Access вручную, кратко описано в предыдущей главе.)
Для рассмотрения самых простых запросов при помощи инструкции SELECT нам достаточно будет трех таблиц, представленных на рис. 21.1-21.3.
Рис. 21.1
Таблица Товары с данными
to Товары : ыб.1иц<5			i- '[ч®	
	| КодТовара	НаименованиеТовара	| ЦенаОптовая | ЦенаРозничная|	
	♦ 006019170049	(S) Tazmania	ЗО.ООр	Зб.ООр
	♦ 036019164741	(S) Cool Spot	42,ООр	49,00р
	* 006019165803	(S) Road Rush II	42,ООр	49,ООр
►	♦ 028019095823	(VCD) Older Marouani	90,ООр	105,ООр
	♦ 028019100222	(VCD) Голая мишень	ЭО.ООр	105,00р
	♦ 028019100018	(VCD) Whami The best of	105,00р	123,ООр „„
	♦ 010415090732	(VCD) Пастырь	111,00р	130,ООр
	♦ 010415090937	(VCD) Шоссе в никуда	120,00р	140,00р
	* 010428144348	(VCD) Доберман	135,00р	158,00р
	♦ 010414114438	(VCD) Патриот	138,00р	161,ООр
	♦ 186100175232	(3DC) Super Runabout	750,00р	875,ООр
I—	* 174500175521	(3DC) Star Gladiator 2	750,ООр	875,00р
	* 174500175359	(3DC) Street Fighter 3 Wimpact	750,00р	875,ООр „|
Запись: Н | < j|		4 ► | >1 |»Ж| из 13		
Рис. 21.2
Таблица Склады с данными
Ни (.клады : таблица			Ий®
	| КодСклада	| НаименованиеСклада |	Адрес
	* 1958	СКЛАД (Брак)	ул	Ленина,95
	* 1508	СКЛАД (МНЕВНИКИ) ул	Советская, 77
	+ 0429	СКЛАД (Мультимедиа) ул	Гайдара,122
9	+ 1518	СКЛАД (НЕЙРОН)	ул	К Маркса, 1
Запись: Н1		4 ► I »11»*1 из 4	
Напомним, что две из этих таблиц (Товары и Склады) являются объектными: они описывают такие объекты, как товары (наименования, цены) и склады (наименования, адреса). Таблица Инвентарная_ведомость указывает, где (на каком складе) и в каком количестве находятся товары.
576
Глава 21
Рис. 21.3
Таблица Инвентарная_ведомость с данными
!		аблица	% Bl
М 1 1 II 1 1 1	1	[	1	1	'll 1	Г 1	1	0429	006019165603 1506	006019165603 1516	006019165603 0429	006019170049 1506	006019170049 1518	ОЙ6019170049 1506	010414114438 1958	010414114438 1506	010428144348 1958	010428144348 0429	036019164741 1506	036019164741 1518	036019164741 1506	174500175359 1958	174500175359 0429	174500175521 1958	174500175521 0429	186100175232 1958	186100175232	3000 200 1200 1000 500 1000 400 3300 800 4200 2000 600 1400 600 2200 1500 2300 2000 1300	—
За	пись. К | < ||	19 ► |	► 1 |»Ж| из 19	
Для тестирования SQL-инструкций в среде Access выберите в левой части главного окна Access в меню Объекты опцию Запросы и дважды щелкните команду Создание запроса в режиме конструктора1. Появившееся окно Добавление таблицы нам в данном случае не нужно2, поэтому его следует закрыть.
Рис. 21.4
Создание запросов в Access начинается с выбора объекта
Запросы
Не обращая внимания на средства Access, предназначенные для легкого создания запроса (в нижней части диалогового окна), выберите команду Режим SQL в меню Вид (рис. 21.6), чтобы, наконец, получить доступ к тому окну, в котором можно будет набирать SQL-инструкции (рис. 21.7).
Инструкцию SELECT будем изучать по принципу «от простого — к сложному»: сначала выбросим из полного синтаксиса этой инструкции все необязательные элементы, а затем постепенно будем использовать их, получая более сложные
Автор не утверждает, что это единственный способ создания SQL-запроса.
Это окно помогает создать запрос пользователю, не умеющему работать с языком SQL.
Основы языка SQL
577
запросы. Если отбросить все необязательные предложения и из списка { * | table.* | [table.Jfieldl [AS aliasl] [, [table.]field2 [AS alias2] [, ...]]} оставить только элемент *, то синтаксис самой простой SELECT-инструкции (SQL-запроса) будет иметь вид:
SELECT * FROM table
19 Программирование на VBA 2002
578
Глава 21
Здесь знак * означает выбор значений всех полей, a table — имя таблицы, из которой выбираются значения. Поэтому самая простая SELECT-инструкция для одной из рассматриваемых нами таблиц может выглядеть так:
SELECT * FROM Товары
Введите эту инструкцию в окно Запрос 1: запрос на выборку, как показано на рис. 21.8, и щелкните кнопку Запуск на панели Конструктор запросов. Результат выполнения этой очень простой SQL-инструкции приведен на рис. 21.9.
Рис. 21.9
Результат выполнения очень простой SQL инструкции в среде Microsoft Access
Рис. 21.8
Введите эту инструкцию в окно Запрос 1: запрос на выборку, как показано на рис 21 8, и щелкните кнопку Запуск
Ltl '	 Т'-'".	_________J.-...............1.'
Файл Правка £ид Вставка Формат Записи Сервис Окно Справка	- (5 х
КодТовара | НаименоеаниеТовара
Г ШДЫЕИ» (S) Road Rush II
_ 006019170049 (S) Tasmania
_ 010414114438 (VCD) Патриот
[ ЦенаОптовая j ЦенаРозничная [
_ 010415090732 __ 010415090937 __010428144348 _ 028019095823 __ 028019100018 __ 028019100222 _ 036019164741
_ 174500175359
_ 174500175521
1ЯЙ1ПП17£Т5") Запись H | jp
(VCD) Пастырь
(VCD) Шоссе в никуда
(VCD) Доберман
(VCD) Dider Marouani
(VCD) Wham1 The best of
(VCD) Голая мишень
(S) Cool Spot
(3DC) Street Fighter 3 Wimpact
(3DC) Star Gladiator 2
Г5ПГ"| Q, ног D nohr t
1 ► I H 1>*1 из 13
42 OOp 30 OOp
138 OOp 111 OOp 120 OOp 135 OOp
90 OOp 105 OOp
90 OOp
42 OOp
750 OOp 750 OOp 7АШ ППн
49 OOp
35 OOp
161 OOp
130 OOp
140 OOp
158 OOp
105 00р
123 00p ft
105 00p
49 00p *
875 OOp
875 OOp Я7К ЛПн И
Режим таолиць
Выбор в SQL-запросе определенных полей
Чаще всего вам не нужно будет получать набор со всеми полями одной (или более) таблицы. Например, поскольку поле КодТовара в таблице Товары предназначено в основном для связи с другими таблицами, то не часто его следует включать в SQL-запрос. В SELECT-инструкции можно указать конкретные наименования используемых полей некоторой таблицы, используя следующий синтаксис:
SELECT fieldl [,field2 [, ...]] FROM table
Например1:
SELECT НаименованиеГовара, ЦенаОптовая From Товары
Результат этого запроса представлен на рис. 21.10.
1 Для возврата к окну ввода SQL инструкций выберите команду Режим SQL в меню Вид.
Основы языка SQL
579
Рис. 21.10
В SELECT-инструкции можно указать конкретные наименования используемых полей
и	Запрос1 : запрос на выборку	ИИКЗЭЁЗ I ЦенаОптовая | -*-J
: ►	tS) Road РизКЩ—ИИ	42,00p f 1
	(S) Tazrnania	30,OOp j
	(VCD) Патриот	138,OOp j ;
	(VCD) Пастырь	111,OOp	;
	(VCD) Шоссе в никуда	120,OOp |
	(VCD) Доберман	135,OOp ‘ -
	(VCD) Dider Marouani	90,OOp I
	(VCD) Whami The best of	105,OOp j
	(VCD) Голая мишень	90,OOp j
	(S) Cool Spot	42,OOp j
	(3DC) Street Fighter 3 Wimpact	750,OOp |
	(3DC) Star Gladiator 2	750,OOp I
	(3DC) Super Runabout	750,OOp |<
Запись: К |	| j	1 ► | ►!		|»Ж| из 13
Для выбираемых в запросе полей можно указать отличные от наименований полей заголовки: видимо, не совсем хорошо будет выглядеть на документе заголовок НаименованиеТовара, хотя бывают заголовки и «похуже». Чтобы указать наименования полей результирующего запроса, необходимо использовать такой синтаксис:
SELECT fieldl [AS aliasl] [,field2 [AS alias2] [, ...]] FROM table
В следующей инструкции мы исправляем ситуацию с «плохими» наименованиями в запросе (результат — на рис. 21.11):
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] From Товары
Рис. 21.11
Для выбираемых в запросе полей можно указать отличные от наименований полей заголовки
is1 Зинрсп 1 laupop i№fiojMy.
	НаименованиеТовара	ЦенаОптовая |?
►		42,00p
	(S) Tazrnania	30,OOp	j
	(VCD) Патриот	138,OOp	;
	(VCD) Пастырь	111,00p	;
	(VCD) Шоссе в никуда	120,OOp
	(VCD) Доберман	135,00р
	(VCD) Dider Marouani	90,00p
	(VCD) Whami The best of	105,OOp
	(VCD) Голая мишень	90,OOp
	(S) Cool Spot	42,00p
	(3DC) Street Fighter 3 Wimpact	750,00p ?
	(3DC) Star Gladiator 2	750,OOp |
	(3DC) Super Runabout	750,OOp |£
Запись: 14 j | j	1 ► | ►!		► Ж| из 13
Выбор в SQL-запросе определенных записей
Ключевое слово WHERE в синтаксисе инструкции SELECT позволяет указывать определенные типы записей, которые должны попадать в набор. При этом инструкция SELECT имеет следующий синтаксис:
SELECT { * I fieldl [AS aliasl] [,field2 [AS allas2] [, ...]]} FROM table [WHERE criteria]
Например, вы можете запросить только те товары, цены которых не более 100 денежных единиц (результат — на рис. 21.12):
SELECT НаименованиеТовара as [Наименование товара],
ЦенаОптовая as [Цена оптовая] From Товары WHERE ЦенаОптовая < 100
19*
580
Глава 21
Рис. 21.12
Ключевое слово WHERE в синтаксисе инструкции SELECT позволяет указывать определенные типы записей, которые должны попадать в набор
si" Запрос! : запрос на выборы
r—--------:----
Наименование товара | Цена оптовая|: 42 ООр 30 ООр " 9°,QQp 90.°0р И 42,00р  „0-°°Р„Й
|(S) Road Rush ll|
(S) Tazmania
(VCD) Голая мишень (VCD) Dider Marouani (S) Cool Spot
*
Запись1 К |	| (
Использование в SQL-запросе функций для вывода определенных записей
В области слова WHERE можно располагать довольно сложное условное выражение с использованием знаков логических операций и функций. Например:
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаОптовая > 50 AND ЦенаОптовая 200
ИЛИ
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаОптовая > 50 AND Len(ЦенаОптовая) < 20
В первом случае запрашиваются товары, оптовая цена которых находится в диапазоне оптовых цен (55-200), а во втором — цены которых больше 50 денежных единиц и длина наименования не превышает 20 символов.
Кроме операций < и >, в инструкции SELECT можно использовать операции = (равно), <= (меньше или равно) и >= (больше или равно), а также AND, OR и NOT. Но еще большие возможности по отбору необходимых записей предоставляют такие операторы, как IS NULL, BETWEEN, IN и LIKE.
Оператор IS NULL позволяет найти в таблице записи, в полях которых не указаны данные, например:
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаРозничная IS NULL OR ЦенаОптовая < 50
Оператор BETWEEN позволяет указать диапазон, в котором находятся данные некоторого поля, например:
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаРозничная BETWEEN 42 AND 120
Оператор IN позволяет указать список, в котором находятся данные некоторого поля, например:
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаРозничная IN (42, 105,750)
В SQL-инструкции можно также использовать оператор LIKE, например инструкция
Основы языка SQL
581
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE НаименованиеТовара LIKE "(VCD)*”
позволяет получить только те записи (рис. 21.13), у которых в наименовании первые пять символов совпадают со строкой "(VCD)”.
Рис. 21.13
Вывод только тех записей, у которых в наименовании первые пять символов совпадают со строкой "(VCD)"
кЦ.. Запрос!.: запрос на выборку
	Наименование товара	| Цена оптовая
►	tVCD) ПатриотЦМ^^Н^Ц	138,00p
	(VCD) Пастырь	111,00р.
	(VCD) Шоссе в никуда	120,00р
	(VCD) Доберман	135,00р.
	(VCD) Голая мишень	90,00р.
	(VCD) Dider Marouani	90,00р.
	(VCD) Whami The best of	105,00р.
*		0,00р.
Запись: Н | < ] Г
..-•Лиамам -
1 » |Н I»! из 7
Оператор LIKE можно использовать для контекстного поиска, например, если пользователь введет текстовую строку, содержащую часть наименования товара, то эту строку легко использовать в виде шаблона. Следующая инструкция выполняет поиск записи, в которой наименование содержит в качестве подстроки строку "(мишень)" (результат — на рис. 21.14):
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE НаименованиеТовара LIKE "‘мишень*"
Рис. 21.14
Результат использования инструкции, которая выполняет поиск записи, где наименование содержит в качестве подстроки строку "мишень”
Оператор NOT, который инвертирует логическое выражение, может использоваться с операторами IS NULL, BETWEEN, IN, LIKE. При этом, практически, речь идет об операторах IS NOT NULL, NOT BETWEEN, NOT IN и NOT LIKE, например, как в следующих четырех инструкциях:
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаРозничная IS NULL OR ЦенаОптовая < 50
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары WHERE ЦенаРозничная BETWEEN 42 AND 120
SELECT НаименованиеТовара as [Наименование товара], ЦенаОптовая as [Цена оптовая] FROM Товары
WHERE ЦенаРозничная IN (42, 105,750)
582
Глава 21
SELECT НаименованиеТовара as [Наименование товара] , ЦенаОптовая as [Цена оптовая] FROM Товары WHERE НаименованиеТовара LIKE "(VCD)*"
Форматирование выводимых в запросе данных
Результирующие данные запроса можно форматировать с использованием, например, функции Format. В следующем запросе данные форматируются при помощи строки "### ##0.00$" (результат — на рис. 21.15):
SELECT НаименованиеТовара as [Наименование товара], Format(ЦенаОптовая,"### ##0.00$") as [Цена оптовая] From Товары WHERE ЦенаОптовая < 100
Рис. 21.15
Результирующие данные запроса можно форматировать
с использованием функции Format
]S) Road Rush ll|
(S) Tazmama
(VCD) Голая мишень (VCD) Older Marouani (S) Cool Spot
| Цена оптовая
42,00$
30 00$
90,00$
90 00$
42,00$	
Для форматирования выводимых в запросе данных можно использовать функции преобразования строк. Например, в следующем запросе наименования товаров выводятся символами верхнего регистра, поскольку здесь используется функция StrConv (результат — на рис. 21.16):
SELECT StrConv(НаименованиеТовара,1) AS [Наименование товара], ЦенаОптовая AS [Цена оптовая] FROM Товары
Рис. 21.16
Наименования товаров выводятся символами верхнего регистра, поскольку здесь используется функция StrConv
ig! 3anpoc1 : запрос на «ыворку	Цена оптовая *
ifil(S) ROAD RUSH цм^|Н|||Ы|	42,00p
(S) TASMANIA	30,OOp
I <VCD) ПАТРИОТ	138,00p	I
(VCD; ПАСТЫРЬ	111,00p I
! (VCD) ШОССЕ В НИКУДА	120,OOp
I (VCD) ДОБЕРМАН	135,OOp _
(VCD) DIDER MAROUANI	90 OOp
	(VCD) WHAMl THE BEST OF	105 OOp
	(VCD) ГОЛАЯ МИШЕНЬ	90,OOp
(S) COOL SPOT	42,00p
|	(3DC) STREET FIGHTER 3 WIMI	750,OOp
(3DC) STAR GLADIATOR 2	750,OOp
Q(3DC) SUPER RUNABOUT	750 OOp ,|
* Запись M |	11	1 ► j ►! ;	►*] из 13
Основы языка SQL
583
Выбор данных из более чем одной таблицы
Имея базу данных из нескольких таблиц, мы до сих пор получали при помощи инструкции SELECT наборы данных только из одной таблицы. Рассмотрим теперь задачу выбора из базы данных товаров некоторого склада. Перед тем как рассмотреть использование слова WHERE для связи таблиц, заметим, что в инструкции SELECT можно перед именем.поля указывать имя таблицы, которое отделяется от имени поля точкой:
SELECT { * | [tablel.]fieldl [AS aliasl] [, [table2.]field2 [AS alias2] [, ...]]} FROM tablel [tablelAlias] [, table2 [table2Alias] [, ...] [WHERE criteria]
Например:
SELECT Товары.НаименованиеТовара AS [Наименование товара], Товары.ЦенаОптовая AS [Цена оптовая] FROM Товары
или
SELECT а.НаименованиеТовара AS [Наименование товара], а.ЦенаОптовая AS [Цена оптовая] FROM Товары а
Во второй инструкции использовано альтернативное имя таблицы (локальный псевдоним), но обе инструкции выдают один и тот же результирующий набор.
Следующая инструкция позволяет получить наименования (из таблицы Товары) и количества (из таблицы Инвентарная_ведомость) товаров (результат — на рис. 21.17):
SELECT Товары.НаименованиеТовара AS [Наименование товара], Инвентарная__ведомость . Количество AS [Количество] FROM Товары, Инвентарная_ведомость
WHERE Товары.КодТовара=Инвентарная_ведомость.КодТовара
Рис. 21.17
Результат инструкции, которая позволяет получить наименования (из таблицы Товары) и количества (из таблицы
Инвентарная_ведомость)
3ai>por1 : запрос на выборку
	Наименование товара
I ►	ЭЕШЗЕЖ
_ (S) Road Rush II ___lS) Road Rush II ___(S) Tazrnania [__(S) Tazrnania
___(S) Tazrnania
___ 'CD) Патриот ___(VCD) Патриот ___(VCD) Доберман ___(VCD) Доберман
'S) Cool Spot
__ ',) Cool Spot __lS) Cool Spot
janecb H |	|| “
иьш
I Количеств j
30C ‘
2C-.
12C ’
1ооояВ1 500
ЮС 4С=
зэоо 1ЕЫ
ВС
42С
20С j
бооИИИ
14С
Обратите внимание на выражение Товары.КодТовара=Инвентарная_ведо-мость.КодТовара. Именно оно и используется для связи таблиц Товары и Инвен-тарная_ведомость по ключевому полю КодТовара.
Результат выполнения предыдущей инструкции напоминает инвентаризационную ведомость без указания места, где находится товар. Следующая инструкция позволяет получить наименования (из таблицы Товары) и количества (из таблицы Инвентарная_ведомость) только для тех кодов товаров, записи которых в таблице Инвентарная_ведомость в поле Код_склада содержат строку "0429":
SELECT Товары.НаименованиеТовара AS [Наименование товара], Инвентарная__ведомость.Количество AS [Количество] FROM Товары, Инвентарная_ведомость
584
Глава 21
WHERE Инвентарная—ведомость.Код_склада='0429'
AND Товары.КодТовара=ИнвентарнаЯ—ведомость.КодТовара
При помощи локальных псевдонимов можно сократить предыдущую инструкцию (результат — на рис. 21.18):
SELECT а.НаименованиеТовара AS [Наименование товара], Ь.Количество
AS [Количество] FROM Товары а, Инвентарная—ведомость b
WHERE b.КоД—склада='0429' AND а.КодТовара=Ь.КодТовара
Рис. 21.18
Наименования товаров выводятся только для одного склада
is! Запрос.1 : запрос на выборку
Наименование товара ] Количество
3000
1 (S)Tazmama	1000
_ (S) Cool Spot	2000
_ (3DC) Star Gladiator 2	1500
(3DC) Super Runabout	2000
[S) Road Rush ll|
Запись: К |	| [
Следует заметить, что вообще-то коды, как товаров, так и складов, не предназначены для использования клиентами. Они необходимы для связи между таблицами. Часто менеджеры, использующие базы данных, даже не знают о наличии кодов в таблицах баз данных. По этой или подобной ей причине нам следует избавиться от «публичного» использования кода склада в SELECT-инструкции. Хотя, конечно, инструкция при этом немного усложнится:
SELECT а.НаименованиеТовара AS [Наименование товара], Ь.Количество AS [Количество] FROM Товары а, Инвентарная—ведомость Ь, Склады с WHERE а.КодТовара=Ь.КодТовара AND b.КодСклада=с.КодСклада AND с.НаименованиеСклада="СКЛАД (Мультимедия)"
В этой инструкции использована таблица Склады, а при помощи поля КодСк-лада эта таблица связана с таблицей Инвентарная_ведомость.
Вывод выбранных данных в определенном порядке
Вы могли уже давно заметить, что наименования товаров в наших таблицах и выводимых наборах не отсортированы. Это бывает особенно заметно, когда данных очень много (например, в окне списка), а нужно найти только некоторые из них. Для сортировки данных в инструкции SELECT имеются слова ORDER BY:
SELECT { * I [table.]fieldl [AS aliasl] [, [table.]field2
[AS alias2] [, ...]]} FROM tablel [tablelAlias]
[, table2 [table2Alias] [, ...] [WHERE criteria] [ORDER BY fieldl [ASC I DESC ][, field2 [ASC I DESC ]][, ...]]]
Здесь к тем элементам SQL-запроса, которые уже рассмотрены, добавлено необязательное предложение ORDER BY. Как следует из синтаксиса инструкции SELECT, используя слова ASC и DESC, можно изменять «направление» сортировки («по возрастанию» и «по убыванию»). Сортировать можно по нескольким полям (сначала по одному, затем — по другому, и так далее) и даже по различным элементам одного и того же поля с использованием функций (как встроенных, так и пользовательских).
Основы языка SQL
585
В следующей инструкции используется сортировка выводимого набора по наименованиям (результат — на рис. 21.19):
SELECT а.НаименованиеТовара AS [Наименование товара], Ь.Количество AS [Количество] FROM Товары а, Инвентарная__ведомость Ь WHERE а.КодТовара=Ь.КодТовара AND b.Код_склада='0429' ORDER BY а.НаименованиеТовара
Рис. 21.19
Сортировка данных в инструкции SELECT
и’ Janpocl:запрос на выборку
|f3DC) Star Gladiator 2|
Наименование товара | Кол,
PDC) Super Runabout
(S) Cool Spot
(S) Road Rush II
(S) Tazmania
Агрегирующие функции в инструкции SELECT
В инструкциях языка ANSI SQL предусмотрены так называемые агрегирующие функции, которые определяют количество записей, вычисляют суммы всех значений полей в наборе, находят минимальные или максимальные, а также средние значения. К агрегирующим функциям относятся функции COUNT, SUM, MAX, MIN и AVG.
Функция COUNT используется для определения количества записей в запросе. Например, в окне на рис. 21.20 введена инструкция для вычисления количества записей в таблице Товары, а на рис. 21.21 показан результат выполнения этой инструкции.
Рис. 21.20
Окно с инструкцией SELECT для определения общего количества записей в таблице
Рис. 21.21
Результат определения общего количества записей в таблице
1? Запрос? : запрос па пыбп
| Запись: Н |  11 Г ' I И h I из
Следующая инструкция вычисляет количество записей, в которых значение поля ЦенаОптовая меньше 100. На рис. 21.22 приведен результат выполнения этой инструкции.
SELECT COUNT(НаименованиеТовара) AS [Всего наименований]
FROM Товары WHERE ЦенаОптовая < 100
586
Глава 21
Рис. 21.22
Результат определения количества записей в таблице при определенном условии
Функция SUM позволяет для группы строк вычислить итоговую сумму значений некоторого поля, например (результат — на рис. 21.23):.
SELECT SUM(Количество) as [Общее количество товаров]
FROM Инвентарная_ведомость
Рис. 21.23
Результат вычисления итоговой суммы значений некоторого поля
При использовании функции SUM можно ограничить количество записей запроса при помощи некоторого условия, например (результат — на рис. 21.24):
SELECT SUM(Количество) AS [Количество на складе]
FROM Инвентарная_ведомость WHERE КодСклада='0429'
Рис. 21.24
При использовании функции SUM можно ограничить количество записей запроса
Функция AVG в инструкции SELECT позволяет найти среднее значение для строк, входящих в запрос. Например, следующая инструкция определяет среднюю цену на товары, наименования которых начинаются со строки "(VCD)" (результат — на рис. 21.25):
SELECT AVG(ЦенаОптовая) AS [Среднее значение]
FROM Товары WHERE НаименованиеТовара LIKE '(VCD)*'
Рис. 21.25
При помощи функции AVG можно вычислить среднее значение
Функции МАХ и MIN использовать также просто, как и AVG, например:
SELECT МАХ(ЦенаОптовая) AS [Максимальная цена]
FROM Товары WHERE НаименованиеТовара LIKE '(VCD)*'
или	'
SELECT MIN(ЦенаОптовая) AS [Макси,л1пьная цена]
.	FROM Товары WHERE Наименование г'вара LIKE '(VCD)*'
В первой из приведенных инструкций определяется максимальное значение цены на товары, наименования которых начинаются со строки "(VCD)' во второй — минимальное значение цены на подобные товары.
Основы языка SQL
587
В конкретных реализациях SQL имеются другие агрегирующие функции, которые следует использовать только в том случае, если вы уверены, что никогда не захотите использовать фрагменты своего кода в различных СУБД.
Группировка данных в инструкции SELECT
Часто в наборах, получаемых при помощи SELECT-инструкций, встречаются повторяющиеся значения. Для рассматриваемой нами базы данных это могут быть, например, коды товаров или складов в таблице с инвентаризационной ведомостью, номера и даты накладных в таблице со спецификациями накладных. Такие повторяющиеся значения можно объединять в группы, используя для групп агрегирующие функции.
В инструкции SELECT для объединения значений в группы используется предложение GROUP BY.
Следующая инструкция имеет результатом список складов и суммарные количества товаров на каждом складе (результат — на рис. 21.26):
SELECT с.НаименованиеСклада, SUM(Ь.Количество) AS Количество
FROM Инвентарная__ведомость Ь, Склады с WHERE b.КодСклада=с.КодСклада GROUP BY с.НаименованиеСклада
Рис. 21.26
Список складов и суммарные количества товаров на каждом складе
[СКЛАД (Брак)|
НаименованиеСклада | Количество
I? Запрос.): аапрос на «ыб...
_ СКЛАД (МНЕВНИКИ) СКЛАД (Мультимедиа) СКЛАД (НЕЙРОН)
' Запись: |< | * 11 Г
133001 31001 9500 J
36001
Если эта инструкция вам кажется сложной, выполните ее аналог, в котором вместо наименований складов используются их коды:
SELECT b.КодСклада, SUM(Ь.Количество) AS Количество
FROM Инвентарная_ведомость b GROUP BY Ь.КодСклада
Заметьте, что эта инструкция использует данные только одной таблицы. Здесь суммируются значения поля Количество для одинаковых значений полей КодСклада. В этом — смысл предложения GROUP BY. В предыдущем запросе мы просто вместо кодов подставили (посредством WHERE Ь.КодСклада=с.КодСклада) наименования складов, использовав для этого справочник Склады; смысл самого запроса, практически, такой же.
Предположим, что нам нужна информация о суммарном количестве товара только на тех складах, где это количество меньше определенного числа. Чтобы выполнить этот запрос, мы не можем использовать предложение WHERE, так как оно «работает» со значениями данных, расположенными в таблице, а нам нужно наложить некоторые ограничения на вычисляемые данные. Для решения подобной задачи следует использовать предложение HAVING, которое так же связано с предложением GROUP BY, как WHERE с SELECT. Другими словами, предложение HAVING налагает некоторые условия на выбранные посредством предложения GROUP BY данные.
Следующая инструкция позволяет получить список складов и суммарное количество товаров на них. Причем в список включаются только те склады, на которых суммарное количество товаров меньше, чем 1000 (результат — на рис. 21.27):
SELECT с.НаименованиеСклада, SUM(Ь.Количество) AS Количество
FROM Инвентарная__ведомость Ь, Склады с WHERE b.КодСклада=с.КодСклада GROUP BY с.НаименованиеСклада HAVING SUM(b.Количество) < 10000
588
Глава 21
Рис. 21.27
В список включаются только те склады, на которых суммарное количество товаров меньше чем 1000
Запрос4 : запрос на выборку [». ||П п Х|
3100
9500
3600
НаименованиеСкладаГ Количество
СКЛАД (МНЕВНИКИ)
СКЛАД (Мультимедиа)
СКЛАД(НЕЙРОН
Запись: Н | Ч |Г
Подзапросы в инструкции SELECT
Подзапрос — это запрос, который размещается внутри другого запроса, а точнее, является частью предложения WHERE (или HAVING) основного запроса и заключается в круглые скобки. Иногда подзапросы называют вложенными запросами. Запрос, содержащий подзапрос, называют сложным запросом. При выполнении сложного запроса сначала выполняется подзапрос (он для этого и заключается в скобки!), а затем — основной запрос.
Выходные данные подзапроса обычно используются при оценке выражения в предложении WHERE (или HAVING) основного (по отношению к данному подзапросу) запроса с использованием таких операторов, как =, >, <, <>, IN, NOT IN, AND, OR. (Эти операторы можно использовать и внутри подзапроса.)
Очень важно понимать, какие данные возвращает подзапрос, поскольку от этого зависит синтаксис использования предложения WHERE. Необходимо при написании сложных запросов соблюдать следующие правила:
	Предложение SELECT подзапроса обычно содержит только один столбец и, следовательно, может иметь результатом массив однородных (только строковые значения, только целые значения и т.д.) значений или только одно значение. Очень редко встречаются случаи использования нескольких столбцов. Если подзапрос возвращает массив значений, соответствующее этому подзапросу предложение WHERE может содержать только многозначные операторы, например, IN.
	Предложение ORDER BY следует использовать только в основном запросе. В подзапросе для упорядочения данных необходимо применять предложение GROUP BY.
	Недопустимо использование в основном запросе предложения BETWEEN. Простой синтаксис подзапроса для оператора SELECT следующий: SELECT ( * | table.* I [table.]fieldl [AS aliasl] [, [table.]field2 [AS alias2] [, ...]]) FROM tablel [tablelAlias] [, table2 [table2Alias] [, ...] WHERE fieldl operator
(SELECT { * | table.* I [table.]fieldl [AS aliasl] [, [table.]field2 [AS alias2] [, ...]]} FROM tablel [tablelAlias] [, table2 [table2Alias] [, ...] WHERE [criteria])
Проще всего продемонстрировать использование подзапроса, если он имеет результатом единственное значение. Например, пусть нам необходимо получить список товаров склада, на котором их больше всего. Для начала нам нужно определить этот склад. Создадим запрос, который возвратит код склада с наибольшим количеством товаров:
SELECT ТОР 1 КодСклада FROM Инвентарная_ведомость GROUP BY КодСклада ORDER BY SUM(Количество) DESC
Предложение TOP 1 указывает на то, что в результирующий набор попадает только одна запись, а поскольку набор сортируется (по убыванию) по суммарным количествам товаров, то в результате мы получаем код склада с наибольшим количеством товаров. Остается использовать ранее рассмотренный запрос, который воз
Основы языка SQL
589
вращает список товаров для указанного кода склада, но если ранее мы указывали этот код, то теперь определяем его в подзапросе (результат — на рис. 21.28):
SELECT а.НаименованиеТовара AS [Наименование товара], Ь.Количество AS Количество FROM Товары AS а, Инвентарная—ведомость AS Ь
WHERE а.КодТовара=Ь.КодТовара AND Ь.КодСклада = (SELECT ТОР 1 КодСклада FROM Инвентарная—ведомость GROUP BY КодСклада ORDER BY SUM(Количество) DESC)
Рис. 21.28
Результат выполнения сложного запроса
	Запрос4 : запрос на выборку	KK
	Наименование товара	Количество[
►	fyCD) Патриот	33C
	(УСО) Доберман	42C
	(3DC) Street Fighter 3 Wimpact	22C
	(3DC) Star Gladiator 2	23C
	(3DC) Super Runabout	13C
Запись:	11	1 ► | ► !			j из 5
Целью следующего запроса является получение ведомости товаров склада, где имеется больше наименований (кодов) товаров (результат — на рис. 21.29).
SELECT а.НаименованиеТовара AS [Наименование товара], Ь.Количество AS Количество FROM Товары AS а, Инвентарная_ведомость AS Ь WHERE а.КодТовара=Ь.КодТовара AND Ь.КодСклада = (SELECT ТОР 1 КодСклада FROM Инвентарная—ведомость GROUP BY КодСклада ORDER BY COUNT(КодТовара) DESC)
Здесь в подзапросе вместо функции SUM используется COUNT — счетчик количества записей.
Рис. 21.29
Результат выполнения сложного запроса
i? Запросе : запрос на выборку		
	Наименование товара	Количес - |
►	LSI Road Rush	
	(S) Tazrnania	
	(VCD) Патриот	
	(VCD) Доберман	
	(S) Cool Spot	
	(3DC) Street Fighter 3 Wimpact	
I Запись	Н J	|j	1 ► | Н		| из 6
Для следующих далее примеров нам необходимо заполнить данными таблицы
НаклЗаголовки и НаклСпецификации (рис. 21.30 и рис. 21.31):
Рис. 21.30
Заполненная данными таблица НаклЗаголовки
И НаклЗаголовки : таблица			’ " ""' ' ’		
	Дата | Номер		| КодСклада	| КодКАгента |ТипНакладной *	
		11/1/2002	1 0429	1958	5
		11/1/2002	5 1506	1518	2
		11/2/2002	1 0429	1958	2
		11/2/2002	2 0429	1506	5
		11/2/2002	3 0429	1506	5
		11/2/2002	4 0429	1958	5
		11/3/2002	1 0429	1518	5
		11/3/2002	2 0429	1958	2
		11/3/2002	3 0429	1518	5
►		11/3/2002	|l 0429	1958	5	rJ
Запись		14 |<||	10 ► | H|k^| из 10		< 3		!	d
590
Глава 21
Рис. 21.31
Заполненная данными таблица
Накл Спецификации
М НаклСлецификации : таблица							
	Дата |	Номер	| КодСклада	| КодТовара	Количество |ЦенаОперации(А		
	11/1/2002		1 0429	010415090937	100	120 00	
	11/1/2002		1 0429	010414114438	200	135 00{	
	11/1/2002		5 1506	028019100222	546	83 00	
	11/2/2002		1 0429	006019165803	100	42 00	
►	11/2/2002		1 0429	028019100222	140	88 00	
	11/2/2002		2 0429	186100175232	100	750 00	
	11/2/2002		2 0429	174500175521	*	200	750 00	
	11/2/2002		2 0429	028019100222	60	89 00	
	11/2/2002		2 0429	010415090732	120	109 00	
	11/2/2002		3 0429	174500175359	200	750 00	
	11/2/2002		3 0429	028019100222	545	85 00	
	11/2/2002		4 0429	174500175521	222	750 00	
	11/2/2002		4 0429	028019100222	334	88 00	
	11/2/2002		4 0429	186100175232	767	745 00	
	11/3/2002		1 0429	028019100222	232	88 00*	
	11/3/2002		1 0429	010415090732	222	110 00	
	11/3/2002		2 0429	010415090732	111	111 00	
	11/3/2002		2 0429	174500175359	234	750 00	
	11/3/2002		3 0429	174500175359	432	750 00	
	11/3/2002		4 0429	174500175521	67	750 00	
	11/3/2002		5 0429	186100175232	231	750 00	
Запись Н j ||		5 ► I и !►*!иэ 21					
Наличие базы данных с накладными дает возможность, по крайней мере, просмотра этих накладных. Рассмотрим ряд вопросов, которые могут возникнуть при просмотре таблиц с накладными.
Если бы нам нужно было создать форму для просмотра накладных, то она, вероятно, была бы похожа на ту, которая изображена на рис. 21.32. Изображенная на этом рисунке форма получена в редакторе VB только с одной целью — понять, какие SQL-запросы были бы необходимы для заполнения такого диалогового окна.
Во-первых, для заполнения окна комбинированного списка в секции Подразделение необходим запрос, в результате которого получался бы список подразделений, накладные которых имеются в таблице НаклЗаголовки. Во-вторых, следует заполнить окно комбинированного списка в секции Дата датами (уникальными) из таблицы НаклЗаголовки.
Далее, после выбора пользователем данных в секциях Подразделение и Дата в окне комбинированного списка Накладная следует поместить список накладных (с указанием номера накладной, типа накладной и наименованием контрагента) Для этого необходимо построить запрос с целью получения таблицы номеров, типов, контрагентов накладных для определенного подразделения и указанной даты.
Рис. 21.32
Так могло бы выглядеть диалоговое окно для просмотра накладных
I Просмотр нанладяык
Подразделение
Справка f
I §
Д^та
Накладная |
Наименование
Количество
Цена
1

3
Выход
л
Основы языка SQL
591
После заполнения данными списка Накладная и пользовательского выбора в этом окне останется только для известного подразделения, даты и номера накладной сформировать запрос по таблице НаклСпецификации, чтобы получить данные о конкретной накладной.
Итак, рассмотрим первый запрос — формирование списка подразделений, накладные которых имеются в таблице НаклЗаголовки. Целесообразно получить таблицу наименований и кодов подразделений. Наименованиями следует заполнить окно комбинированного списка для отображения в диалоговом окне. Коды необходимо записать в список, не отображаемый в окне, но синхронизированный с видимым списком. После выбора пользователем необходимого подразделения можно узнать и код этого подразделения.
Запрос, о котором идет речь, должен быть следующим:
SELECT DISTINCT b.КодСклада, а.НаименованиеСклада
FROM Склады а, НаклЗаголовки b WHERE а.КодСклада=Ь.КодСклада
Если его выполнить для данных, отображенных на рис. 21.30и21.31 (и таблицы Склады), то получится набор, приведенный на рис. 21.33.
Рис. 21.33
Склады, накладные которых имеются в таблице НаклЗаголовки
vr Запрос4 : запрос на выборку
КодСклада |НаймёниБаниеС|<лада | ?
__0429	СКЛАД (Мультимедиа) •_
±J1596I	СКЛАД fМНЕВНИКИ)
Запись: Н | 4 ||	2	| >1 |	| из 2
Таким образом, если пользователь выберет необходимый склад, то мы (или программа, поддерживающая диалоговое окно) будем знать код этого склада. Считая известным код склада, создадим очень простой запрос для формирования данных списка дат, например, для склада с кодом "0429”:
SELECT DISTINCT Дата FROM НаклЗаголовки WHERE КодСклада="0429"
Результатом этого запроса может быть таблица, приведенная на рис. 21.34.
Рис. 21.34
Склады, накладные которых имеются в таблице НаклЗаголовки
После выбора пользователем склада и даты необходимо сформировать запрос для списка Накладная с целью получения таблицы номеров, типов, контрагентов накладных для определенного подразделения и указанной даты (например, 11.02.2002). Правильным будет упорядочить результат запроса по номерам накладных:
SELECT а.Номер, b.НаименованиеКАгента, а.ТипНакладной	,
FROM НаклЗаголовки AS а, КонтрКАгенты AS b
WHERE а.КодКАгента = Ь.КодКАгента AND а.КодСклада="0429"
AND а.Дата = CDate("11/02/2002") ORDER BY а.Номер
Результатом этого запроса может быть таблица, приведенная на рис. 21.35.
Осталось сформировать запрос для заполнения таблицы со спецификацией выбранной накладной (например, с номером 2):
SELECT Ь.НаименованиеТовара, а.Количество, а.ЦенаОперации
FROM НаклСпецификации а, Товары b WHERE а.КодТовара=Ь.КодТовара
AND а.КодСклада="0429" AND а.Дата=СОаЬе("11/02/2002")
AND Номер =2 ORDER BY b.НаименованиеТовара
Результатом запроса может быть таблица, приведенная на рис. 21.36.
592
Глава 21
Рис. 21.35
Такая таблица может послужить источником данных для списка Накладная
й* Запрос? : запрос на выборку
Номер] НаименованиеКАгента ]ТипНакладной|
►	1	СКЛАД^Брак)	2
_	2	СКЛАД (МНЕВНИКИ)	5
_	3	СКЛАД (МНЕВНИКИ)	5
~J	4 СКЛАД (Брак)	5............
Запись Н | < | [ Г* ► [ И *| из 4
Рис. 21.36
Таблица со спецификацией накладной
Запрос# : запрос на выборку
НаименованиеТ овара
3DC) Star Gladiator >j
(3DC) Super Runabout
(VCD) Голая мишень
__](VCD) Пастырь
| Количество[ценаОперации 200	750	00
100	750	00
60	89	00
___ _J20 __ J09 00
d*3 4	4JJ ?i
Этим примером заканчивается глава, посвященная введению в язык SQL, который имеет много не рассмотренных здесь возможностей. В следующих двух главах приведены некоторые примеры использования SQL-инструкций в VB-коде. Среди этих инструкций встречаются те, которые не обсуждались в этой главе.
Глава 22
Доступ к базам данных из VBA-кода
Как вы могли заметить, в двух предыдущих главах нет ни единой строки VBA-кода. В этой главе мы снова возвращаемся к программированию на языке Visual Basic и теперь в качестве объектов кода будем использовать новые объекты — элементы баз данных. Поскольку Visual Basic не является языком баз данных, для доступа к данным следует использовать предназначенные для этого объекты (их свойства и методы). В этой главе рассматриваются две модели объектов доступа к данным: Data Access Objects (DAO) и ActiveX Data Objects (ADO).
Microsoft DAO
Microsoft DAO (Data Access Objects — объекты доступа к данным) позволяет работать с базами данных из приложения, поддерживающего Visual Basic for Applications. Объекты DAO подразделяются на те, которые отражают структуру базы данных, и на те, которые являются данными и позволяют взаимодействовать со многими типами баз данных из любого приложения, поддерживающего Visual Basic for Applications. При помощи объектов DAO можно:
	создавать базы данных, изменять их структуру;
	извлекать, добавлять, удалять и обновлять данные, хранимые в таблицах баз данных;
	подключаться к базам данных на удаленных серверах и разрабатывать клиент-серверные приложения.
DAO позволяет осуществлять доступ к базам данных различных форматов, которые можно разбить на три категории:
	Формат Microsoft Jet — все базы данных, построенные на основе ядра баз данных Microsoft Jet (включая созданные с использованием Microsoft Access, Microsoft Visual Basic, Microsoft Visual C++ и Microsoft Excel).
	Формат, поддерживаемый устанавливаемыми драйверами ISAM, которые обеспечивают доступ к внешним базам данных через DAO или Microsoft Jet. Драйверы ISAM имеются для таких форматов, как Microsoft FoxPro, dBASE, Microsoft Excel и других.
	Источники данных ODBC (например, Microsoft SQL Server). Для операций с источниками данных ODBC модель DAO можно использовать через Microsoft Jet или ODBCDirect.
Технологию DAO для операций с источниками данных ODBC можно использовать двумя способами: посредством Microsoft Jet [если необходимы уникальные возможности этого ядра, например, создание и модификация объектов, или объединение данных из баз различных форматов] или ODBCDirect [если нужно выполнять запросы или процедуры, хранимые на сетевом сервере, или если клиентскому приложению требуются специфические возможности ODBC, например, пакетное обновление или асинхронные запросы]. Поскольку же посредством ODBCDirect доступны не все возможности DAO, в Microsoft DAO предусмотрена поддержка ODBC ядром Microsoft Jet. Таким образом, для работы с источниками данных ODBC можно использовать и Microsoft Jet, и ODBCDirect или и то, и другое.
594
Глава 22
Выбор доступа к источникам данных ODBC зависит от типа рабочего пространства (workspace), которое определяет активный сеанс, связанный с учетной записью конкретного пользователя.
Рабочие пространства DAO
Объекты DAO, как все объекты приложений Microsoft, организованы в иерархическую структуру. Объекты содержат коллекции, коллекции — другие объекты. Объект DBEngine находится на вершине иерархической объектной модели DAO.
DAO поддерживает две различные среды баз данных (databases environments) или два типа рабочего пространства:
	Microsoft Jet workspace — обеспечивает доступ к данным в базах Microsoft Jet, ODBC-источниках через Microsoft Jet и в базах в формате устанавливаемых драйверов ISAM, таких как Microsoft FoxPro, dBASE, Paradox, Microsoft Excel, Microsoft Exchange и Outlook, Lotus 1-2-3 и др. DAO-модель для Microsoft Jet workspace представлена на рис. 22.11.
	ODBCDirect workspace — обеспечивает доступ к данным посредством ODBC, без загрузки ядра (engine) базы данных Microsoft Jet. DAO-модель для ODBCDirect workspace представлена на рис. 22.2.
[DBEngine |
-| Errors
]—| Error ||
-| Workspaces |—| Workspace ||
-| Databases |—I Database ||
-| Containers |—| Container ||
Documents |—| Document j
-| QueryDefs [—{ QueryDef	[|
-| Fields |—’I Field ||
*-| Parameters ]—| Parameter ||
-| Recordsets |—[ Recordset [|
^~l Fields	|—| Field
-| Relations	[—[Relation
L| Fields	|—pFiZid
^-| Fields"
-| TableDets |—| TableDef ||
-[ Fields
-| Indexes
1-| Field	||
]—| Index	||
L| Fields |-| Field
-| Groups [—| Group ||
Qju ters I—f User
-| Users
Groups
]—| Group '	||
Рис. 22.1. DAO-модель для Microsoft Jet workspace
1 На рисунках 22.1 и 22.2 затененные прямоугольники представляют коллекции, а незатененные — объекты.
Доступ к базам данных из УВА-кода
595
[DBEngine |
-| Errors	|—| Error
-| Workspaces |—| Workspace [|
-| Connections |—[ Connection ||
»	-| QueryDels |—[ QueryDel	[|
L| Parameters Parameter [|
-| Recordsets |—| Recordset [|
Ч Fields ~	]-| Field
-| Databases |—| Database ||
Ч Recordsets |—[ Recordset ||
L| Fields	|—| Field
Рис. 22.2. DAO-модель для ODBCDirect workspace
Рабочее пространство Microsoft Jet следует использовать при работе с базами Microsoft Jet (.mdb-файлами) и другими настольными (desktop) ISAM-базами или, если вам необходимы преимущества некоторых уникальных возможностей системы Microsoft Jet, таких как объединение данных из нескольких баз с различными форматами.
Рабочее пространство ODBCDirect удобно, когда необходимо выполнить запрос или хранимую процедуру (stored procedure) на удаленном сервере, таком как Microsoft SQL Server. Вам могут понадобиться некоторые преимущества ODBC, например, пакетное обновление (batch update), выполнение асинхронного запроса (asynchronous query).
DAO имеет 17 различных типов объектов. Каждый DAO-объект (кроме DBEngine) имеет соответствующую коллекцию, которая включает все существующие объекты этого типа. Например, коллекция Recordsets содержит все открытые Recordset-объекты. Каждая коллекция принадлежит объекту, который расположен на предыдущем уровне в иерархической DAO-структуре. Например, объект Recordset «владеет» коллекцией Fields. Большинство DAO-объектов имеют коллекции и свойства по умолчанию. Например, коллекцией по умолчанию объекта Recordset является Fields, а свойством по умолчанию объекта Field является Value.
На вершине DAO-моделей находится единственный объект DBEngine. Чтобы успешно работать с объектом DBEngine, необходимо хорошо знать его свойства и методы. DBEngine имеет следующие свойства:
DefaultType	Тип — Long. Тип рабочего пространства (Microsoft Jet или ODBCDirect), который будет использоваться при создании Workspace-объекта. По умолчанию свойство устанавливается равным значению константы dbUseJet (стандартным является пространство Microsoft Jet). Создавая рабочее пространство явно, мож-но указать значение этого свойства при помощи аргумента метода CreateWorkspace, используя константу dbUseJet или dbUseODBC (для ODBCDirect).
596
Глава 22
DefaultUser	Тип — String. Имя пользователя, используемое при создании рабочего пространства по умолчанию. Строка может быть длиной от 1 до 20 символов в рабочем пространстве Microsoft Jet и любой длины в рабочем пространстве ODBCDirect. Она может включать алфавитно-цифровые символы, пробелы и любые символы, кроме: " (двойные кавычки), / (прямой слэш), \ (обратный слэш), [] (квадратные скобки), : (двоеточие), | (символ конвейеризации), < (знак меньше чем), > (знак больше чем), + (знак плюс), = (знак равенства), ; (точка с запятой), , ( запятая), ? (знак вопроса), * (звездочка), «ведущих» пробелов и управляющих символов (ASCII 00 to ASCII 31). По умолчанию свойство DefaultUser устанавливается равным строке "admin”. Имя пользователя обычно «чувствительно» к регистру.
Default-Password	Тип — String. Пароль, используемый при создании рабочего пространства по умолчанию. DefaultPassword — строка длиной до 14 символов в рабочем пространстве Microsoft Jet и любой длины в рабочем пространстве ODBCDirect. Может включать любые символы, кроме ASCII 0. Значение по умолчанию — строка нулевой длины (""). Пароль «чувствителен» к регистру.
IniPath	Информация о ключе в Windows Registry, который содержит значения для Microsoft Jet database engine (только для рабочего пространства Microsoft Jet). Ядро Microsoft Jet можно конфигурировать с использованием Windows Registry. Реестр можно использовать для уста|ювки таких параметров, как настраиваемые ISAM DLL. Чтобы эта опция имела какой-либо эффект, необходимо установить свойство IniPath перед тем, как ваше приложение активизирует любой другой DAO-код. Для инициализации параметров некоторых настраиваемых ISAM-драйверов можно также использовать Windows Registry.
LoginTimeout	Количество секунд, через которое выдается ошибка при неудачной попытке подключения к ODBC-базе данных.
SystemDB	Путь для текущего местонахождения файла с информацией рабочей группы (только для рабочего пространства Microsoft Jet).
Version	Рабочее пространство Microsoft Jet: для DBEngine-объекта возвращается используемая версия DAO. Для объекта Database возвращается версия Jet, в которой был создан mdb-файл. Рабочее пространство ODBCDirect: для DBEngine-объекта возвращается используемая версия DA0. Для объекта Database возвращается версия используемого драйвера ODBC.
Объект DBEngine создавать не нужно. Можно написать простую программу для считывания некоторых свойств этого объекта:
Sub DBEngineTest()
MsgBox DBEngine.DefaultType	1	возвращает	2
MsgBox DBEngine.LoginTimeout	'	возвращает	20
MsgBox DBEngine.Version	'	возвращает	3.6
End Sub
Для указания используемого типа рабочего пространства (Microsoft Jet или ODBCDirect) можно либо непосредственно установить свойство DefaultType объекта DBEngine, либо использовать метод CreateWorkspace. Следующие операторы непосредственно задают свойство DefaultType объекта DBEngine:
DBEngine.DefaultType = dbUseJet
DBEngine.DefaultType = dbUseODBC
Доступ к базам данных из УВА-кода 597
В этих операторах использованы DAO-константы dbUseJet и dbUseODBC, которые предназначены для указания типа рабочего пространства.
Как видно из рис. 22.1 и 22.2, обе модели имеют коллекции Workspaces с объектами типа Workspace (рабочее пространство), содержащими открытые базы данных и предоставляющими механизмы работы с таблицами базы. Объект Workspace можно не включать в коллекцию Workspaces, если он используется только в той процедуре (подпрограмме), в которой и создан. В рабочем пространстве Microsoft Jet для доступа к данным базы Microsoft Jet, источникам, требующим драйверов ISAM, и ODBC-источникам можно использовать DAO совместно с ядром Microsoft Jet. В рабочем пространстве ODBCDirect для доступа к источникам данных ODBC допускается использование DAO без обработки запросов ядром Microsoft Jet.
Использование DAO-модели для Microsoft Jet
Рабочее пространство Microsoft Jet включает объекты (рис. 22.1), определяющие структуру базы данных: TableDef, Field, Index, QueryDef, Parameter и Relation. Здесь же находятся объекты, предназначенные для манипуляций с данными, например, Recordset. Для защиты данных предназначены такие объекты, как User, Group, Container и Document.
Для создания рабочего пространства следует использовать метод Create Workspace объекта DBEngine со следующим синтаксисом:
синтаксис
Set workspace = CreateWorkspace(name, user, password [, type])
Аргумент name — строка с уникальным наименованием нового Workspace-объекта. Аргумент user — строка с именем владельца Workspace-объекта. Аргумент password — строка с паролем Workspace-объекта (до 14-ти символов). Необязательный аргумент type — значение одной из констант dbUseJet или dbUseODBC (по умолчанию — dbUseJet).
В следующих операторах для указания используемого типа рабочего пространства применяется метод CreateWorkspace:
Dim wrkJet As Workspace
Set wrkJet = CreateWorkspace ("Jetworkspace", "admin", "")
Объект Database
Объект Database в модели DAO представляет открытую базу данных. Для открытия базы данных и получения ссылки на представляющий ее объект Database во всех приложениях (кроме Microsoft Access) следует использовать метод Open-Database объекта BDEngine или Workspace (на них можно не ссылаться для открытия базы в стандартном рабочем наборе). Синтаксис метода OpenDatabase следующий1:
СИНТАКСИС
Set database = [workspace.]OpenDatabase(dbname [, options] [, read-only] [, connect])
Здесь database — объектная переменная, ссылающаяся на Database-объект; workspace — объектная переменная, представляющая существующее рабочее пространство (по умолчанию — стандартное пространство). Единственный обязательный аргумент dbname — строка с именем существующего файла
1 Приведен полный синтаксис метода — не только для Microsoft Jet.
598
Глава 22
базы данных Microsoft Jet (mdb-файла) или DNS (data source name) ODBC-источника данных.
Необязательный аргумент options устанавливает некоторые опции для базы данных:
	Для пространства Microsoft Jet можно использовать значения констант True (открывает базу для единоличного использования) и False (открывает базу для коллективного использования) — значение по умолчанию.
	Для пространства ODBCDirect можно использовать значения констант dbDri-verNoPrompt [ODBC Driver Manager1 использует строку соединения (connection string)2, предоставляемую аргументами dbname и connect. Если информации будет недостаточно, возникнет runtime-ошибка], dbDriverPrompt [ODBC Driver Manager отображает диалоговое окно ODBC Data Sources, которое содержит любую релевантную информацию, предоставляемую аргументами dbname или connect. Строка соединения состоит из DSN, которое пользователь выбирает посредством диалоговых окон. Если пользователь не указывает DSN, используется DSN по умолчанию.], dbDriverComplete (значение по умолчанию) [Если аргументы connect и dbname включают всю необходимую для соединения информацию, ODBC Driver Manager использует строку в connect. Иначе он действует, как в случае, когда указывается константа dbDriverPrompt] и dbDriverCompleteRequired [оказывает действие, подобное действию константы dbDriverComplete, за исключением того, что ODBC-драйвер запрещает запросы любых данных, которые не требуются для выполнения соединения].
Аргумент read-only — может принимать значение константы True для доступа «только на чтение» и — False (по умолчанию) для разрешения вносить изменения в базу. Аргумент connect — строковое выражение для определения информации о подключении, включая пароль.
Объект BDEngine (или Workspace) позволяет не только открыть существующую базу данных Microsoft Jet, но и создать новую с использованием метода CreateDatabase со следующим синтаксисом:
СИНТАКСИС
Set database = [workspace.]CreateDatabase (dbname, locale [, options])
Здесь database — объектная переменная, ссылающаяся на Database-объект; ' workspace — объектная переменная, представляющая существующее рабочее пространство (по умолчанию — стандартное пространство). Аргумент dbname — строка с (полным) именем создаваемого файла базы данных Microsoft Jet (mdb-файла). Аргумент locale — строковое выражение, которое определяет порядок сортировки по умолчанию текстовых значений создаваемой базы данных; в качестве значений этого аргумента следует использовать константы dbLangGeneral, dbLangArabic, dbLangCyrillic и другие (см. справочную систему). Этот же аргумент можно использовать для задания пароля для создаваемой базы данных, конкатенируя значение необходимой константы со строкой вида ";pwd=NewPassword", например:	,
dbLangCyrillic & ";pwd=NewPassword"	,
1	Приложение, которое управляет соединениями между источниками данных, доступными посредством ODBC, и драйверами, используемыми для доступа.
2	Строка, используемая для определения источника данных внешней базы и обычно назначаемая свойству Connect объектов QueryDef, TableDef, Connection или Database или аргументу метода OpenDatabase.
Доступ к базам данных из VBA-кода
599
Необязательный аргумент options — константа (или комбинация констант), определяющая дополнительные свойства создаваемой базы данных. В качестве констант могут использоваться: dbEncrypt (база данных с шифрованными данными), dbVersionlO (используется формат файлов версии Microsoft Jet database engine 1.0), dbVersionll (используется формат файлов версии Microsoft Jet database engine 1.1), dbVersion20 (используется формат файлов версии Microsoft Jet database engine 2.0), dbVersion30 (значение по умолчанию, используется формат файлов версии Microsoft Jet database engine 1.0, совместимый с версией 3.5).
Database-объект имеет свойства и методы, которые позволяют манипулировать данными открытой базы. Например, для любого типа базы данных можно использовать метод Execute для выполнения запроса-действия (action query)1 или задавать свойство Connect для установления связи с ODBC-источником данных. Для ограничения времени ожидания выполнения запроса для ODBC-источника данных можно использовать свойство QueryTimeout.
Метод OpenRecordset позволяет выполнить запрос на выбор данных (select-запрос)2 и создает Recordset-объект.
С базой данных Microsoft Jet (mdb-файл) можно также использовать такие методы и свойства (и коллекции) для манипулирования Database-объектами, как:
	методы CreateTableDef и CreateRelation для создания таблиц и связей;
	метод CreateProperty для определения новых Database-свойств;
	метод CreateQueryDef для создания постоянного (persistent) или временного определения запроса;
	методы MakeReplica, Synchronize и PopulatePartial для создания и синхронизации полных или частичных реплик3 базы данных;
	свойство CollatingOrder для установления алфавитного порядка сортировки полей, содержащих символьные данные.
В рабочем пространстве ODBCDirect можно использовать:
	Свойство Connection для получения ссылки на объект Connection, который соответствует Database-объекту.
Объект Recordset
Объект Recordset представляет набор записей в базе данных и позволяет манипулировать данными базы на уровне записи. В DAO’ имеется пять типов Recordset-объектов:
	Table-type Recordset (табличный) — (только в рабочих пространствах Microsoft Jet) представление (в коде) базисной таблицы в базе данных. В рабочем пространстве Microsoft Jet объект Recordset этого типа можно использовать для добавления, удаления и обновления записей в таблице. Свойство Record-Count табличного объекта Recordset возвращает число записей в таблице.
	Dynaset-type Recordset (динамический набор) — результат запроса по одной или нескольким таблицам. Этот набор записей позволяет добавлять, модифицировать и удалять записи из входящей в него таблицы или таблиц. Объект
1	Запрос позволяет извлекать данные или изменять их в базе данных.
2	Запрос, который «отвечает на вопрос», какие данные хранятся в базе данных, и возвращает Recordset-объект без изменения данных. После нахождения Recordset-данных их можно проверять и изменять в основных таблицах. В отличие от этих запросов запросы-действия могут изменять данные, но не возвращают наборов данных.
3	Копия базы данных, включающая ее таблицы, запросы, формы, отчеты, макросы и модули.
600
Глава 22
Recordset этого типа можно создавать в рабочих пространствах Microsoft Jet и ODBCDirect.
	Snapshot-type Recordset (статический, набор) — результат запроса. Набор содержит значения всех полей, указанных в запросе. Данные в наборе нельзя модифицировать, но объект Recordset такого типа требует меньше ресурсов, чем динамический набор.
	Forward-only-type Recordset (статический набор с последовательным доступом) — результат запроса. Объект Recordset этого типа похож на Recordset статического набора, за исключением того, что по его записям можно «продвигаться» только в направлении от начала к концу набора.
	Dynamic-type Recordset (динамический) — (только в рабочих пространствах ODBCDirect) результат запроса из одной или более таблиц.
Объект Recordset создается методом OpenRecordset объекта Database. Синтаксис метода следующий:
СИНТАКСИС г;
Set recordset = object. OpenRecordset (source [, type] [, options'] I, locked!ts])
Здесь recordset — объектная переменная, представляющая открываемый объект Recordset; object — объектная переменная, представляющая уже созданный объект, используемый для создания нового Recordset-объекта; source — строка, определяющая источник записей [имя таблицы или запроса, SQL-инструкция, возвращающая записи; для табличного объекта Recordset в базе данных Microsoft Jet допускается указание только имени таблицы в mdb-файле]. Необязательный аргумент type указывает тип объекта Recordset и может принимать значение одной из констант:
	dbOpenTable — для открытия Recordset-объекта типа «табличный»;
	dbOpenDynaset — для открытия Recordset-объекта типа «динамический набор»;
	dbOpenSnapshot— для открытия Recordset-объекта типа «статический набор»;
	dbOpenForwardOnly — для открытия Recordset-объекта типа «статический набор с последовательным доступом»;
	dbOpenDynamic — для открытия Recordset-объекта типа «динамический». Необязательный аргумент options определяет характеристики нового Recordset-объекта и может принимать значение одной из констант:
	dbAppendOnly — позволяет добавлять новые записи в набор, но не разрешает редактирование и удаление существующих записей (только для типа «динамический набор» Microsoft Jet);
	dbSQLPassThrough — передает SQL-инструкцию ODBC-источнику, доступному посредством Microsoft Jet (только для типа «статический набор» Microsoft Jet);
	dbSeeChanges— генерирует runtime-ошибку, если один пользователь изменяет данные, которые редактируются другим пользователем (только для типа «динамический набор» Microsoft Jet);
	dbDeny Write — не разрешает другим пользователям модифицировать и добавлять записи (только для Recordset-объекта Microsoft Jet);
	dbDenyRead — не разрешает другим пользователям считывать данные из таблицы (только для типа «табличный» Microsoft Jet);
	dbForwardOnly — создает статический набор с последовательным доступом (только для Recordset-объекта типа «статический набор» Microsoft Jet). Не
Доступ к базам данных из УВА-кода
601
обходим только для обратной совместимости; при этом в качестве аргумента type нужно использовать значение константы dbOpenForwardOnly;
	dbReadOnly — не допускает внесение изменений в Recordset-объект (только для Microsoft Jet). Присвоение значения константы dbReadOnly аргументу lockedits заменяет эту константу, которая предназначена только для обратной совместимости;
	dbRunAsync — запускает асинхронный запрос (только для рабочего пространства ODBCDirect);
	dbExecDirect — выполняет запрос, пропуская SQLPrepare и вызывая непосредственно SQLExecDirect (только для ODBCDirect). Следует использовать эту опцию только для Recordset-объекта, не основанного на запросе с параметрами1;
	dblnconsistent — позволяет выполнять несогласованные обновления (только для Recordset-объекта типа «динамический набор» и «статический набор» Microsoft Jet);
	dbConsistent — позволяет выполнять только согласованные обновления (только для Recordset-объекта типа «динамический набор» и «статический набор» Microsoft Jet).
Необязательный аргумент lockedits устанавливает тип блокировки данных и может принимать значение одной из констант:
	dbReadOnly — запрещает пользователям вносить изменения в Recordset-объект (только для рабочего пространства ODBCDirect). Можно использовать dbReadOnly либо в аргументе options, либо в lockedits, но не в обоих. В противном случае возникает runtime-ошибка;
	dbPessimistic — использует «пессимистическую» блокировку для определения порядка внесений изменений в Recordset в многопользовательской среде. Страница1 2, содержащая редактируемую запись, блокируется сразу при использовании метода Edit (по умолчанию для рабочих пространств Microsoft Jet);
	dbOptimistic — использует «оптимистическую» блокировку3 для определения порядка внесений изменений в многопользовательской среде. Страница, содержащая редактируемую запись, не блокируется, пока не используется метод Update;
	dbOptimisticValue — использует «оптимистический» параллелизм, основывающийся на значениях строк (только для рабочего пространства ODBCDirect);
	dbOptimisticBatch — позволяет выполнять «оптимистическое» обновление пакетов4 (только для рабочего пространства ODBCDirect).
1 Запрос, который требует предоставления одного или нескольких значений-критериев перед выполнением запроса.
2 Часть базы данных, в которой хранятся записи. В зависимости от размера записей страница может содержать более одной записи. В базах данных Microsoft Jet (mdb-файлы) страница имеет длину 2048 (2К) байтов.
3 Тип блокировки, при которой страница данных, содержащая одну или несколько записей, включая редактируемую запись, недоступна другим пользователям, только пока запись обновляется методом Update, но доступна между вызовами методов Edit и Update. «Оптимистическая» блокировка используется при доступе к ODBC-базам данных или, когда свойство LockEdit объекта Recordset равно значению константы False.
1 Модель курсора для клиентов, которые работают с курсорами, но не блокируют сервер или выдают обновление по одной строке. Вместо этого клиент обновляет несколько строк, которые буферизуются локально, а затем использует пакетное обновление. Эта модель курсора дает возможность пользователю отменять соединение с сервером и вновь устанавливать соединение с тем же или даже другим сервером.
602
Глава 22
Для работы с объектом Recordset необходимо знать его свойства и методы. Некоторые из них приведены в следующей таблице.
Метод	Описание
AddNew	Добавляет новую (пустую) запись. После внесения в поля записи данных следует вызвать метод Update.
Close	Закрывает Recordset-объект.
Delete	Удаляет текущую запись (которая была достигнута методами MoveFirst, MoveLast, MoveNext, MovePrevious, FindFirst, FindLast, FindNext, FindPrevious, Seek) в Recordset-объекте.
Edit	Устанавливает режим редактирования текущей записи Recordset-объекта. После редактирования записи следует вызвать метод Update.
MoveFirst, MoveLast, MoveNext, MovePrevious	Устанавливает в качестве текущей первую, последнюю, следующую или предыдущую запись Recordset-объекта, соответственно.
FindFirst, FindLast, FindNext, FindPrevious	Устанавливает в качестве текущей соответственно первую, последнюю, следующую или предыдущую запись, удовлетворяющую заданным условиям (в виде текстовой строки с условным выражением).
Seek	Устанавливает в качестве текущей запись, удовлетворяющую некоторым условиям, в индексированном Recordset-объекте типа «табличный».
Update	Сохраняет результаты методов AddNew и Edit.
CancelUpdate	Отменяет все изменения в Recordset-объекте, выполненные посредством методов AddNew и Edit.
Свойство	Описание
BOF, (EOF)	Возвращает значение константы True, если указатель текущей записи находится перед первой записью (после последней записи) набора.
NoMatch	Возвращает значение константы True, если необходимая запись найдена.
RecordCount	Возвращает количество записей в Recordset-объекте.
Для получения подробной информации о методах и свойствах объекта Recordset следует обратиться к справочной системе или к многочисленным изданиям по программированию на VBA и VB. '	,
Пример работы подключения VBA-кода к базе данных
Рассмотрим пример использования объекта Recordset в Excel-приложении. В предыдущих двух главах была создана база данных и заполнены ее таблицы в среде Access. Воспользуемся таблицей Товары этой базы для вывода информации в диалоговом Excel-окне, которое в режиме разработки представлено на рис. 22.3.
Доступ к базам данных из УВА-кода
603
Рис. 22.3
Форма в режиме разработки для тестирования методов объектов
Database и Recordset
Несмотря на то что форма довольно простая, приведем, как обычно, ее элементы управления в следующей таблице:
Тип элемента	Свойство, которое изменено (используется в коде)	Значение	Примечание
UserForm	Name	UserForml	Имя главной формы, на которое можно ссылаться в коде.
Frame	Name	Frame 1	Имя, на которое можно ссылаться в коде.
	Caption	Список товаров	Текст - заголовок.
ListBox	Name	ListBox 1	Имя, на которое можно ссылаться в коде.
CommandButton	Name	CmdLoad	
	Caption	Загрузить список	Заголовок для кнопки.
CommandButton	Name	CmdExit	
	Caption	Выход	Заголовок для кнопки.
	Cancel	True	Клавиша Esc также вызовет процедуру CmdExit_Click.
Код модуля этой формы, включающий две событийные процедуры, приведен в листинге 22.1.
Листинг 22.1. Открытие существующей базы данных и считывание ее записей в элемент управления формы
1	Private Sub CmdLoad_Click()
2
3	Dim my_base As Database
4	Dim rstNwind As Recordset
DAO-объект: база данных
DAO-объект: набор данных
604
Глава 22
5
б	' открыть базу данных:
7	Set my_base = OpenDatabase("d:\dbs.mdb")
8
9	' открыть набор:
10	Set rstNwind = my_base.OpenRecordset("Товары", dbOpentTable)
11
12	If rstNwind.RecordCount > 0 Then
13
14	rstNwind.MoveFirst	' перейти к началу набора
15
16	' до конца набора добавлять записи в список
17	‘ Do While Not rstNwind.EOF
18	ListBoxl.Additem rstNwind.Fields(1)
19	rstNwind.MoveNext
'20
21	Loop
22	End If
23
24 End Sub
25
26
27	Private Sub CmdExit_Click()
28	Unload Me
29	End Sub
В строках 1-24 описана событийная процедура для кнопки с заголовком «Загрузить список». В строках 3—4 описываются переменные my_base и rstNwind, одна из которых имеет тип Database, другая — Recordset. (Для успешной работы кода необходимо в окне References установить ссылку на Microsoft DAO 3.6 Object Library.) Код в строке 7 использует метод OpenDatabase объекта DBEngine, чтобы открыть существующую базу данных. Код в строке 10 открывает Recordset-объект rstNwind с записями таблицы Товары.
В строке 12 проверяется условие наличия записей в наборе rstNwind. Пока не было обращения к записям набора, свойство RecordCount не содержит точного количества записей в наборе rstNwind, но, по крайней мере, его значение будет больше нуля, если в таблице Товары имеется хотя бы одна запись. Если записи в таблице Товары имеются, то выполняются строки кода 14-21: метод MoveFirst устанавливает текущей первую запись набора, далее в цикле считываются записи второго столбца таблицы с использованием коллекции Fields — полей набора, которым соответствуют кортежи отношения.
В строке 17 находится заголовок цикла Do While, который в качестве условия окончания цикла использует значение свойства EOF набора rstNwind. В строке 19 применяется метод MoveNext объекта Recordset для перемещения к следующей записи набора. Результат работы процедуры CmdLoad_Click приведен на рис. 22.4.
Рис. 22.4
Диалоговое окно в режиме исполнения для тестирования методов объектов Database и Recordset
Доступ к базам данных из УВА-кода
605
В строках 27-29 описана событийная процедура кнопки с заголовком «Выход», которая просто завершает работу приложения.
Рассмотрим подробнее строку 10 кода листинга 22.1, которая связывает с Re-cordset-объектом rstNwind набор записей таблицы Товары из mdb-базы данных:
Set rstNwind = my_base.OpenRecordset("Товары", dbOpenTable)
В этом операторе используется константа dbOpenTable для выбора Recordset-объекта rstNwind типа «табличный». В результате в набор попали все поля таблицы (все кортежи отношения) Товары, хотя нам, на самом деле, нужны были только наименования товаров. По этой причине в строке 18 при извлечении наименований из набора используется оператор, в котором указан номер второго поля набора:
ListBoxl.AddItem rstNwind.Fields(1)
Если данные всей таблицы Товары действительно не нужны, то набор rstNwind можно открыть другим оператором:
Set rstNwind = my_base.OpenRecordset("SELECT НаименованиеТовара FROM Товары", dbOpenDynaset)
И поскольку теперь коллекция Fields содержит только один элемент типа Field, оператор в строке 18 должен иметь вид:
ListBoxl.Additem rstNwind.Fields(0)
Что изменилось в вызове метода OpenRecordset? В качестве первого аргумента используется строка с SQL-запросом, поэтому переменная rstNwind ссылается на набор, состоящий из таблицы с одним столбцом. Но важно в данном случае то, что мы, вообще-то, можем использовать не только этот простой QSL-запрос, а любой — какой только нам будет нужен.
Изменим немного рассматриваемую форму: добавим к форме текстовое окно для ввода строки и вместо элемента ListBox поместим на форму элемент MSFlexGrid, который позволяет выводить несколько столбцов таблицы (рис. 22.5). При этом таблица со свойствами элементов управления формы будет иметь следующий вид:
Тип элемента	Свойство, которое изменено(используется в коде)	Значение	Примечание
UserForm	Name	UserForml	Имя главной формы, на которое можно ссылаться в коде.
Frame	'	Name	Frame 1	Имя, на которое можно ссылаться в коде.
	Caption	Список товаров	Текст - заголовок.
MSFlexGrid	Name	MSFlexGrid 1	Имя, на которое можно ссылаться в коде.
CommandButton	Name	CmdLoad	
	Caption	Загрузить список	Заголовок для кнопки.
CommandButton	Name	CmdExit	
	Caption	Выход	Заголовок для кнопки.	।
606
Глава 22
Тип элемента	Свойство, которое изменено (используется в коде)	Значение	Примечание
	Cancel	True	Клавиша Esc также вызовет процедуру CmdExit_Click.
Label	Name	Label 1	Метка для TextBoxl.
TextBox	Name	TextBoxl	Текстовое окно для ввода строки с SQL-запросом.
Рис. 22.5
Диалоговое окно в режиме разработки для тестирования методов объектов
Database и Recordset
С учетом свойств элемента MSFlexGrid событийная процедура кнопки с заголовком «Загрузить список» может выглядеть так, как приведено в листинге 22.2.
Листинг 22.2. Открытие существующей базы данных и считывание ее записей в элемент управления формы MSFlexGrid
1 Private Sub CmdLoad_Click()
2
3	Dim my_base As Database	' DAO-объект: база данных
4	Dim rstNwind As Recordset	' DAO-объект: набор данных
5	Dim SQLstr As String
6	*
7	' открыть базу данных:
8 Set my_base = OpenDatabase("d:\dbs.mdb")
9
10	' ввести SQL-запрос:
11	SQLstr = TextBoxl.Text
12
13	1 11 открыть набор:
14	Set rstNwind = my base.OpenRecordset(SQLstr, dbOpenDynaset)
15
16 If rstNwind.Recordcount > 0 Then
17
18	rstNwind.MoveFirst	' перейти к началу набора
19
20	' задать количество строк:
21	MSFlexGridl.Cols = rstNwind.Fields.Count + 1
22
Доступ к базам данных из УВА-кода
607
23	' установить ширину первых колонок:
24	MSFlexGridl.ColWidth(0) = 1
25	’ If MSFlexGridl.Cols > 1 Then MSFlexGridl.ColWidth(1) = 1500
26	If MSFlexGridl.Cols > 2 Then MSFlexGridl.ColWidth(2) = 2000
27
28	' до конца набора добавлять записи в таблицу:
29	Do While Not rstNwind.EOF
30
31	' сформировать элемент добавления к таблице:
32	newElement = ""
33	For i - 0 То rstNwind.Fields.Count - 1
34	newElement = newElement & Chr(9) & rstNwind.Fields(i)
35	Next
36
37	' добавить элемент к таблице:
38	MSFlexGridl.Additem newElement
39
40	rstNwind.MoveNext
41	Loop
42	End If
43
44	End Sub
В строке 11 приведенного кода считывается, возможно, строка с SQL-запросом, который затем используется в строке 14 в качестве аргумента метода OpenRecordset. В строке 21 задается свойство Cols (количество столбцов должно соответствовать количеству столбцов Recordset-объекта) объекта MSFlexGridl. В строках 24-26 задается ширина первых трех столбцов объекта MSFlexGridl. Эта часть кода существенно зависит от выводимых данных, поэтому ее трудно сделать универсальной.
В строках 32-35 формируется строка для добавления в объект MSFlexGridl. Эта строка состоит из значений полей набора rstNwind (rstNwind.Fields.Count — количество полей в наборе), разделяемых символом табуляции. В строке 38 к объекту MSFlexGridl добавляется очередная строка с данными.
Конечно, код процедуры CmdLoad_Click должен иметь обработчик прерываний для обработки ошибок, но для простоты кода этого не сделано, так как чаще всего такие естественные для разработчика элементы программного кода затеняют главную цель того или иного примера.
На рис. 22.6 приведено диалоговое окно данного приложения, в котором в текстовое поле введена строка "Товары", т.е. здесь не используется SQL-инструкция, а просто указывается имя таблицы. В результате работы процедуры CmdLo-ad_Click в объекте MSFlexGridl отображаются все поля таблицы.
Рис. 22.6
Диалоговое окно отображает все поля таблицы Товары
UscrForml
SQL-запрос
’ Товары
Список товаров
006019165803 006019170049 010414114438 010415090732 010415090937 010428144348 028019095823
028019100018
(5) Road Rush II
(5) Tasmania (VCD) Патриот (VCD) Пастырь (VCD) Шоссе в никуда (VCD) Доберман (VCD) Didrr Marouani (VCD) Wham1 The best of
028019100222 (VCD) Голая мишень
036019164741	(5) Cod Spot
174500175359 ) Street Fighter 3 Wimpact
42
30
138 111
120 135
90
105
90
42
750
130
15S
105
123
105
49
875
Загрузить список
Выход
608
Глава 22
На рис. 22.7 приведен результат работы процедуры CmdLoad_Click, код которой использует (из текстового окна TextBoxl) следующий SQL_3anpoc:
SELECT а.НаименованиеТовара, Ь.Количество
FROM Товары а, Инвентарная_ведомость b WHERE а.КодТовара=Ь.КодТовара
Рис. 22.7
Диалоговое окно отображает поля, полученные в наборе в результате SQL-запроса
Userforml
SQL-iarqjoc
SELECT а НаименованиеТовара b Количество FROM Товары а, Инвентарная_ведомость b WHERE а КодТовара-!
Список товаров
(S) Road Rush II
(5) Road Rush II \S) Tazmama (S) Tasmania (S) Tasmania (VCD) Патриот (VCD) Патриот
(VCD) Доберман (VCD) Доберман
(S) Cool Spot (S) Cool Spot
200 1200 1000
500 1000
400
3300
800 4200 2000
600
Загрузить список ।
Выход
На рис. 22.8 приведен результат работы процедуры CmdLoad_Click, код которой использует (из текстового окна TextBoxl) следующий SQL_3anpoc:
SELECT с.НаименованиеСклада, SUM(Ь.Количество)
FROM Инвентарная_ведомость Ь, Склады с WHERE Ь.КодСклада=с.КодСклада GROUP BY с.НаименованиеСклада
Рис. 22.8
Диалоговое окно отображает поля, полученные в наборе в результате SQL-запроса
Пример создания базы данных из кода VBA
Рассмотрим пример создания базы данных из кода VBA. Создавать базы данных из кода приходится в основном для каких-либо временных таблиц или для данных, которые существенно связаны с датами. Например, если создается база данных с накладными некоторой производственно-торговой фирмы, то есть смысл накладные для каждого отчетного периода (например, месяца) хранить в отдельных mdb-файлах. Относительно небольшой размер файла за период будет способствовать увеличению скорости обработки информации, а хранение данных в нескольких файлах поможет решить задачи надежности — при порче файла текущего периода информация, хранящаяся в файлах с данными предыдущих периодов (быть может, даже защищенных от записи), не пострадает. Впрочем, задачи эффективности и надежности не являются темами данной книги.
Доступ к базам данных из VBA-кода
609
В листинге 22.3 приведен код простой процедуры, которая создает файл с именем test_mdb.mdb и таблицу Телефоны с тремя полями.
Листинг 22.3. Создание базы данных из VBA-кода
1	Sub CreateDatabaseTest()
2	' создает базу данных test_mdb.mdb с таблицей Телефоны
3
4	Dim	myDatabase	As Database
5	Dim	myTable As	TableDef
6	Dim	myField As	Field
7
8	' создание базы данных:
9	On Error GoTo NotCreateBase
10	Set myDatabase = DBEngine.CreateDatabase("test_mdb", dbLangGeneral)
11	MsgBox "База данных test_mdb.mdb создана"
12
13	' создание таблицы базы данных с тремя полями:
14	On Error GoTo NotCreateTable
15
16	Set myTable = New TableDef
17
18	With myTable
19	.Fields.Append .CreateField("Фамилия", dbText)
20	.Fields.Append .CreateField("Имя", dbText)
21	.Fields.Append .CreateField("Телефон", dbText)
22	End With
23
24	' присвоить имя таблице:
25	myTable.Name = "Телефоны"
26	myDatabase.TableDefs.Append myTable
27
28	Set myDatabase = Nothing
29	.:
30	MsgBox "Таблица создана"
31	Exit Sub
32
33	NotCreateBase:
34	MsgBox "У нас проблема с созданием базы данных test_mdb.mdb"
35	Exit Sub
36
37	NotCreateTable:
38	MsgBox "У нас проблема с созданием таблицы"
39
40	End Sub
В строках 4-6 описываются переменные типа Database (база данных), TableDef (определение таблицы) и Field (поле таблицы), место которых в модели DAO показано на рис. 22.1. Эти типы данных доступны в VBA-коде, если в окне References (меню Tools ] References) установлен флажок Microsoft DAO 3.6 Object Library. '
Для проверки того, поддерживается ли VBA-системой тот или иной тип данных, не следует торопиться набирать этот тип с клавиатуры. Лучше подождать после набора ключевого слова As, пока VB-редактор предложит выбрать поддерживаемый тип данных из всплывающего списка. Полезно также набирать наименования свойств и методов на одном регистре - если VB-редактор не изменяет отдельные символы в таких наименованиях, значит (из-за ошибки при вводе) они ему неизвестны.
В строке 9 «включен» обработчик ошибок для сигнализации о том, что по каким-то причинам mdb-файл не создан. В строке 10 находится оператор, создающий
20 Программирование на VBA 2002
610
Глава 22
новую базу данных при помощи метода CreateDatabase объекта DBEngine. Если обработчик ошибки создания базы не запускается, значит, база создана, можно выполнять код дальше. При возникновении ошибки выполнение кода продолжается с оператора в строке 34: перед завершением процедуры выдается сообщение.
В строке 14 устанавливается новый обработчик ошибок. В строке 16 создается новый объект типа TableDef. В строках 18-22 для нового объекта создаются три текстовых поля. В строке 25 новая таблица получает имя, а в строке 26 созданная таблица добавляется к базе данных.
Доступ к источникам данных ODBC
При доступе к данным ODBC рабочее пространство Microsoft Jet обеспечивает следующие (некоторые) возможности, отсутствующие в рабочем пространстве ODBCDirect:
	Обновляемые объединения: возможность модификации данных в Recodrset-объектах, представляющих объединения нескольких таблиц.
	Поддержка подключенных таблиц: возможность хранить в локальной базе данных Microsoft Jet постоянные связи с сервером баз данных с возможностями кэширования информации о структуре, полях и индексах подключенной таблицы в локальной базе данных.
	Поддержка методов поиска: доступность методов FindFirst, FindNext, Find-Previous и FindLast объекта Recodrset.
*	Нестандартные свойства: возможность добавлять новые свойства к существующим объектам.
	Перекрестные запросы: возможность использовать SQL-оператор TRANSFORM для создания перекрестных запросов.
	Доступ к неоднородным данным: возможность работать с удаленными данными, данными mdb-файлов и данными, доступными посредством устанавливаемых драйверов ISAM. Возможность объединять данные из разных источников.
	Язык определения данных (Data Definition Language, DDL): возможность модифицировать структуру базы данных.
Технология ODBCDirect дает возможность осуществления доступа к удаленным данным посредством модели DA0 поверх интерфейса ODBC API, что позволяет устанавливать соединения, создавать курсоры и выполнять сложные процедуры при минимальном использовании ресурсов локального компьютера, минуя ядро Microcoft Jet. ODBCDirect имеет следующие преимущества:
	Прямой доступ: VBA-приложение может непосредственно обращаться к источникам данных ODBC, что позволяет повысит производительность, снизить сетевой трафик, переложить на сервер большую часть нагрузки по обработке данных.
	Улучшенный доступ к специфическим возможностям сервера: приложение получает доступ к функциям сервера баз данных, недоступным через Microsoft Jet. Например, можно задавать входные параметры для хранимых (на сервере) процедур и контролировать возвращаемые значения.
	Асинхронные запросы: после выдачи запроса, можно выполнять любой программный код, не дожидаясь результата запроса, время от времени проверяя, не завершен ли запрос.
	Пакетное обновление с нежесткой блокировкой (batch optimistic updating): приложение может локально кэшировать изменения объекта Recordset и передавать их на сервер единым пакетом.
	Выполнение хранимых процедур: приложение может обрабатывать возвращаемые значения и выходные параметры хранимых процедур.
Доступ к базам данных из УВА-кода
611
Перед использованием ODBC необходимо зарегистрировать источник данных ODBC, информация о котором сохраняется в реестре и становится доступной всем приложениям. Зарегистрировать источник данных можно с помощью диспетчера источников данных ODBC или из VB-кода. В следующей главе показано, как зарегистрировать базу данных на удаленном сервере, а здесь в качестве примера зарегистрируем как источник ODBC базу данных d:\dbs.mdb, для работы с которой использовалась форма, представленная на рис. 22.5-22.8.
Щелкните (один раз или дважды, в зависимости от настройки вашей системы) значок (рис. 22.9) диспетчера источников данных ODBC.
Рис. 22.9
Значок диспетчера источников данных ODBC
Data Sources (ODBC)
i- .t
Возможно, окно диспетчера источников данных ODBC будет похоже на представленное на рис. 22.10.
Рис. 22.10
Возможно, окно диспетчера источников данных ODBC будет похоже на это окно
ODBC Data Source Administrator
User DSN ^System DSN File DSN ’ Drivers 1 Tracing | Connection Pooling About §
User Data Sources
Файлы dBASE 1 Файлы Excel
Driver „„ _	, t_
Microsoft Access Driver (*mdb)
Microsoft dBase Driver (* dbf)
Microsoft Excel Driver (* xls)
Bemove
Configure
A^d
An ODBC User data source stores information about how to connect to the indicated data provider AUser data source is only visible to you andean only be used on the current machine
j Help
Щелкните кнопку Add (добавить) для добавления нового источника и в списке Select a driver for which you want to set up a data source (рис. 22.11) окна Create New Data Source выберите Microsoft Access Driver (*.mdb). Затем щелкните кнопку Finish.
Рис. 22.11
В списке Select a driver for which you want to set up a data source выберите Microsoft Access Driver (*.mdb)
20*
612
Глава 22
В текстовом поле Data Source Name (Имя источника данных) окна ODBC Microsoft Access Setup (Установка драйвера ODBC для Microsoft Access) введите имя нового источника (то, на что из VB-кода мы будем ссылаться как на DSN), например, Test_dbs (рис. 22.12). Для выбора базы данных для ODBC-источника щелкните кнопку Select.
Рис. 22.12
В текстовом поле Data Source Name окна ODBC Microsoft Access Setup введите имя нового источника
В диалоговом окне Select Database очень просто указать базу данных (рис. 22.13).
Рис. 22.13
В диалоговом окне Select Database очень просто указать базу данных
Select Database
Database N§me ^dbs mdb
Directories
d\
__—
CD ads_win_zip О binom200099
; cd girls
I CD netsp
‘ Cd VBA_2002 CD VBprojects CD Vs6sp5vb
I OK
Cancel
Help J [“ Read Only ( Exclusive
List Files of Type
Access Databases f mdl
Drives
'Isa d	Network
В результате в окне ODBC Microsoft Access Setup можно будет увидеть то, что представлено на рис. 22.14, а в окне ODBC Data Source Administrator (рис. 22.15) появляется новый источник ODBC-данных — Test_dbs.
Использование DAO-модели для ODBCDirect
Модель объектов рабочего пространства ODBCDirect включает подмножество объектов рабочего пространства Microsoft Jet и объект Connection (см. рис. 22.2). Объект Workspace, содержащий коллекцию Connections, представляет рабочее пространство ODBCDirect и может быть включен в коллекцию рабочих пространств Workspaces.
Доступ к базам данных из УВА-кода
613
Рис. 22.14
В диалоговом окне ODBC
Microsoft Access Setup должна быть именно такая информация
ODBC Microsoft Access Setup
Data Source Цате	Test_dbs
Qescnption	|
Database
Database D\dbsmdb
, j	Greats । Repair | Compact
System Database
• Nong
Database
Й8
OK
Cancel
Help
Advanced
2ptions>> |
Рис. 22.15
В окне ODBC Data Source Administrator появляется новый источник ODBC-данных — Test_dbs
J-tODBC DataSource Administrator
UserOSN | System DSN } File DSN Drivers Tracing j Connection Pooling About
User DataSources
’Driver.................
___________ Microsoft Access Driver (*mdb) База данных MS Access Microsoft Access Driver (* mdb)
Microsoft dBase Driver (* dbf) Microsoft Excel Driver (*xls)
Name
, Файлы dBASE Файлы Excel
An ODBC User data source stores information about how to connect to the indicated data provider A User data source is only visible to you andean only be used on the current machine
OK
Cancel
j Help
Объект Connection является элементом коллекции Connections (все открытые объекты Connection), представляет соединение с источником ODBC в рабочем пространстве ODBCDirect и предоставляет следующие возможности для доступа к ODBC-данным:
	Асинхронное подключение. Программа может асинхронно подключаться к источнику данных ODBC, не ожидая установления, но впоследствии проверяя результат выполнения соединения.
	Асинхронные запросы. Программа может асинхронно выполнять запросы к ODBC-источнику, не ожидая выполнения длительных запросов, но впоследствии проверяя результат выполнения запроса.
	Объекты QueryDef. Для работы с данными ODBC-источника можно определять объекты QueryDef, представляющие запросы.
Для создания объекта Connection следует использовать метод OpenConnection объекта Workspace с синтаксисом:
.СИНТАКСИС’
Set connection = (workspace.]OpenConnection (dbname (, options] [, readonly] (, connect])
614
Глава 22
Здесь connection — объектная переменная типа Connection, которая будет ссылаться на новое соединение. Необязательная переменная workspace — переменная типа Workspace, ссылающаяся на рабочее пространство, которое будет содержать новое соединение.
Аргумент dbname — строковое выражение, определяющее имя зарегистрированного источника данных.
Необязательный аргумент options определяет, следует ли и когда выдавать запрос на подключение, следует ли устанавливать асинхронное соединение. Для этого аргумента предусмотрены следующие константы:
	dbDriverNoPrompt — ODBC Driver Manager (диспетчер драйверов ODBC) использует строку подключения, исходя из содержимого аргументов dbname и connect.
и dbDriverPrompt — ODBC Driver Manager выводит на экран диалоговое окно ODBC Data Sources, которое отображает любую релевантную информацию, содержащуюся в dbname или connect. Строка подключения (connection string) определяется DSN, выбранным пользователем в этом окне.
	dbDriverComplete — (значение по умолчанию) Если аргумент connect включает всю необходимую информацию для выполнения соединения, ODBC Driver Manager использует в качестве строки соединения значение аргумента connect. В противном случае поведение диспетчера аналогично поведению при использовании константы dbDriverPrompt.
	dbDriverCompleteRequired — Использование этой константы имеет такой же результат, как и при использовании dbDriverComplete, но ODBC-драйвер блокирует запросы любой информации, которая не требуется для завершения подключения.
	dbRunAsync — Выполнять метод асинхронно. Может использоваться с любой другой options-константой.
Необязательный аргумент readonly (тип Boolean) определяет режим доступа: при значении True — доступ только на чтение; при False (значение по умолчанию) — на чтение и запись.
Необязательный аргумент connect — строка подключения, содержащая параметры для диспетчера драйверов ODBC. Она может включать имя пользователя, пароль, имя базы данных по умолчанию и имя источника данных, переопределяющее значение аргумента dbname. Строка подключения начинается с "ODBC;" и содержит последовательность именованных параметров, необходимых драйверу для доступа к данным. Состав именованных параметров зависит от источника данных, но как минимум, требуются идентификатор пользователя (UID), пароль (PWD) и имя источника данных (DSN). Если аргумент не указывается, значения UID и/или PWD берутся из свойств UserName и Password объекта Workspace.
Для полученного в предыдущем разделе ODBC-источника данных с именем Test_dbs событийная процедура CmdLoad_Click из листинга 22.2 может быть переписана, как показано в листинге 22.4.
Листинг 22.4. Открытие существующей базы данных и считывание ее записей в элемент управления формы MSFlexGrid
1	Private Sub CmdLoad__Click ()
2
3	Dim	my_wrk As Workspace
4	Dim	my cnn As Connection
5	Dim	ConnectStr As String
6	Dim	rstNwind As Recordset
Доступ к базам данных из УВА-кода
615
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Dim SQLstr As String
Dim newElement As String, i As Integer
Connectstr = "ODBC;DSN=Test_dbs;UID=;PWD="
' ввести SQL-запрос:
SQLstr = TextBoxl.Text
Set my_wrk = DBEngine.CreateWorkspace("NewODBCDirect" , __ "sa", dbUseODBC)
Set my_cnn = my_wrk.OpenConnection("Test_dbs" , _ dbDriverNoPrompt, False, ConnectStr)
' открыть набор:
Set rstNwind = my_cnn.OpenRecordset(SQLstr, dbOpenDynaset)
rstNwind.MoveLast	' перейти в конец набора для иницализации
Recordcount
If rstNwind.Recordcount > 0 Then
rstNwind.MoveFirst	' перейти к началу набора
' задать количество строк:
MSFlexGridl.Cols = rstNwind.Fields.Count + 1
1 установить ширину первых колонок
MSFlexGridl.ColWidth(0) = 1
If MSFlexGridl.Cols > 1 Then MSFlexGridl.ColWidth(1) = 1500 If MSFlexGridl.Cols > 2 Then MSFlexGridl.ColWidth(2) = 2000
' до конца набора добавлять записи в список Do While Not rstNwind.EOF
«	1 сформировать элемент добавления:
newElement = ""
For i = 0 To rstNwind.Fields.Count - 1 newElement = newElement & vbTab & rstNwind.Fields(i)  Next
1 добавить элемент к таблице:
MSFlexGridl.Additem newElement
rstNwind.MoveNext
Loop
End If
End Sub
Этот пример приведен только для демонстрации использования ODBC-источника данных. Аналогичным образом можно в качестве источника данных ODBC использовать файл в dbf-формате.
Microsoft ADO
Основным методом доступа к разделяемым файлам и базам данных кли-ент/сервер становятся технология ActiveX Data Objects (ADO) и OLE DB, пришедшие на смену прикладному интерфейсу программирования Open Database Connectivity (ODBC). Технология ADO является еще одной моделью доступа к базам данных и представляет собой объектно-ориентированный интерфейс для технологии доступа к данным OLE DB. ADO поддерживает ключевые возможности для построения клиент/серверных и Web-приложений, а также обеспечивает функции Remote Data Service (RDS), посредством которого можно перемещать данные с сер
616
Глава 22
вера в клиентское приложение или на Web-страницу, манипулировать данными «на стороне клиента» и возвращать обновленные данные серверу.
В данном разделе речь пойдет о самой малой части возможностей этой технологии для доступа к базам данных. Для более детального ознакомления с ActiveX Data Objects и OLE DB можно воспользоваться как справочной информацией, так и многочисленными изданиями по разработке баз данных для приложений Windows.
На рис. 22.16 показано окно Object Browser с несколькими первыми членами класса Connection библиотеки ADODB. Обратите внимание на наличие событий в окне Members of'Connection' [Для того чтобы можно было увидеть объекты библиотеки ADODB в окне Object Browser, необходимо в окне References установить ссылку на Microsoft ActiveX Data Object 2.7 Library.]
Рис. 22.16
Окно Object Browser с несколькими первыми членами класса Connection библиотеки ADODB
апопв
obj»c-
AJ
Member
Class
Search Results
| Library? ~~~~~
Classes
° <globals>
iP ADCPROP_ASYNCTHRE^
i/3 ADCPROP_AUTORECAL( ADCPROP-UPDATECRITI ADCPROPJJPDATERES'i AffectEnum
iP BookmarkEnum
ьЬ Command
лЛ CommandTypeEnum
iP ConnectModeEnum
Members nf Connection
ВЗЁ* Attributes
BeymTrans
f BeginTransComplete
Cancel
Close
Э? CommandTimeout CommitTrans
V CommitTransComplete
£ ConnectComplete
aS* Connectionstring
Й? ConnectionTimeout
CursorLocation
Class Connection
Member of
Как видно из модели ADO (рис. 22.17), вместо иерархии объектов здесь имеется независимый набор объектов (и коллекций). Причем объект Error и коллекция Errors, объекты Recordset и Fields (и их коллекции) имеют аналоги и одно и то же назначение в моделях DAO и ADO. Объект ADO Connection соответствует объекту DAO Workspace, а объект ADO Command похож на DAO QueryDef. Однако свойст-
Рис. 22.17
Объекты и коллекции модели ADO
[connection]
-	[ Errors |—| Erroi ~|
_| Properties |—| Property"]
| Command*]
-	) Parameters |—| Parameter]
_| Propertied]—| Property-]
| Recordset]
-	| Fields |—| Field ~|
-	| Properties [—| Property*]
| Record |
L| Fields |—| Field ~]
Stt earn
Доступ к базам данных из УВА-кода
617
ва и методы объектов ADO явно отличаются от свойств и методов соответствующих объектов модели DAO, хотя рассмотренные при изучении модели DAO понятия очень пригодятся при освоении модели ADO.
Объект Connection
Объект Connection — основной объект ADO верхнего уровня. Именно с него начинается подключение к источнику данных, после чего можно использовать связанные с соединением объекты Command или Recordset. Объект Connection имеет следующие свойства1:
Attributes	Определяет использование транзакций и может быть суммой XactAttributeEnum-значений: adXactAbortRetaining (новая транзакция запускается при вызове метода RollbackTrans), adXactCommitRetaining (новая транзакция запускается при вызове метода CommitTrans). Значение по умолчанию равно 0 — поддерживающие транзакции не используются.
Command-Timeout	Определяет время (в секундах), через которое прекращается неуспешное выполнение метода Execute соответствующего объекта Command (тип Long). Значение по умолчанию — 30.
Connection-String	Строка с информацией, необходимой для провайдера2, чтобы открыть соединение с источником данных. Пример: "Provider=MSDASQL;DSN=dsnName;UID=userName; PWD=userPassword;"
Connection-Timeout	Определяет время (в секундах), через которое прекращается неуспешная попытка установки соединения (тип Long).
Cursor-Location	Определяет используемый механизм курсора (элемент базы данных, определяющий «перемещение» по записям) и может быть одним из CursorLocationEnum-значений: adUseClient [курсор на стороне клиента], adUseNone [не использовать механизм курсора], adUseServer [курсор на стороне сервера, значение по умолчанию] (тип Long).
Default-Database	Определяет имя базы данных по умолчанию для объекта Connection, если оно не было указано в Connectionstring, (тип String).
Isolation- Level	Определяет поведение транзакций, которые взаимодействуют с другими одновременно выполняющимися транзакциями, и может быть одним из IsolationLevelEnum-значений: adXactUnspeci-fied [провайдер использует различные уровни транзакции, которые нельзя определить], adXactChaos [транзакция не будет переписывать изменения, выполненные транзакциями более высокого уровня изоляции], adXactBrowse [разрешается чтение незафиксированных изменений в других транзакциях], adXactReadUncom-mitted [то же назначение, что и у adXactBrowse], adXactCursor-Stability [разрешается чтение только зафиксированных изменений в других транзакциях], adXactReadCommitted [то же назначение, что и у adXactCursorStability], adXactRepeatableRead [разрешается чтение изменений в других транзакциях], adXact-Isolated [все транзакции не зависят от других (изолированных) транзакций], adXactSerializable [то же назначение, что и у adXactlsolated] (тип Long).
1 Как и для других объектов, приведены все свойства, несмотря на то, что некоторые из них в этой книге не обсуждаются и не используются.
2 Термин, к которому можно привыкать постепенно, сначала подразумевая под ним «драйвер».
618
Глава 22
Mode	Определяет режим доступа на чтение и запись для объектов Connection, Record или Stream1 и может быть одним из ConnectModeEnum-значений: adModeRead [режим с разрешением только чтения], adModeReadWrite [режим с разрешением чтения и записи], adModeRecursive, adModeShareDenyNone [разрешает другим пользователям открывать соединение с любым режимом доступа], adModeShareDenyRead [запрещает чтение данных другими пользователями], adModeShareDenyWrite [Запрещает другим пользователям открывать соединение с правами на запись], adModeShareExclusive [режим монопольного использования], adModeUnknown [режим по умолчанию; указывает на то, что не установлены никакие разрешения на соединение], adModeWrite [режим с разрешением только записи] (тип Long).
Provider	Строка, указывающая имя провайдера (если он не задан в строке Connectionstring). По умолчанию используется значение MSDASQL (Microsoft OLE DB Provider for ODBC).
State	Указывает состояние соединения: открыто или закрыто. Возвращает значение (типа Long) и может быть одним из ObjectStateEnum-значений: adStateClosed [объект закрыт — значение по умолчанию], adStateOpen [объект открыт], adStateConnecting [объект соединяется], adStateExecuting [вызван метод Execute объекта Connection или Command], adStateFetching [в объект Recordset возвращаются строки].
Version	Указывает номер версии объектной модели ADO (тип String).
Объект Connection имеет следующие методы:
BeginTrans	Запускает транзакцию.
1 Cancel	Отменяет вызов асинхронного метода.
Close	Закрывает открытый объект и любые зависимые объекты.
| CommitTrans	Завершает транзакцию, закрепляя изменения в источнике данных. Разрешает запуск новой транзакции.
I Execute	Выполняет определенный запрос: SQL-инструкцию, хранимую процедуру или текст, определяемый провайдером.
| Open	Открывает соединение с источником данных.
Open Schema	Возвращает информацию о схеме базы данных.
1 RollbackTrans	Отменяет любые изменения, выполненные во время транзакции, и завершает транзакцию (отменяет транзакцию). Разрешает запуск новой транзакции.
Поскольку технология ADO представляет собой объектно-ориентированный интерфейс, объект Connection имеет события, которые полезны для перехвата ошибок, при выполнении асинхронных операций с базами данных и в других случаях. В этой книге не рассматриваются вопросы использования событий при работе с базами данных, а читателю, конечно же, следует изучить эту тему самостоятельно, не дожидаясь следующего издания данной книги.
Для подключения к источнику данных можно использовать метод Open объекта Connection библиотеки ADO. При этом необходимо посредством свойства
1
Представляет поток двоичных или текстовых данных.
Доступ к базам данных из УВА-кода
619
ConnectionString предоставить информацию об источнике в виде строки подключения, подобной строке подключения ODBC. Провайдера данных можно указать также в свойстве Provider. Это должна быть строка с типом провайдера OLE DB для подключения. При использовании провайдера ODBC для OLE DB его можно вообще не указывать, так как он используется по умолчанию. Однако хорошим «тоном» считается указывать провайдера явно.
Строка подключения (свойство ConnectionString) в ADO применяется для подключения к серверу базы данных. При использовании провайдера ODBC для OLE DB строка подключения должна быть точно такой же, как и строка подключения ODBC. Например, в коде листинга 22.5 используется провайдер ODBC для OLE DB. Строка подключения включает только имя источника данных, указанное в диалоговом окне ODBC Microsoft Access Setup в текстовом поле Data Source Name (рис. 22.14).
Листинг 22.5. Открытие ADO-соединения с ODBC-источником
1	Dim cn As ADODB.Connection
2
3	Function ADODB_ConnectedODBC () As Boolean
4	' устанавливает соединение для ODBC
5	Set cn = New ADODB.Connection
6
7	On Error GoTo err_not_connection
8
9	Set cn = New ADODB.Connection
10	cn.Provider = "MSDASQL"
11	cn . ConnectionString	=	" DSN==Test dbs; "
12	cn.Open
13	•
14	ADODB__ConnectedODBC	=	True
15	Exit Function
16
17	err_not_connection:
18	ADODB_ConnectedODBC = False
19
20	End Function
21
22
23	Sub Main_ADODB()
24	' тестирует ADODB_ConnectedODBC
25
26	If ADODB__ConnectedODBC () Then
27	MsgBox	"Похоже,	соединение установлено..."
28
29	1 код,	использующий	установленное соединение:
30	...
31	cn.Close	'	закрыть соединение
32	Else
33	MsgBox	"Что-то	не	сложилось с соединением!"
34
35	' код,	который	не	использует соединение:
36	...
37
38	End If
39
40	End Sub
Функция ADODB_Connected только открывает соединение и возвращает значение константы True, если не возникает ошибка при подключении к источнику данных. Поскольку ошибки при подключении к источникам данных — дело обыч-
620
Глава 22
ное, следует всегда не забывать вставлять в код операторы, реагирующие на возможные отказы для улучшения «отношений» между пользователем и разрабатываемым для него приложением.
Процедура Main_ADODB вызывает функцию ADODB_Connected и выполняет тот или иной код, основываясь на возвращаемом функцией значении. В этой же процедуре открытое соединение закрывается методом Close (строка 31).
Код листинга 22.6 отличается от кода листинга 22.5 только использованием другого провайдера — Microsoft .Jet. OLEDB. 4.0 (строка 11). Имя функции AD0-DB_ConnectedODBC, предназначенной для установления соединения, изменено на ADODB_Connected J et.
Листинг 22.6. Открытие ADO-соединения с использованием Jet-провайдера
1	Dim cn As ADODB.Connection
2
3	Function ADODB_ConnectedJet() As Boolean
4	' устанавливает соединение для Jet-провайдера
5
6	Set cn = New ADODB.Connection
7
8	On Error GoTo err_not_connection
9
10	Set cn = New ADODB.Connection
11	cn.Provider = "Microsoft.Jet.OLEDB.4.0"
12	cn.Connectionstring = "d:\dbs.mdb"
13	cn.Open
14
15	ADODB_ConnectedJet = True
16	Exit Function
17
18	err_not_connection:
19	ADODB_ConnectedJet = False
20
21	End Function
22
23	Sub Test_ADODB_Connected()
24	' тестирует ADODB_Connected: устанавливает соединение и
25	' использует данные из таблицы Товары
26
27 If ADODB_ConnectedJet() Then
28	MsgBox "Похоже, соединение установлено..."
29	' код, использующий установленное соединение:
30
31	Set rs = New ADODB.Recordset
32	rs.CursorType = adOpenDynamic	‘
33	rs.Source = "SELECT * FROM Товары"
34	Set rs.ActiveConnection = cn
35	rs.Open
36
37	MsgBox rs.Fields(1) & "	" & rs.Fields(1).Name & "	" &
rs.Fields(1).Type
38
39	cn.Close ' закрыть соединение
40	Else	,
41	MsgBox " Что-то не сложилось! "
42	End If
43
44	End Sub
ADO-объект Command предназначен для выполнения параметризованных хранимых процедур в виде временных операторов или постоянных SQL-операто-
Доступ к базам данных из УВА-кода
621
ров, предварительно скомпилированных. В данной книге этот объект не рассматривается, но читателю настоятельно рекомендуется ознакомиться с этим объектом и его коллекциями, используя справочную систему. В некоторой степени можно использовать также книги по разработке приложений, связанных с базами данных, в системе программирования Visual Basic.
Одним из наиболее полезных методов (после Open, конечно) объекта Connection является метод Execute/имеющий следующий синтаксис:
^СИНТАКСИС -и... ... . и
невозвращающий набор:
connection.Execute CommandText [, RecordsAffected}
возвращающий набор (объект Recordset):
Set recordset = connection.Execute (CommandText [, RecordsAffectedi)
Аргумент CommandText — строка, содержащая SQL-инструкцию, имя таблицы, хранимой процедуры, URL или текст, определяющий провайдера. Необязательный аргумент RecordsAffected — переменная типа Long, в которую провайдер возвращает число записей, принимающих «участие» в операции.
Пример использования метода Execute приведен далее при рассмотрении объекта Recordset, поскольку именно при помощи этого объекта можно легко увидеть результат выполнения метода Execute.
Объект Recordset
Конечной целью большинства приложений, использующих базы данных, является создание просмотр и обновление наборов записей. ADO-объект Recordset предназначен, как и в модели DAO, для доступа к наборам записей в источнике данных (можно говорить «к информации, предоставляемой провайдером»). ADO-объект Recordset имеет довольно много свойств, методов и событий, которые вряд ли можно освоить одновременно и сразу. Скорее, на их изучение уйдет много времени и этому должна быть посвящена специальная книга. Те же свойства и методы, которые дают понятные и самые необходимые результаты, приведены ниже.
Свойства ADODB.Recortset	
ActiveConnection	Указатель на открытое соединение, которому соответствует объект Recordset.
BOF	При равенстве значению константы True означает то, что указатель записи установлен перед первой записью (строкой) набора и нет текущей записи.
Bookmark	Значение (типа Variant), возвращающее ссылку на определенную запись.
CacheSize	Определяет число записей в локальной памяти (КЭШе) для уменьшения числа обращений к серверу (тип Long).
622
Глава 22
CursorType	Определяет тип курсора набора и может принимать значение одной из CursorTypeEnum-констант: adOpenDynamic [используется динамический курсор; отображаются добавления, изменения и удаления, выполняемые другими пользователями; все типы перемещения по записям набора доступны, за исключением перемещения на закладку, если его не поддерживает провайдер], adOpenForivardOnly [набор с однонаправленным перемещением курсора и записей только для чтения], adOpenKeyset [подобен динамическому курсору, но данные, добавляемые другими пользователями, скрываются, данные, удаляемые другими, недоступны, а изменяемые — остаются видимыми], adOpenStatic [используется статический курсор; статическая копия набора записей для нахождения данных и генерации отчетов; добавления, изменения или удаления данных другими пользователями невидимы]. По умолчанию используется значение константы adOpenForwardOnly (тип Long).
EditMode	Возвращает состояние редактирования набора и может принимать значение одной из EditModeEnum-констант: adEditNone [операции редактирования не выполняются] (значение по умолчанию), adEditlnProgress [текущая запись редактировалась, но не сохранена], adEditAdd [использовался метод AddNew, в буфере копирования находится новая 1 запись, которая не была сохранена в базе данных], adEditDelete [текущая запись была удалена] (тип Long).
EOF	При равенстве значению константы True означает то, что указатель записи установлен за последней записью набора и нет текущей записи.
RecordCount	Возвращает количество записей (тип Long) в объекте Recordset.
Sort	Строка, содержащая SQL-выражение предложения ORDER BY без самих зарезервированных слов и определяющая порядок сортировки записей набора.
Source	Строка, содержащая SQL-инструкцию, имя таблицы, хранимой процедуры или связанного объекта Command.
Методы ADODB.Recortset	
AddNew	Добавляет новую запись к изменяемому набору данных.
Clone	Создает копию объекта Recordset с независимым указателем записи.
Close	Закрывает объект Recordset.
Delete	Удаляет текущую запись из набора.
Find	Ищет записи, удовлетворяющие некоторому критерию.
GetRows	Возвращает двумерный массив (строки и столбцы) записей (тип Variant).
GetString	Возвращает разделяемую табуляцией строку для указанного количества записей.
Move	Перемещает указатель записи с текущей записи.
MoveFirst	Перемещает указатель записи к первой записи.
Доступ к базам данных из УВА-кода
623
MoveLast	Перемещает указатель записи к последней записи.
MoveNext	Перемещает указатель записи к следующей записи.
MovePrevious	Перемещает указатель записи к предыдущей записи
Open	Открывает набор данных активного объекта Connection (или Command).
Save	Создает файл, содержащий копию набора записей.
Update	Применяет результат модификации набора записей.
UpdateBatch	Применяет результат всех модификаций набора записей пакетного типа.	:
Коллекция Field как свойство объекта Recordset
Прежде чем подробно рассмотреть некоторые свойства и методы объекта Recordset, следует отметить коллекцию Fields, которую можно рассматривать как свойство этого объекта. Именно посредством этого свойства можно из кода VBA получить доступ к данным, хранящимся в полях записей. Коллекция Fields имеет одно свойство Count (количество полей набора Recordset) и два метода: Item (указывает определенный элемент коллекции) и Refresh (обновляет объект в коллекции).
Свойства объекта Fields (см. справочную систему) в основном предназначены для чтения, например свойство Name, возвращающее имя поля в наборе, или свойство Туре, возвращающее тип поля. Наиболее часто используется свойство Valua (возвращающее значение поля), которое имеет статус «только для чтения» в наборах данных с последовательным доступом и наборах, открытых с блокировкой «только для чтения».
Далее рассматриваются некоторые свойства и методы объекта Recordset. В листинге 22.7 процедура Test_ADODB_Connected (из листинга 22.5) дополнена строками 10-16 для считывания информации из таблицы Товары. В строке 10 создается объект rs типа Recordset; в строке 11 свойству CursorType объекта rs присваивается значение константы adOpenDynamic. В строке 12 определяется SQL-выражение для указания считываемых полей из источника данных (в этом случае — все поля таблицы Товары). В строке 13 посредством свойства Active-Connection объекта rs назначается открытое соединение сп, а в строке 14 набор rs открывается методом Open.
В строке 16 используется свойство Value объекта rs.Fields(l) — значение второго по порядку поля набора rs. Ключевое слово здесь не указано, так как это свойство применяется по умолчанию. Свойство rs.Fields(l).Name в строке используется для получения наименования второго поля набора, a rs.Fields(l).Type — для типа поля. В строке 18 методом Close соединение сп закрывается.
Листинг 22.7. Открытие ADO-соединения и считывание информации из таблицы базы данных 1 2 3 4 5 6 7 8 9 10 11
1 Sub Test_ADODB_Connected()
2 1 тестирует ADODB_ConnectedODBC: устанавливает соединение и
3 ' использует данные из таблицы Товары
4
5
6 If ADODB_ConnectedODBC() Then
7	MsgBox "Похоже, соединение установлено..."
8	' код, использующий установленное соединение:
9
10	Set rs = New ADODB.Recordset
11	rs.CursorType = adOpenDynamic
624
Глава 22
12	rs.Source = "SELECT * FROM Товары"
13	Set rs.ActiveConnection = cn
14	rs.Open
15
16	MsgBox rs.Fields(l) 4 "	"4 rs.Fields(1).Name 4 "	"4
rs.Fields(1) .Type
17
18	cn.Close ' закрыть соединение	►
19	Else
20	MsgBox "Что-то не сложилось!"
21	End If
22
23	End Sub
Для формы, показанной на рис. 22.5, теперь можно написать код, представленный в листинге 22.8. Процедура CmdLoad._Click для установления соединения при помощи ADO и провайдера для ODBC1 11 использует функцию ADODB_Connected-ODBC.
Листинг 22.8. Открытие ADO-соединения и считывание информации в элемент управления MSFIexGrid
1 Dim cn As ADODB.Connection
2
3
4 Function ADODB_ConnectedODBC() As Boolean
5 1 устанавливает соединение для ODBC
6 Set cn - New ADODB.Connection
7
8 On Error GoTo err_not_connection
9
10 Set cn = New ADODB.Connection
11	cn.Provider = "MSDASQL"
12	cn.Connectionstring = "DSN=Test_dbs;"
13	cn.Open
14 . '
15	ADODB_ConnectedODBC	= True
16	Exit Function
17
18 err_not_connection:
19 ADODB_ConnectedODBC = False
20
21 End Function
22
23	’
24 Private Sub CmdExit_Click()
25 Unload Me
26 End Sub
27
28
29 Private Sub CmdLoad_Click()
30
31 Dim rstNwind As ADODB.Recordset
32 Dim newElement As String, i As Integer
33
34	If Not ADODB_ConnectedODBC() Then
35	MsgBox "Что-то не сложилось!"
36	Exit Sub
37	End If
1 В следующей главе будет использоваться провайдер для SQL Server.
Доступ к базам данных из УВА-кода
625
38
39
40	Set rstNwind = New ADODB.Recordset
41
42	' открыть набор:
43	rstNwind.Open TextBoxl.Text, cn
44
45	rstNwind.MoveFibst	' перейти к началу набора
46
47	' задать количество строк:
48	MSFlexGridl.Cols = rstNwind.Fields.Count + 1
49
50	' установить ширину первых колонок
51	MSFlexGridl.ColWidth(0) = 1
52	If MSFlexGridl.Cols > 1 Then MSFlexGridl.ColWidth(1) = 1500
53	If MSFlexGridl.Cols > 2 Then MSFlexGridl.ColWidth(2) = 2000
54
55	' до конца набора добавлять записи в список
56	Do While Not rstNwind.EOF
57
58	' сформировать элемент добавления:
59	’ newElement = ""
60	For i = 0 To rstNwind.Fields.Count - 1
61	newElement = newElement & vbTab & rstNwind.Fields(i)
62	Next
63
64	' добавить элемент к таблице:
65	MSFlexGridl.Additem newElement
66
67	rstNwind.MoveNext
68	Loop
69
70	End Sub
В отличие от предыдущего примера здесь имеется возможность в качестве свойства Source указать строку, вводимую во время работы приложения в текстовое окно. Как и ранее, в это текстовое окно можно ввести SQL-инструкцию для выбора данных из нескольких таблиц для определенных записей.
В строке 43 записан оператор для открытия набора rstNwind:
rstNwind.Open TextBoxl.Text, cn
Ранее вместо этого использовались операторы, подобные следующим:
rstNwind.Source = TextBoxl.Text
Set rstNwind.ActiveConnection = cn
rstNwind.Open
Для примера использования метода Execute объекта Connection добавим к форме, которая приведена на рис. 22.5, текстовую строку и кнопку с наименованием «Выполнить инструкцию» (рис. 22.18).
Событийная процедура кнопки «Выполнить инструкцию» содержит всего один оператор (кроме заголовка и оператора окончания процедуры):
Private Sub CommandButtonl_Click() cn.Execute TextBox2.Text
End Sub
Таким образом, эта процедура использует содержимое текстового окна Text-Вох2 в качестве аргумента CommandText метода Execute и выполняет этот метод для соединения сп. Конечно, необходимо предусмотреть обработчик ошибок в этой процедуре, так как пользователь может ввести неверную инструкцию, но сейчас это не очень важно.
626
Г лава 22
Рис. 22.18 Форма для тестирования приложения с использованием метода Execute объекта Connection в режиме разработки
Для тестирования приложения следует выполнить:
	запустить приложение;
	в окне SQL-запрос ввести строку "Товары";
	щелкнуть кнопку Загрузить список;
	ввести в нижнем окне SQL-инструкцию
INSERT INTO Товары (КодТовара, НаименованиеТовара) VALUES ('1','Совсем новый товар1)
	щелкнуть кнопку Выполнить инструкцию;
	щелкнуть кнопку Загрузить список;
Если все сделать так, как указано, в окне списка Список товаров можно будет увидеть новый товар (рис. 22.19).
Рис. 22.19 Форма для тестирования приложения с использованием метода Execute объекта Connection в режиме выполнения
Далее можно вводить любые релевантные SQL-инструкции, например
DELETE FROM Товары WHERE КодТовара»'1 '
Эта инструкция удалит запись, которая содержит в поле КодТовара значение "1".
Добавлять записи в набор можно не только SQL-инструкцией для метода Connection.Execute. Это позволяет сделать метод AddNew объекта Recordset, который имеет следующий синтаксис:
Доступ к базам данных из VBA-кода
627
СИНТАКСИС
recordset.AddNew [FieldList] [, Values]
Необязательный аргумент FieldList — одно имя, массив имен или порядковых номеров полей в новой записи. Необязательный аргумент Values — одно значение или массив для полей в новой записи. Если Fieldlist — массив, Values должен быть тоже массивом с тем же самым количеством элементов. Обычно аргументы этого метода не используются. Чаще всего метод применяется для добавления пустой записи, а затем запись редактируется, как в следующем примере.
Изменим форму, приведенную на рис. 22.19: вместо текстового окна и кнопки в нижней части формы поместим на форму текстовые окна и кнопку для ввода данных, как показано на рис. 22.20. При этом таблица со свойствами элементов управления формы будет иметь следующий вид:
Тип элемента	Свойство, которое изменено (используется в коде)	Значение	Примечание
UserForm	Name	UserForm 1	Имя главной формы, на которое можно ссылаться в коде.
Frame	Name	Framel	Имя, на которое можно ссылаться в коде.
	Caption	Список товаров	Текст - заголовок.
MSFlexGrid	Name	MSFlexGridl	Имя, на которое можно ссылаться в коде.
CommandButton	Name	CmdLoad	
	Caption	Загрузить список	Заголовок для кнопки.
CommandButton	Name	CmdExit	
	Caption	Выход	Заголовок для кнопки.
	Cancel	True	Клавиша Esc также вызовет процедуру CmdExit_Click.
Label	Name	Labell	Метка для TextBoxl.
TextBox	Name	TextBox1	Текстовое окно для ввода строки с SQL-запросом.
Frame	Name	Frame2	Имя, на которое можно ссылаться в коде.
	Caption	Добавление записи	Текст - заголовок.
Label	Name	Label2	Метка для TextBox2.
Label	Name	Lab el 3	Метка для TextBox3.
Label	Name	Label4	Метка для TextBox4.
TextBox	Name	TextBox2	Текстовое окно для ввода кода товара.
TextBox	Name	TextBox3	Текстовое окно для ввода наименования товара.
628
Глава 22
Тип элемента	Свойство, которое изменено (используется в коде)	Значение	Примечание
TextBox	Name	TextBox4	Текстовое окно для ввода цены товара.
CommandButton	Name	CmdAdd	Кнопка для добавления записи.
	Caption	Добавить	Заголовок кнопки.
Рис. 22.20
Форма для тестирования приложения с использованием метода AddNew объекта Recordset в режиме разработки
В листинге 22.9 приведен код модуля формы, которая отображена на рис. 22.20. В строках 81-93 описана событийная процедура CmdAdd_Click, которая добавляет к набору новую (пустую) запись (строка 84), а затем, используя содержимое текстовых окон TextBox2, TextBox3 и TextBox4, изменяет содержимое полей этой записи (строки 87-89). Код строки 91 добавляет запись в базу данных.
Листинг 22.9. Добавление данных в таблицу, отображаемую в объект Recordset
1	Dim cn As ADODB.Connection
2	Dim rstNwind As ADODB.Recordset
3
4	Function ADODB_ConnectedJet () As Boolean	'i
5	' устанавливает соединение для Jet-провайдера
6
7	Set cn = New ADODB.Connection
8	/
9	On Error GoTo err_not_connection
10
11	Set cn = New ADODB.Connection
12	cn.Provider = "Microsoft.Jet.OLEDB.4.0"
13	cn.Connectionstring = "d:\dbs.mdb"
14	cn.Open
15
16	ADODB_ConnectedJet	= True
17	Exit Function
18
19	err_not_connection:
20	ADODB_ConnectedJet = False
Доступ к базам данных из VBA-кода
629
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
End Function
Private Sub CmdExitClick()
rstNwind.Close
cn.Close »
Unload Me
End Sub	<
Private Sub CmdLoad_Click() ' загрузка списка записями набора
Dim newElement As String, i As Integer
If Not ADODB_ConnectedJet() Then MsgBox "Что-то не сложилось!" Exit Sub
End If
Set rstNwind = New ADODB.Recordset
rstNwind.Source = TextBoxl.Text rstNwind.LockType = adLockOptimistic
Set rstNwind.ActiveConnection = cn rstNwind.Open
' открыть набор:
1 rstNwind.Open TextBoxl.Text, cn
rstNwind.MoveFirst ' перейти к началу набора
' задать количество строк:
MSFlexGridl.Cols = rstNwind.Fields.Count + 1
' установить ширину первых колонок MSFlexGridl.ColWidth(0) = 1
If MSFlexGridl.Cols > 1 Then MSFlexGridl.ColWidth(1) = 2500 If MSFlexGridl.Cols > 2 Then MSFlexGridl.ColWidth(2) = 2000 ' до конца набора добавлять записи в список Do While Not rstNwind.EOF
' сформировать элемент добавления: newElement = ""
For i = 0 To rstNwind.Fields.Count - 1 newElement = newElement & vbTab & rstNwind.Fields(i)
Next
' добавить элемент к таблице: MSFlexGridl.Additem newElement
rstNwind.MoveNext
Loop
End Sub
Private Sub CmdAdd_Click()
' добавление записи (без проверки уникальности кода)
630
Глава 22
84 rstNwind AddNew ' добавить пустую запись в набор
85
86	' редактирование данных в добавленной записи
87	rstNwind	Fields(0)	-	TextBox2.Text
88	rstNwind	Fields(1)	=	TextBox3 Text
89	rstNwind	Fields(2)	=	TextBox4 Text
90
91 rstNwind Update ' сохранить запись	*
92
93 End Sub
Одним из наиболее «интересных» методов объекта ADODB.Recordset являет ся метод Save, который записывает данные набора в файл и имеет следующий синтаксис:
СИНТАКСИС
recordset Save FileName, PersistFormat
Здесь FileName — полное имя файла для записи, PersistFormat — значение константы, определяющей формат файла: adPersistADTG (является значени ем по умолчанию и указывает на формат, являющийся собственностью Advanced Data Tablegram) или adPersistXML (XML-формат).
Далее рассматривается пример использования метода Save объекта ADODB.Re-cordset. Для этого предлагается создать диалоговое окно на базе формы, представленной на рис. 22.21. В следующей ниже таблице описаны некоторые свойства элементов управления формы.
Рис. 22.21
Форма для тестирования приложения с использованием методов ASave и Open объекта Recordset в режиме разработки
Тип элемента	Свойство, которое изменено (используется в коде)	Значение	Примечание
UserForm	Name	UserForm2	Имя главной формы, на которое можно ссылаться в коде.
	Caption	Тестирование Recorset.Save	
ListBox	Name	ListBoxl	Окно для отображения списка.
CommandButton	Name	CmdLoad	Имя кнопки.
Доступ к базам данных из УВА-кода
631
Тип элемента	Свойство, которое изменено (используется в коде)	Значение	Примечание
	Caption	Запись в файл	Заголовок для кнопки.
CommandButton	Name	CmdClear	Имя кнопки.
	Caption	Очистить список	Заголовок для кнопки.
CommandButton	Name	CmdRead	Имя кнопки.
	Caption	Чтение из файла	Заголовок для кнопки.
CommandButton	Name	CmdExit	Имя кнопки.
	Caption	Выход	Заголовок для кнопки.
	Cancel	True	Клавиша Esc также вызовет процедуру CmdExit Click.
Label 1	Name	Label 1	
	Caption	Структура базы d:\dbs.mdb	
В листинге 22.10 представлен код модуля формы. Алгоритм работы с формой очень простой: при щелчке на кнопке Запись в файл посредством кода процедуры CmdLoad_Click (27-54) создается набор rstNwind в результате вызова метода OpenSchema объекта сп типа Connection (строка 38). После создания его записи помещаются (строки 42-54) в список (рис. 22.22) и сохраняются в XML-файле c:\rstNwindSave.xml (строка 49) методом Save. Набор rstNwind и соединение сп закрываются (строки 58, 59).
	Листинг 22.10. Использование методов Save и Open объекта Recordset
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24	Dim cn As ADODB.Connection Function ADODB_ConnectedJet() As Boolean ' устанавливает соединение для Jet-провайдера Set cn = New ADODB.Connection On Error GoTo err_not_connection Set cn = New ADODB.Connection cn.Provider = "Microsoft.Jet.OLEDB.4.0"	’	' cn.Connectionstring = "d:\dbs.mdb" cn.Open ADODB_ConnectedJet = True Exit Function err_not_connection: ADODB_ConnectedJet = False End Function Private Sub CmdExit__Click () Unload Me
632
Глава 22
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44.
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
End Sub	i
Private Sub CmdLoad_Click()
Dim rstNwind As ADODB.Recordset
Dim newElement As String, i As Integer
If Not ADODB_ConnectedJet() Then	*
MsgBox "Что-то не сложилось!" Exit Sub
End If
' открытие набора с данными о структуре базы данных: Set rstNwind = cn.OpenSchema(adSchemaTables)
' добавление элементов набора в список: Do Until rstNwind.EOF
ListBoxl.Additem "Table name: " S _ rstNwind!TABLE_NAME S vbCr S _ "Table type: " S rstNwind!TABLE_TYPE 4 vbCr rstNwind.MoveNext
Loop
' запись набора в файл: rstNwind.Save "c:\rstNwindSave.xml", adPersistXML
rstNwind.Close ’ закрыть набор cn.Close	' закрыть соединение
End Sub
Private Sub CmdRead_Click() ' чтение набора из файла
Dim rstNwind As New ADODB.Recordset
Dim newElement As String, i As Integer
' открытие набора с данными о структуре базы данных: rstNwind.Open "с:\rstNwindSave.xml"
' добавление элементов набора в список:
Do Until rstNwind.EOF
ListBoxl.Additem "Table name: " & _ rstNwind!TABLE_NAME & vbCr & _ "Table type: " & rstNwind!TABLE_TYPE & vbCr rstNwind.MoveNext
Loop
rstNwind.Close ' закрыть набор
End Sub	, ,
Private Sub CmdClear_Click()	f
ListBoxl.Clear
End Sub
Доступ к базам данных из УВА-кода
633
Рис. 22.22
Форма для тестирования приложения с использованием методов ASave и Open объекта Recordset в режиме выполнения
Тестирование Recorset.Save ,
Структура базы d \dbs mdb
< Table name MSysAccessObjectsDTable type ACCESS TABLED Table name MSysAccessXMLDTable type ACCESS TABLED Table name MSysACEsDTable type SYSTEM TABLED Table name MSysObjects^Table type SYSTEM TABLED Tbble name MSysQuenesDTable type SYSTEM TABLED
j Table name MSysRelatlonshipsDTable type SYSTEM TABLED Table name 3anpoclDTable type VIEWD
« Table name ЗапросHDTable type VIEWD
Запись в файл
Очистить список
Выход
После загрузки набора в окно списка и файл можно щелкнуть*на кнопке Очистить список для удаления элементов из списка процедурой CmdClear_Click (строки 80-82). В этот момент приложение никак не связано с базой данных, а в файле c:\rstNwindSave.xml хранятся записи ранее используемого набора. На рис. 22.23 часть этого файла показана при помощи приложения Internet Explorer.
Рис. 22.23
Так выглядит файл С \rstNwindSave xml в приложении Internet Explorer после записи с использованием методов ASave и Open объекта Recordset
Seai ch Favorites Media
-
1C VstNwridSave xinl
low TABU? НАНЕ- КонтрКАгеитьГ TABLE ГУРЕ - TABLE"
ПАН- < SEATED 2ОО2-11-21ТОО:2О:22 DATE- I1ODLI1ED 2003-03-12Т21:26:49 /
- rm И ABIE ПАНЬ НаклЗаголовки 1МЧ1 ПРЬ- TABLE
LATE: CREATED- 2002-11-21Т00 48’42 ГАТЕ	2002-
12-17T01:58.47 /
/ iov TADir.HAHE- НаклСпецификации TABLE.JI ffl TABLE DAIIJKIAIID 2002-ll-21T00:25:20 DAI LJIO01T (Lb- 2002-12-17T02:01’41 /
z ro ' TABLE ПАНГ- Склады TABLE TYTC- TABLE
DAIL MAUD- 2002-ll-17T07:23’18 DAU IKDIHID 2002-12-10T09:21 13 / z row TABLE HAHI - Товары (ABIE ПИ TABLE
DATE ( REAIED- 2002-11-17T07.24’27 DA|l I1<*DIHED 2002-
12-10T09:21:21 /
I I Кг»
!	/>1111
Done	My Computer
Теперь можно щелкнуть на кнопке Чтение из файла. Процедура CmdRe-ad_Click (строки 64-85) откроет набор rstNwind (но уже с использованием в качестве источника файла c:\rstNwindSave.xml) и заполнит окно списка.
В этой главе представлена очень малая часть информации о доступе к базам данных из УВА-кода. Заканчиваем главу с надеждой на будущую возможность посвятить этим вопросам гораздо больше времени и книжных страниц.
Глсва 23
Работа с SQL Server
Как отмечалось в главе 20, «Введение в базы данных», если вы являетесь зарегистрированным пользователем SQL Server, то при помощи Excel-мастера подключения внешних данных и наличии у вас соответствующих полномочий вы можете загрузить в Excel данные из базы, расположенной на SQL Server. В этой главе рассматриваются вопросы, связанные с использованием SQL Server, как обычной сетевой СУБД, к которой вы можете обращаться-посредством своего собственного кода на языке Visual Basic.
Рассмотрим некоторые положения, связанные с наиболее популярной реляционной системой управления базами данных типа клиент/сервер SQL Server (впрочем, это относится ко всем клиент/серверным СУБД). На следующем рисунке (подготовлен в Microsoft Visio 2000) представлена компьютерная сеть, состоящая из сервера и трех персональных компьютеров, которые связаны с сервером. В реальной ситуации персональных компьютеров может быть довольно много. Сервер также может быть не один как по количеству, так и по типу. Здесь имеется в виду SQL Server. Причем термины «клиент» и «сервер» относятся и программному, и к аппаратному обеспечению. Программное обеспечение сервера базы данных обрабатывает запросы, инициализируемые программным обеспечением клиента, посылая результат обработки запросов клиенту.
Рис. 23.1
Компьютерная сеть, состоящая из сервера и трех персональных компьютеров
Программное обеспечение клиента «подсоединяется» к программному обеспечению сервера, делает запрос, получает результат и обрабатывает его, возможно, выводя на экран некоторые из полученных данных. Одним из хороших примеров программного обеспечения клиентской части может служить Microsoft Access, хотя, на самом деле, с использованием языка VBA и драйверов ODBC к SQL Server может «достучаться» любое приложение Microsoft.
На компьютере сервера запускается программное обеспечение сервера базы данных SQL Server. Программное обеспечение клиента базы данных SQL Server
Работа с SQL Server
635
может быть также запущено с компьютера сервера. На следующем рисунке показано взаимодействие программного обеспечения сервера и клиентов. Компьютер клиента, работающий под управлением какой-либо ОС (Windows 95/98, 2000, Windows NT Server, Windows NT Workstation, Windows 3.1 или MS-DOS), запускает клиентское приложение SQL Server. Это приложение посылает запросы на SQL Server, принадлежащий компьютеру сервера, который работает под управлением ОС Windows 95/98, 2000, Windows NT Server, или Windows NT Workstation и запускает все типы приложений, включая приложение клиента и сервера.
Рис. 23.2
Взаимодействие программного обеспечения сервера и клиентов
Computer
Клиентское приложение SQL-Server
SQL Server
Пользователей базы данных, которая обслуживается сервером, может быть много. Данные в базе могут быть в целях сохранности и безопасности закрыты частично или полностью (по крайней мере, для обновления) от различных категорий пользователей. Для этого в SQL Server имеются соответствующие механизмы, в том числе так называемые представления и хранимые процедуры, которые, как и таблицы базы данных, могут быть доступны или недоступны определенным группам пользователей. Представления — это своеобразные фильтры, отображающие данные базы. Клиенту можно вообще закрыть всякий доступ к самим таблицам базы и разрешить доступ только посредством представлений. С помощью таких фильтров можно скрыть некоторые данные от клиента. Хранимые процедуры являются программами, которые работают на сервере и вызываются либо приложением клиента, либо правилами, поддерживающими целостность данных, или триггерами. Хранимые процедуры применяют в работе мощные аппаратные решения SQL Server и обеспечивают высокую производительность при обработке данных. Как представления, так и хранимые процедуры пишутся на одном из диалектов языка SQL.
Менеджер, работающий с клиентским приложением, должен знать параметры доступа к данным (логическое имя и пароль, зарегистрированные на сервере администратором), которые доступны ему, согласно его функциональным обязанностям. Если менеджеру необходимы дополнительные способы обработки данных, он может обратиться либо к разработчику клиентской, либо разработчику серверной части СУБД.
636
Глава 23
Для приобретения навыков работы с SQL Server ее можно установить на от-, дельный персональный компьютер, создать собственную базу данных и написать для нее клиентское приложение.
Зачем пользователю, освоившему VBA для Excel или Word, необходимо научиться работать с SQL Server? Представьте такую ситуацию. Ваша фирма приобрела или уже давно использует вычислительную сеть, в которой некоторые данные хранятся на SQL Server. Сервер обслуживают очень грамотнее и недоступные специалисты, с которыми не так просто установить контакт, особенно, если они работают не на вашей фирме, а выполняют работу по договору. Вы трудитесь на своем компьютере, который при помощи достаточно громоздкой системы управления базой данных «добывает» данные в той форме, какая была предусмотрена при разработке СУБД (назовем ее для важности «большая» СУБД).
По мере вашего роста как специалиста (допустим, вы — менеджер или работаете как программист в помощь менеджеру) у вас появилась потребность не только извлечь некоторые данные из базы, но и представить (или даже предварительно переработать!) их так, как не было предусмотрено при разработке «большой» СУБД. Хотя в данный момент времени вы можете не достаточно четко представлять, в какой форме вам нужно получить отчет по тем или иным данным.
Какое решение имеет эта гипотетическая проблема? Ответ — очень простое! Необходимо поставить задачу «программисту со стороны серверной части» (если у вас нет доступа к отдельным таблицам всей базы) по извлечению необходимых вам данных, получение же этих данных, их обработку и формирование соответствующих отчетных форм вы можете осуществить, «не покидая» привычный вам Microsoft Office.
Если же эта книга попадет в руки начинающему программировать системы управления базами данных при помощи продуктов Microsoft, то эта глава может дать ему некоторые начальные знания по SQL Server, которые пробудят у читателя желание серьезно заняться изучением и применением SQL Server. Начинать работать с SQL Server можно на своем домашнем компьютере, так как версия SQL Server 7.0 (Desktop) предназначена для систем Windows NT и (что более радостно) Windows 95/98 (конечно же, пока еще большинство домашних компьютеров работают под управлением этой системы). Здесь будут рассмотрены задачи построения программ как «со стороны клиента», так и «со стороны сервера». Даже если вы не собираетесь программировать серверные части приложений, знать о том, что это не так уж и сложно (конечно, речь — о простых приложениях), все равно полезно. Вообще, специалист в любой области не должен быть очень «узким», в этом случае ему трудно бывает общаться со специалистом «узким» в другой области, если вдруг им необходимо участвовать в совместной работе. Если вы наотрез отказываетесь программировать с использованием SQL Server, то поймите эту «кухню» хотя бы для того, чтобы грамотно объяснить «серверным» программистам, что вы от них хотите получить. А, вообще-то, если вы еще не поняли, SQL Server здесь «ни причем». Работать из Microsoft Office можно, практически, с любыми системами баз данных. Просто именно сейчас и именно для этой книги в качестве примера было удобнее выбрать SQL Server, тем более, что это — не самая плохая система; скорее — наоборот. Если вы серьезно решили (или это решили за вас) заниматься разработкой баз данных, то можете не задумываться над тем, с чего начать. Устанавливайте на компьютер и начинайте изучать самую современную и одну из мощнейших систем управления базами данных. Она вполне подойдет как для работы на отдельном компьютере, так и в сети — локальной и всемирной.
f
Установить SQL Server на компьютер очень просто
Установка Desktop-версии SQL Server на локальный компьютер не труднее установки программы WinZip и ей подобных. При этом термин «локальный» совсем не означает, что вы не можете установить SQL Server на компьютер, работающий
Работа с SQL Server
637
в сети. Было бы даже очень неплохо, если бы вы, имея дома сеть (хотя бы из двух компьютеров), установили SQL Server на один из компьютеров (под Windows 98), азатем «пользовали» его с другого удаленного на всю длину квартиры (или многоквартирного дома) компьютера. Как и при установке многих других продуктов, диалоговые окна, сопровождающие установку, часто не похожи. Но поскольку в данном случае процесс установки не представляет никаких трудностей, не будем подробно на нем останавливаться. При возникновении у вас каких-либо проблем, используйте литературу, специально посвященную SQL Server, например, книгу Тихомирова Ю.В. «Microsoft SQL Server 7.0 — СПб.: БХВ — Санкт-Петербург, 2000».
Базы данных в SQL Server
Данные в SQL Server хранятся в базах данных. Физическая реализация базы представляет собой несколько файлов на диске, хотя от пользователя данных этот факт скрыт (если пользователь с этим согласен). В SQL Server, кроме пользовательских, имеются несколько встроенных (системных) баз, одними из которых являются master, model, tempdb и msdb. На рис. 23.3 с помощью утилиты SQLServer Enterprise Manager показан состав баз данных SQL Server до того, как пользователь создал свою первую базу. Если при установке указать использование баз-примеров, то в качестве пользовательских можно увидеть и другие базы.

Рис. 23.3
Системные базы данных SQL Server
7 ..... ТЧМШЖД—Х]
Retort Mew Jools
fr» ч ®|ra * x i* q i (5
fe(r  I .» О Ж Й
4 Hems
____I Console Foot
Ь Microsoft 5QL Servers
F, SQL Server Group
Г- gg VOVA. (Windows Э5/Э8) г-
♦ U master
Л (j model
+ msdb
T tempdb
й- Г1 Data Transformation
I Management
4, 1 Security
+  | Support Services
Ll........................ J	2J
master
msdb
Как системные, так и пользовательские базы данных в SQL Server располагаются в различных объектах, к основным из которых относятся (рис. 23.4):
	Таблицы (Tables)
	Представления (Views)
» Хранимые процедуры (Stored Procedures)
	Расширенные хранимые процедуры (Extended Stored Procedures)
	Пользователи (Users)
 Роли (Roles)
» Правила (Rules)
» Умолчания (Defaults)
» Типы данных, определенные пользователем (User Defined Data Types)
» Диаграммы базы данных (Database diagrams)
638
Глава 23
Рис. 23.4
Основные объекты базы данных в SQL Server
ЯГ SQL Server Enterprise Manager - (Сотой RootXMicrosoft SQL Se... BOE3
. Console Window (Help s I £dron View Tools
' 4	.
1 itpm
[SQL Server Gtoupj
___J Lonj.ole Root
I liuosoft SQL Servers
- ,J-~———
- ВЛАДИМИР (Windows 95/98)
-	1 Databases
- (J master □ Tables dxf1 Views S Stored Procedures
Extended Stored ocedures Users
Roles
D Rules f””l Defaults C User Defined Data Types
+ tJ model
+ msdb
+ [J tempdb
* Data Transformation Services i+	।	Management
+ ____|	Security
*	I	Support Services
ВЛАДИМИР (Windows 95/98)
Таблицы базы данных являются местом хранения бизнес-данных, организованных на этапе проектирования базы в логически связанные между собой двумерные таблицы.
Представление — это способ получения данных из базы, результатом которого является (виртуальная) таблица, полученная из (возможно) многих таблиц базы данных. Представление позволяет, кроме защиты данных, представлять данные по-разному для разных пользователей.
Хранимая процедура — это подпрограмма, работающая на сервере. Одним из результатов работы хранимой процедуры может быть возвращение таблицы подобно тому, как это делает представление. Как и обычная подпрограмма, хранимая процедура может принимать аргументы.
Пользователи — это объекты, которые содержат имена, пароли и другие атрибуты, представляющие пользователей базы данных.
Роли — это именованный набор прав в рамках сервера или конкретной базы данных.
Правила — это механизм контроля данных при вводе их в базу. Правила позволяют поддерживать порядок работы, принятый в организации, эксплуатирующей базу данных.
Умолчания используются для заполнения незаданных полей таблицы при вставках новых записей. Например, вы можете не знать цены на товар, который хотите зарегистрировать заранее. В этом случае можно для поля цены задать нулевое значение по умолчанию и не использовать код для выполнения этой операции, поскольку она будет автоматически выполнена сервером.
Пользователи SQL Server могут на основе существующих определять собственные типы данных, называемые типы данных, определенные пользователем.
Диаграммы базы данных создаются при помощи утилиты SQL Server Enterprise Manager в диалоговом режиме и позволяют просматривать таблицы базы данных и связи между ними, выполнять модификацию структуры и состав объектов базы данных.
Работа с SQL Server
639
Основные этапы работы с SQL Server
Работа с SQL Server состоит из непосредственной работы на сервере и написании программного обеспечения так называемой клиентской части, которая будет создавать запросы (обычно с посредством пользовательского интерфейса) для сервера и принимать и представлять полученную информацию.
Основные этапы работы непосредственно с сервером можно выполнить при помощи утилиты SQL Server Enterprise Manager или языка T-SQL. Они состоят из:
	создания базы (или нескольких) данных — набор таблиц;
	написания представлений и хранимых процедур для обработки данных на сервере;
	установления прав доступа для каждого элемента базы данных.
Основная работа, связанная с построением клиентской части, состоит из создания интерфейса и написания программ для взаимодействия с серверной частью.
Создание базы данных при помощи Server Enterprise Manager
Конечно, в больших коллективных системах управления базами данных созданием новых баз занимается только администратор, но, вряд ли, ему придется читать данную книгу. И поскольку это издание предназначено для начинающего разработчика баз данных, то ему на своем персональном компьютере можно делать все, что душе угодно, т.е. во много раз больше, чем может позволить себе многоопытный и ответственный администратор баз данных.
Создание базы — обычный процесс (конечно, без учета этапа проектирования) описания таблиц и их взаимных связей — в данном случае выполняется, как и во многих других СУБД. При этом можно воспользоваться теми таблицами, которые вы, быть может, ранее применяли в других системах, например, Microsoft Visual FoxPro, Paradox (начиная с версии III), dBase (версии Ш-IV), Microsoft Access и Excel и просто текстовые файлы. С вновь созданной базой при помощи утилиты SQL Server Enterprise Manager можно работать таким же образом, как во многих других оболочках систем управления базами данных. Эта утилита может быть использована почти для всех административных операций с локальными или удаленными базами данных.
Для работы с SQL Server Enterprise Manager сначала следует запустить SQL Server Service Manager и щелкнуть на кнопке Start/Continue (рис. 23.5). Теперь можно загрузить Server Enterprise Manager.
Рис. 23.5
Для работы с SQL Server Enterprise Manager сначала следует запустить SQL Server Service Manager
|fcSQL Seivei Sei vic* Мопдце»
Services. [н-.-.QLuer/er
Г” Ли(о itart j-ervice when OS starts
\W0VA MOSQLSeivei Running
Далее щелкните правой кнопкой мыши на компоненте Databases в окне SQL Server Service Manager и из контекстного меню выберите New Database (рис. 23.6).
640
Глава 23
Рис. 23.6
Для создания новой базы данных щелкните правой кнопкой мыши на компоненте Databases в окне SQL
Server Service Manager и из контекстного меню выберите New
Database
Tif Console RootVMicrecaft SQL ServerslSQL Serve* GrocjpWll..
j v/jCton View Joo!5 <<“ ly ryA » 0 iC C8
4 Rems
...,1 Console Root
i-д Microsoft SQL Servers
- <J SQL Server Group
“ gg VOVA [Windows Э5/ЭВ)
master
♦ < I Data Tran New Database
i J Manageme
+ ц I Security ..+ Support Se
AB Tasks
View
..New jwndow fiurn here
Refresh
В текстовом окне Name диалогового окна Database Properties введите новое имя базы данных, например, УчетТоваров, как на рис. 23.7. Теперь можно щелкать на кнопке ОК, в результате чего вы сразу увидите, что значок новой базы данных отображается в окне SQL Server (рис. 23.8).
Рис. 23.7
Диалоговое окно Database Properties для создания новой базы данных
Рис. 23.8
Значок новой базы данных в окне SQL
Server Enterprise Manager
Consol* RootVMicrosoft SQL S«rv«is\SQL	6niu^\VHV		ТТ5Г1
ficton Vew look О l (tj ® > * (3 C? i±._^0JjC3 7 Items		
	| Console Root Microsoft SQL Servers H SQL ^wvef Group	/ a gg VOVA (Windows 95/98J + jESESSSI + I Data Transformation Services j- О Management	< + и Security + 2j Support Services	d tempdb d	J УчетТоваров	Vj	
Dore
Работа с SQL Server
641
Создать в базе данных таблицу не сложнее, чем — базу данных. Щелкните правой кнопкой мыши на имени базы в окне SQL Server Enterprise Manager и в контекстном меню выберите сначала New, а затем — Table (рис. 23.9).
Рис. 23.9
Создать в базе данных таблицу не сложнее, чем базу данных
7b Console RootVMicrosoft SQL SawrtVSQL Swvar EhoupWOVA (Windows Э5... НЙ
Action View £ools Ф5 ftT| Q7[ Й* Q CP фсз
On Dias
ГП ТаЫИ Viev\ Store
(f? User Role A
E3 Rule
□ Oefc C User &• 2J Data Transit It,   } Managemen +	I Security —
New Database
JMew
All Tasks
View
New window horn here
delete
Refresh
Properties
Help
ineral
Tables & Indexes
Database User
Database Rgle
Database Diagran)
Tabb.
View
Stored Procedure
rdf- A
Ryle
Default
User Defined Data Txpe
Publication
Pull Subscription
Spa_^j
В окне Choose Name (рис. 23.10) введите имя таблицы, например, Товары. Теперь вам ничто не мешает описать каждое поле таблицы подобно тому, как это делается в Microsoft Access, но с немного другими типами данных для полей (рис. 23.11).
По окончании формирования таблицы щелкните на значке, расположенном слева от меню Console, и выберите из появляющегося меню команду Close. В дальнейшем вы всегда можете редактировать таблицу, выбрав ее из иерархического меню, щелкнув правой кнопкой мыши на значке таблицы и выбрав из контекстного меню Design Table, как показано на рис. 23.12.
Рис. 23.10. В окне Choose Name введите имя таблицы
21 Программирование на VBA 2002
642
Глава 23
Рис. 23.11
Описание структуры таблицы в SQL Server
>^2:НешТаЫет'ЦчетТоварое‘оп VOVA'	_________ jBISEij
й c
	Column Name	| Datatype	| Length | Precision | Scale	Allow Nul *|
	КодТовар	char	12	0	0	
»	НаименованиеТовара	char	50	0	0	
	ЦенаОптовая	топе/	8	19	4	
7“	ЦенаРозничная	money	19	4	
Рис. 23.12
В дальнейшем вы всегда можете редактировать таблицу, выполнив команду
Design Table
ТЬ Consol* RoolKMicrosolt SUL Servois\SUL Soivm GroupWUVA (Wrufom
Action yiew Tool* <=>
& о ® ca
- .J '-НетТоБаров ZZj Diagrams Zj Table;
6тГ views
Stored Procedures
Users
^2 Roles И Rules ГП Defaults
User Defined Data Types
+	1	Data Transformation Services
+i	I	Management
+	1	Security
ZJ sysindexkeys Zj sysmembers ZJ sysobiects ZJ syspermissions ZJ sysprotects ZJ sysreferences ZJ systypes ZJ sysusers
Hew Table
Design Table
Open Table
Own₽r Ж1
dbo dbo dbo dbo dbo dbo dbo dbo
dbo
Full T ext Index Table
“II Tasks Copy Delete R ei юте
Properties
Создать таблицу в вашей базе на SQL Server можно и по-другому: просто импортировав ее из любой ранее созданной базы данных. Это может быть основным способом создания таблиц, если вы, например, решите все свои разработки по базам данных в других СУБД перенести на SQL Server. На рис. 23.13 показано, как
Рис. 23.13
Из контекстного меню выбрать операцию импорта таблицы
Contote Ro<rt\Micrw*«fl SQL S«vm«\SQL Ssivm br«j*WUVA (Wm4wt
Action 2ew Tools
New Datafca*©
New
Import Data.
C? □ Й>
General
AITasfes;
New window from here
Relate
Relie$t
Pipperliet
--------1..T"UPt<j User
. i Data Transfo
. I Management
1 Security
I Support Serv-es
Export Data
Maintenance Pla i Generate SQL Scitph
Backup Database Restore Database Truncate Log
Shirk Datable
p-v Ftepbsiuti£unfli f$
x »о ®ca
Tables & Indexes Space Allocated
УчетТоваров
Database
ase properties database did yr am
shrink database
import data
	
owner	sa
Date	1003 03
created	1 b 35 3u
Size	2M0
Space	0 66MB
available	
Database	d
Работа с SQL Server
643
из контекстного меню выбрать операцию импорта таблицы. После выбора вами Import Data вас «окружит своей заботой» соответствующий «помощник» и перепись таблицы из баз многих форматов покажется вам приятным занятием.
В главе 20, «Введение в базы данных», рассмотрен процесс создания базы данных для учета движения товаров на складе. Было бы полезно такую базу поместить на SQL Server, чтобы ее данными имели возможность пользоваться сразу несколько менеджеров. Конечно, эта база слишком проста для того, чтобы приносить много пользы фирме, но достаточно хороша для примера этой книги. Именно эту базу можно импортировать средствами SQL Server Enterprise Manager, тем более, что она уже заполнялась данными (если, конечно, читатель аккуратно создавал эту базу и вводил данные по мере чтения книги).
Если вы успели создать таблицу в базе с именем УчетТоваров, удалите ее при помощи контекстного меню (рис. 23.12). Впрочем, можно этого и не делать. Выберите команду Import Data (рис. 23.13). В появившемся окне DTS Import Wizard (рис. 23.14) щелкните кнопку Next (как сами понимаете, других вариантов почти нет). На экране появится окно с более богатым набором элементов управления (рис. 23.15), предназначенное для определения источника, из которого будут взяты таблицы для импорта. В окне комбинированного списка Source выберите Microsoft Access (рис. 23.16).
Рис. 23.14
В окне DTS Import Wizard щелкните кнопку Next
Рис. 23.15
Окно, предназначенное для определения источника, из которого будут взяты таблицы для импорта
2I
644
Глава 23
OTS Import Wizard
Рис. 23.16
В окне комбинированного списка
Source выберите Microsoft Access
Choose a Data Source
Where would you like Io copy data horn? You can copy data from any of the sources listed below Choose one of the following sources
Source
In Of' sei
Serv
J Micro ull OLE D8 Provider for SUL Stiver ^Driver para о Microsoft Visual FoxPro S'MediaCatalogDB OLE DB Provider S'MedwCatalogMergedDB OLE DB Provider S MediaCalalog«VebDB OLE DB Provider
b Microsoft Access
ЛР M icrosoft Access T rerber (’ mdb) Tjj Microsoft Data Link
Username
Password.
£a'abase
Ц ^default v] Fehesh | Advanced
< gack. |~~ Next>
После выбора в окне комбинированного списка Source элемента Microsoft Access диалоговое окно незаметно изменится для того, чтобы можно было в нем указать имя mdb-файла (рис. 23.17).
Рис. 23.17
После выбора в окне комбинированного списка Source элемента Microsoft Access диалоговое окно незаметно изменится для того, чтобы можно было в нем указать имя mdb-файла
Щелкните кнопку Next в этом окне для перехода к следующему окну; в нем необходимо указать сведения о базе данных, в которую будут записываться импортируемые таблицы (рис. 23.18). Впрочем, если вы начинали работу при помощи контекстного меню с выделенным именем базы данных УчетТоваров, то в этом окне останется только щелкнуть кнопку Next — все остальное будет уже готово.
Если процесс импортирования данных пройдет успешно, на экране, наконец, появится сообщение, ради которого стоило все затевать (рис. 23.24) — «Из Microsoft Access в базу Microsoft SQL Server передано 6-ть таблиц».
Если данные в базу УчетТоваров будут регулярно записываться (этим или иным способом), то не составит особого труда извлекать их оттуда, для различного рода отчетов.
На этом мы завершим краткое описание возможностей SQL Server Enterprise Manager по созданию баз данных. Пока мы не рассмотрели ни вопросы создания представлений, ни — хранимых процедур. Но мы сделаем это позже.
Работа с SQL Server
645
Рис. 23.18
В этом окне следует указать базу данных, в которую попадут импортируемые таблицы
% DI S Import Wizard
Choote a Destination
Where would you kke Io copy dale to*7 You can copy data to any of the destinations listed below Choose one of the following destinations
Destination
Microsoft OLE DB Provider tor SOL Server
□
In order to connect to Microsoft SQL Server you must specify the server user name and password
pOVA	j
Г Use Windows NT authentication Use Server authentication
Username
Password j
database | J УчетТоваров •*] fleftesh | Advanced
< gack
Next >
Cancel |
Рис. 23.19
В этом окне полезна только кнопка
Next
Рис. 23.20
Укажите импортируемые таблицы и щелкните кнопку Next
V DTS Import Wizard

Select Source Tables
You can choose one or more tables to copy You can copy the schema and data as it is in the source or click ( ) to transform th* data using ActiveX scripts
tabled
Source Table ________
№ v* Инвентарная_ведом
v* КонтрКАгента v* НаклЗаголовки
•/ НаклСпецификации
| "Destination Table( Transform*
!.□ [УчетТоварое].[дЬо][И
l2 [УчетТ оваров) [dbo) {
1113 [УчетТoBapo8j.[dbo)[ йШ [УчетТоваровЦдЬо] [Н
•у Склады	1Д {У четТ оваров) [dbo] [
j £e»electAII j
Preview |
< gack
Cancel J
646
Глава 23
Рис. 23.21
Для дальнейшей работы щелкните кнопку Next
Рис. 23.22
Щелкните кнопку со странным именем Finish
Рис. 23.23
Если данных в таблицах очень много, у вас имеется возможность понаблюдать за тем, как оформляют процессы копирования данных профессионалы
Microsoft Access
Mrnsuft SOL Shi /ег
Progress
lllllllllllllll
Transfer status
j Step Name	| Status	ж
Create Table [УчетТоваров] [dbo] [Инвентарная ведим	Cor iplete	
|> Copy Data from Инвентарная_ведомость to [Уч^тТовар	Running [0]	
Create Table [УчетТоваров] [dbo] [КонтрКАгента] Step	Complete	
Copy Data from КонтрКАгента to [У четТоваров] [dbo] [К	Waiting	
Create Table [УчетТоваров] [dbo] [НаклЗаголовки] Step	Complete	—
Copy Data from НаклЗаголовки to [У четТоваров] [dbo] [	Waiting	
v Create Table [УчетТоваров] [dbo] [НаклСпециФикации]	Complete	
Copy Data from НаклСпециФиг ации to [Учет!оваров] [d	Waiting	d
Cancel
Работа с SQL Server
647
Рис. 23.24
Ради этого сообщения и стоило все затевать
OTS Wizard
Successfully transferred S table(s) from Microsoft Access to Microsoft SQL Server.
Создание базы данных посредством кода
Создавать и корректировать базу при помощи Server Enterprise Manager легко, в чем вы сами можете убедиться, но это не всегда бывает возможно, а иногда и неудобно.
Если вы — не системный администратор, то вряд ли вас «подпустят» к клавиатуре компьютера, на котором находится SQL Server. В лучшем случае на какое-то время вам могут дать права на создание баз данных с удаленного компьютера, да и то, скорее всего, на «пустом» сервере.
Если вы работаете с SQL Server на своем компьютере, то создавать базу при помощи Server Enterprise Manager можно также в качестве «разминки». Дело в том, что обычным делом любого «нормального» пользователя компьютера является случайное удаление тех или иных данных, а иногда и полное форматирование жестких дисков. Не всегда у пользователя имеется время на подготовку к переустановке системы. Конечно, никогда не стоит забывать о всевозможных способах дублирования информации, но гораздо удобнее просто написать код для создания баз данных. Это будет самой «твердой» копией пустой (без данных) базы. Если код для создания базы данных включает, кроме описания таблиц, еще определения хранимых (stored) процедур и представлений (views), то процесс восстановления базы на SQL Server (без данных) займет очень мало времени. Конечно, где-то, скорее всего, в некотором внешнем для SQL Server формате должны храниться данные для заполнения базы.
После соединения с сервером из клиентской части программного обеспечения можно посылать команды серверу. Несмотря на то, что эти команды посылаются из VBA-приложения (или, например, C++ или Delphi), они, конечно, должны быть командами языка Т-SQL. Поэтому здесь и далее мы рассмотрим некоторые из них.
Инструкция создания базы данных на «SQL-диалекте» SQL Server имеет непростой синтаксис, но большая его часть является необязательной и предназначена для очень «тонкой» настройки. Самый простой синтаксис этой инструкции имеет следующий вид:
ЧСИНТАКСИС +	»< +
CREATE DATABASE <database_name>
Здесь database_name — имя создаваемой базы данных. Имя должно быть уникальным для данного сервера, отвечать правилам для имен идентификаторов и не превышать по длине 128 символов.
Инструкция создания таблицы базы данных на «SQL-диалекте» SQL Server имеет также непростой синтаксис, но большая его часть является необязательной. Самый простой синтаксис этой инструкции имеет следующий вид:
синтаксис	>.
CREATE TABLE (имя таблицы^
( имя_поля1 тип поля [NIT NULL ] , имя_поля2 тип поля [NIT NULL ] , имя_поляЗ тип поля [NIT NULL ] , . . . )
648
Глава 23
Для создания таблицы на сервере необходимо передать серверу SQL-инструкцию, например, при помощи метода Execute объекта Connection, например:
' создать новую таблицу в текущей базе данных
cn.Execute "CREATE TABLE Т2 " S
"(C_KOD VARCHAR(12) NOT NULL, " S
" N_SELLO MONEY, " S
" N_SELL MONEY, " &	*
" N_ZAKUP FLOAT " S n J >
В главе 20 на рис. 20.28 представлена схема базы данных, которая в этой главе была загружена при помощи SQL Server Enterprise Manager на сервер. Эта схема была создана в системе ERWin, позволяющей не только отображать базу при помощи редактора, но и генерировать код для создания базы данных для различных СУБД, в том числе и для SQL Server. В листинге 23.1 представлен код, сгенерированный для этой цели на языке Т-SQL (диалект SQL Server) в системе ERWin.
Листинг 23.1. Код для создания базы данных, сгенерированный в системе ERWin
1 CREATE TABLE Инвентарная ведомость (	
2	КодТовара	VARCHAR(12) NOT NULL,
3 4 5 )	КодСклада	SMALLINT NOT NULL,	' Количество	INTEGER NULL
6 до 7	X
8 9 ALTER	TABLE Инвентарная ведомость
10 11 до 12 13	ADD PRIMARY KEY NONCLUSTERED (КодТовара, КодСклада)
14 CREATE 15 16 17 18 )	TABLE Контрагенты ( НаименованиеКАгента SMALLINT NULL, КодКАгента SMALLINT NOT NULL, Адрес varchar(20) NULL
19 до 20 21	
22 ALTER 23 24 до 25 26	TABLE Контрагенты ADD PRIMARY KEY NONCLUSTERED (КодКАгента)
27 CREATE 28 29 30 31	TABLE НаклЗаголовки ( КодКАгента	SMALLINT NOT NULL, КодСклада	SMALLINT NOT NULL, Дата	datetime NULL, Номер	INTEGER NULL,
32 33 )	ТипНакладной	INTEGER NULL
34 до > 35 36	t
37 ALTER	TABLE НаклЗаголовки
38 3 9 до 40 41	ADD PRIMARY KEY NONCLUSTERED (КодКАгента, КодСклада) <
42 CREATE	: TABLE НаклСпецификации (
43	Дата	datetime NULL,	1
Работа с SQL Server
649
44	КодТовара	VARCHAR(12) NOT NULL,
45	Номер	INTEGER NULL,
46	Количество	int NULL,
47	ЦенаОперации	DOUBLE PRECISION NULL
48 )	
4 9 go 50	
51	•
52 ALTER	TABLE НаклСпецификации
53	ADD PRIMARY KEY NONCLUSTERED (КодТовара)
5 4 go 55 56	
57 CREATE	: TABLE Склады (
58	НаименованиеСклада VARCHAR(4 NULL,
59	КодСклада	SMALLINT NOT NULL,
60	Адрес	char(18) NULL
61 )	
62 go 63 64	
65 ALTER	TABLE Склады
66	ADD PRIMARY KEY NONCLUSTERED (КодСклада)
67 go 68 69	
70 CREATE	: TABLE Товары (
71	НаименованиеТовара VARCHAR(30) NULL,
72	КодТовара	VARCHAR(12) NOT NULL,
73	ЦенаОптовая	DOUBLE PRECISION NULL,
74	ЦенаРозничная	DOUBLE PRECISION NULL
75 )	
7 6 go 77 78	
79 ALTER	TABLE Товары
80	ADD PRIMARY KEY NONCLUSTERED (КодТовара)
81 go 82 83	
84 ALTER TABLE Инвентарная_ведомость
85	ADD FOREIGN KEY (КодСклада)
86	REFERENCES Склады
87 go
88
89
90 ALTER TABLE Инвентарная_ведомость
91	ADD FOREIGN KEY (КодТовара)
92	REFERENCES Товары
93 go
94
95
96 ALTER TABLE НаклЗаголовки
97	ADD FOREIGN KEY (КодКАгента)
98	REFERENCES Контрагенты
99 go
100
101
102 ALTER TABLE НаклЗаголовки
103	ADD FOREIGN KEY (КодСклада)
104	REFERENCES Склады
105 go
106
650
Глава 23
107
108 ALTER TABLE НаклСпецификации
109	ADD FOREIGN KEY (КодТовара)
110	REFERENCES Товары
111 go
Для передачи кода, сгенерированного при помощи ERWip, на сервер писать VBA-код не нужно. ERWin имеет диалоговые средства для подключения к SQL Server и передачи на него генерирующего кода. Чтобы отправлять на сервер команды из VBA-кода, необходимо подключиться к серверу. Это можно сделать, зарегистрировав в качестве источника данных ODBC базу данных, хранящуюся на сервере. В этом случае код, рассматриваемый в главе 22 с использованием ODBC, можно без всяких изменений использовать и для SQL Server.
В листинге 23.2 для соединения с источником данных, находящемся на SQL Server, используется технология ADO и провайдер для SQL Server. В последних листингах главы 22 для установки соединения применялись функции ADODBCon-nectedODBC (с использованием провайдера для ODBC) и ADODB ConnectedJet (с использованием провайдера для Microsoft Jet). В листинге 23.2 применяется функция ADODB ConnectedSQL, которая использует провайдер для SQL Server. Остальной код, практически, остается тем же.
Листинг 23.2. Открытие ADO-соединения с источником SQL Server
1 Dim cn As ADODB.Connection
2
3 Function ADODB_ConnectedSQL() As Boolean
4 ' устанавливает соединение для SQL Server
5 Set cn = New ADODB.Connection
6
7	On Error GoTo err_not_connection
8
9	Set cn - New ADODB.Connection
10	cn.Provider = "SQLOLEDB.l"
11	cn.Connectionstring = _
12	"0АТАВА5Е=УчетТоваров;SERVER=VOVA;UID=Dmitry;PWD=Dmitry"
13	cn.Open
14
15	ADODB_ConnectedSQL	= True
16	Exit Function
17
18 err_not_connection:
19 ADODB_COnnectedSQL = False
20
21 End Function	’
22 Sub Test_ADODB_Connected()
23 ' тестирует ADODB_ConnectedSQL: устанавливает соединение и
24 1 11 использует данные из таблицы Товары
25
26
27 If ADODB_ConnectedSQL() Then
28	MsgBox "Похоже, соединение установлено..."
29	' код, использующий установленное соединение: ‘
30
31	Set rs = New ADODB.Recordset	'
32	rs.CursorType = adOpenDynamic
33	rs.Source = "SELECT * FROM Товары"
34	Set rs.ActiveConnection = cn
35	rs.Open
36
37	MsgBox rs.Fields(l) & " " & rs.Fields(1).Name
Работа с SQL Server
651
38
39	cn.Close 1 закрыть соединение
40	Else
41	MsgBox "Что-то не сложилось!"
42	End If
43
44 End Sub
Представления и хранимые процедуры
Последняя тема книги посвящена одному из интересных (с точки зрения программистов) вопросов — разработке клиент-серверных приложений. Дело в том, что при переходе от mdb-версий баз данных к версиям SQL Server одним переносом самой базы на сервер ограничиваются далеко не все разработчики. Это связано со многими обстоятельствами, в том числе с изменением физических устройств по передаче информации и, быть может, качественного состава пользователей базы. Перспектива передачи информации на большие расстояния (большие, чем в рамках одного компьютера) должна вызывать у разработчика баз данных желание передавать только самую необходимую часть данных, хранящихся на сервере. Например, из тысячи накладных, находящихся в базе данных, нам нужно передать на клиентский компьютер только одну (хотя можно передать все для дальнейшего выбора необходимой из них).
В каком-либо контексте многие пользователи, имеющие отношение к программированию баз данных, слышали о программном обеспечении «на стороне сервера», которое обрабатывает запросы клиентского компьютера и возвращает результаты этой обработки клиенту. Этот аппарат, в частности, реализуется при помощи представлений (views) и хранимых процедур (stored procedure), находящихся на сервере вместе с базой данных (рис. 23.4).
Для того чтобы разрабатывать представления и хранимые процедуры, необходимо использовать подробную инструкцию по разработке программного обеспечения выбранного сервера баз данных. В этом разделе содержится «рекламная» информация о возможностях, открываемых разработчику VBA-приложений, если он «осмелится» использовать данные, обрабатываемые при помощи представлений и хранимых процедур SQL Server.
Представление подобно запросу в базе данных Access; оно не имеет параметров и возвращает набор данных (таблицу). Например, для базы данных УчетТоваров следующее представление (вместе с кодом для его создания) возвращает таблицу из трех полей, содержащую информацию о товарах:
CREATE VIEW Прейскурант AS SELECT НаименованиеТовара
AS 'Наименование' , ЦенаОптовая AS 'Цена оптовая' FROM Товары
Для наглядности структура таблицы, используемой в представлении, приведена на рис. 23.25, а ее содержимое — на рис. 22.6.
Инструкция CREATE VIEW представляет собой обычную SQL-инструкцию, подобную той, которая использовалась в окне, показанном на рис. 22.19 для ввода инструкций DELETE и INSERT INTO в главе 22. Так же, как и эти инструкции, ова не возвращает набор и может быть передана на сервер посредством метода Execute объекта Connection. Но в отличие от этих и других инструкций представление, во-первых, навсегда останется на сервере в области хранения информации о базе данных УчетТоваров и, во-вторых, может быть помещено на сервер при помощи SQL Server Enterprise Manager.
Для создания представления при помощи SQL Server Enterprise Manager следует раскрыть ветвь УчетТоваров, как показано на рис. 23.27. При этом можно увидеть, где SQL Server хранит все представления этой базы данных. Далее необходимо выбрать Action | New View.
652
Глава 23
Рис. 23.25
Структура таблицы, используемой в представлении
Table Prepeilies • Товары
3
Geneial |
Owner
Товарь
Регггг-$юп$ j
dbo
Create date
10 03 03 22 00 34
Fdegroup Rows
PRIMARY
26
Columns
КодТовара
Наименование! овара
ЦенаОптовая
ЦенаРозничная
Data Ту ptee'] Nulls J Defa nvarchar nvarchar
money money
50
8
8
I ...°к................................................................................................................................I
Cancel I
Рис. 23.26
Содержимое таблицы, используемой в представлении
|7ш	in Table'Товары*				визе!
Й*	°o □ мн	cP !	.	(f=	4ц
	КодТовара	|НаименованиеТовара	1 ЦенаОптовая |ЦенаРозничма5-<1	
	ВДЗД Ш (ЗДДО|	(и; Road Rush II	42	49	J
	006019170049	(5) Tasmania	30	35
	010414114438	(VCD) Патриот	138	161
	010415090732	(VCD) Пастырь	111	130
	010415090937	(VCD) Шоссе в никуда	120	140
	010428144348	(VCD) Доберман	135	158
-	028019100222	(VCD) Голая мишень	90	105
	028019095823	(VCD) Dtder Marouani	90	105
	028019100018	(VCD) Wham' The best of	105	123
	036019164741	(S) Cool Spot	42	49
	174500175359	(3DC) Street Fighter 3 Wimpact	750	875
	174500175521	(3DC) Star Gladiator 2	750	875
	186100175232	(3DC) Super Runabout	750	875
T]	006019165803	(S) Road Rush II	42	49
				
Рис. 23.27
Здесь SQL Server хранит все представления базы данных УчетТоваров
[’Йи Censel» R»at\Micf«t«ft SQL Swv*Ts\SQLS»rv«iGi*up\VGVA(Wi»ihiRi ЭЬ/М№а*аЬыыШ<««гТ	Rf"*Q
Action View	Tools Ф	(Xj	ГГ		• 3 й г X » 0 В 5			
				20 Items			
VOVA Endows 95?38|		“3		Name	Owne	1 Type	f Dea*e Dale л
! . 1	Databases			CHECK CONSTRAINTS	INFORMATI	System	1311 98307 17
4	Lj fmans			^COLUMN DOMAIN USAGE	informati	System	13 11 98 3:07 12
	@ master			6V*COLUMN PRIVILEGES	INFORMATI	System	1311 98 30713
	model			AT COLUMNS	INFORMATI	System	13 11 9830712
	(jj msdb			6V CONSTRAINT COLUMN US	INFORMATI	System	13 11 98 30718
tt	Q tempdb (g УчетТоваров сЕд Dagrarns (21 Tabtes бхгЩД			^CONSTRAINT TABLEJJSAGE	INFORMATI	System	1311 9830717
				^DOMAIN CONSTRAINTS	INFORMATI	System	1311 98307 U
				^DOMAINS	INFDR MAT!	System	1311 98 30711
				AT KEY COLUMN USAGE	INFORMATI	System	1311 98 30715
				^REFERENTIAL CONSTRAINTS	INFORMATI	System	1311 98 30716
	Stored Procedures			^SCHEMATA	INFORMATI	System	1311 98 30709-
	Users			tfcf sysaDernates	dbo	System	1311 98 3 0019
	Ди Roles			sy sconstiants	dbo	System	1311 98 3 0019
	S3 Rules			syssegments	dbo	System	13 11 9830019
	I"1 Defaults	_ 1		Stable constraints	HFORMATI	System	1311 98307 10 „1
<1	Г			<1					_J 2Г
							
Работа с SQL Server
653
На экране появится окно для ввода нового представления, куда следует ввести SELECT-запрос, как показано на рис. 23.28, то есть без первых слов "CREATE VIEW Прейскурант AS".
Рис. 23.28. В окне кода представления введите обычный SQL-запрос
Преимуществом создания представления таким способом является возможность проверки кода представления (особенно сложных представлений), так как, щелкнув на кнопке Run, можно проверить правильность написания представления (рис. 23.29).
Рис. 23.29. Щелкнув на кнопке Run, можно проверить правильность написания представления
654
Глава 23
Если все — правильно, следует для сохранения представления в базе данных щелкнуть кнопку Save и ввести в окне Save As наименование представления — Прейскурант (рис. 23.30).
Рис. 23.30
В этом окне следует ввести имя представления
После ввода наименования представления, можно увидеть, что представление Прейскурант заняло свое место в базе данных УчетТоваров (рис. 23.31).
й Console Rool\Micro»oft SQL ServcrASQI Snivel GrowpWOVA (Windows

□	9 o ® ca

- ___J DafsbaSeS	_-*J
+ finans
+ Й master
+ model
• + ij
+_ U ServiceCenter
+ (J tempdb
(J УчетТоваров
£k£| Diagrams
~’| Tables
bVJHS
Stored Procedures
Users
0 Roles	___
И Rules
ПП Defaults
£2 Usci Defined Dafa Ti ^.i
~ T 1 ±r
Name	Ormer	1 Type
^DOMAIN CONSTRAINTS	INFORMATI	System
&TDOMAINS	INFORMATI	System
ftTKEY.COLUMN USAGE	INFORMATI	System
AT REFERENTIAL-CONSTRAINTS	INFORMATI	System
AT SCHEMATA	INFORMATI	System
6?cT sysalternates	dbo	System
bxTsysconstr amts	dbo	System
syssegments	dbo	System
AT TABLE CONSTRAINTS	INFORMATI	System
ftTTA8LE_PRWILEGES	INFORMATI	System
ЙС TABLES	INFORMATI	System
fa* VIE W_C0 LU M N.U SAG E	INFORMATI	System
6VVIEW_TAEILE_USAGE	INFORMATI	System
fa* VIEWS	INFORMATI	System
Сто'1 Прейскурант	dbo	User
±L
I Create 0 ate *1
1311 Э8 3 07 14
1311 98 3 0714
1311 9830715
13 11 98307 1b
13 11 98307 03
13 11 9830019
1311 9830013
1311 9830019
1311 9830710
1311 9830711
1311 98307 03
1311 38307 20
1311 38307 20
1311 38307 13
31 03 03 20 57 2 V
±J
Рис. 23.31. Представление Прейскурант заняло свое место в базе данных УчетТоваров
После создания представления его можно редактировать только при помощи SQL Server Enterprise Manager столько раз, сколько это будет необходимо для успешной эксплуатации базы данных. Если доступа к этому средству не имеется, то можно из VBA-кода SQL-инструкцией DROP Прейскурант удалить представление, а затем ввести его новый код из VB-программы.
Для демонстрации использования представления Прейскурант в листинге 23.3 приведен код процедуры Test_ADODB_Connected из листинга 22.2, но теперь для передачи в набор данных применен метод Execute с объекта Connection аргументом "SELECT * FROM Прейскурант". Как видно из этой SELECT-инструкции, имя представления используется как имя обычной таблицы, хотя представление может быть довольно сложным запросом.
Листинг 23.3. Открытие ADO-соединения с источником SQL Server и использование представления 1 2 3 4 5
1 Sub Test_ADODB_Connected()
2 ' тестирует ADODB_ConnectedSQL: устанавливает соединение
3 ' и использует представление
4
5
Работа с SQL Server
655
6	If ADODB_ConnectedSQL() Then
7	MsgBox "Похоже, соединение установлено..."
8	' код, использующий установленное соединение:
9
10	' применение представления:
11	Set rs = cn.Execute("SELECT * FROM Прейскурант")
12
13	MsgBox rs.Fields(1) & " " & rs.Fields(1).Name
14
15	cn.Close 1 закрыть соединение
16	Else
17	MsgBox "Что-то не сложилось!"
18	End If
19
20	End Sub
Более гибким средством получения определенных наборов данных с сервера является хранимая процедура, которая в отличие от представления может принимать параметры, влияющие на выбор данных. Как и для разработки представлений, для освоения аппарата хранимых процедур следует хорошо ознакомиться с инструкциями конкретного сервера. Здесь же будет приведен только один пример, с одной стороны, для того, чтобы показать необходимость работы с хранимыми процедурами, с другой — чтобы читатель не подумал, что эта тема для него очень сложная.
CREATE PROCEDURE СпецифНакладной @pwhere char(4), @nom_naclad char(7), @datn char(10) AS SELECT b.C_NAMET as 'Наименование', a.N_KOL as 'Кол-во', a.N__SLLD as 'Цена' FROM T1NACL1 a, T2 b WHERE a.C_WHERE = @pwhere and a.N_NOM =@nom_naclad and a.D_DATN=@datn and a.C~KOD=b.C_KOD ORDER BY b.C_NAMET
Основным отличием хранимой процедуры от представления является возможность передавать процедуре параметры со всеми вытекающими из этого последствиями: процедура может иметь операторы, влияющие на последовательность выполнения кода, возвращаемые наборы могут зависеть от входных параметров. Кроме того, хранимая процедура может и не возвращать набор. В приведенной выше процедуре с наименованием СпецифНакладной список
Spwhere char(4), @nom_naclad char(7), @datn char(10)
является списком параметров: @pwhere — текстовый длиной 4 символа, @nom_na-clad — текстовый длиной 7 символов, @datn — текстовый длиной 10 символов. Символ @ также входит в имя параметра. Если хранимая процедура представляет собой единственный SQL-запрос, то параметры используются в предложении WHERE, как в рассматриваемом примере.
Код листинга 23.4 использует хранимую процедуру для получения спецификации накладной. Строка strSQL, которая формируется для вызова процедуры СпецифНакладной, имеет следующее значение:
"ЕХЕС СпецифНакладной @pwhere='3123' , @nom_naclad=5, @datn='11.02.2003'"
Листинг 23,4. Открытие ADO-соединения с источником SQL Server и использование хранимой процедуры 1 2 3 4 5 6 7 8
1 Sub Test_ADODB_Connected2()
2 ' тестирует ADODB_ConnectedSQL: устанавливает соединение
3 ' и использует хранимую процедуру
4
5 Dim strSQL As String
6
7	m_pwhere = "3123"	' код склада
8	m_nom_naclad = 5	' номер накладной
656
Глава 23
9 m_datn = "11.02.2003"	' дата накладной
10
11	strSQL = "EXEC СпецифНакладной @pwhere='" & m_pwhere &	" &
12	" @nom_naclad=" & Str(m_nom_naclad) & ", " & _
13	" @datn='" & m_datn & .............
14
15	If ADODB_ConnectedSQL() Then
J.6	MsgBox "Похоже, соединение установлено..»"
17	' код, использующий установленное соединение:
18
19	' применение хранимой процедуры:
20	Set rs = cn.Execute (strSQL)
21
22	MsgBox rs.Fields(l) & "	" & rs.Fields(1).Name
23
'24	cn.Close ' закрыть соединение
25	Else
26	MsgBox "Что-то не сложилось!"
27	End If
28
29 End Sub
При написании представления или хранимой процедуры всегда следует помнить, что они выполняются на сервере, а значит должны соответствовать синтаксису SQL-версии СУБД, обеспечивающей сервер В частности, нельзя использовать функции, которые хорошо работали в SQL-инструкциях локального или клиентского компьютера
Приложения
В данных приложениях собраны справочные сведения, которые могут пригодиться разработчикам VBA-приложений. Для более удобной работы с этими приложениями некоторые материалы содержатся одновременно в нескольких приложениях.
Приложение А
Справочные таблицы книги
Таблица 2.1. Команды меню File (файл)
Команда	Горячая клавиша	Действие
Save <project> (сохранить <проект>)	Ctrl+S	Сохраняет текущий проект VBA на диске, 1 включая все модули и формы.
Import File (импорт файла)	Ctrl+M	Добавляет существующий модуль, форму или класс в текущий проект. Вы можете импортировать только модули, формы или классы, 1 сохраненные ранее командойЕхроН File из другого проекта.
Export File (экспорт файла)	Ctrl+E	Сохраняет текущий модуль, форму или класс в формате текстового файла для импортирования в другой проект или в целях архивиро-1 вания.
Remove <item> (удалить <...>)		Перманентно удаляет модуль или форму текущего выбора из проекта VBA. Эта команда не доступна, если в Project Explorer не выбран никакой элемент.
Print (печать)	Ctrl+P	Печатает модуль или форму для документирования или с целью архивирования.
Close and Return to ... (закрыть и вернуться в ... )	Alt+Q	Закрывает Редактор VB и возвращает вас в host-приложение и документ/рабочую книгу, из которых вы открывали Редактор VB.
Таблица. 2.2. Команды меню Edit
Команда	Горячая клавиша	Действие
Undo (отменить)	Ctrl+Z	Отменяет самую последнюю команду. Не все команды могут быть отменены. Меню доступно только в случае, если есть, что отменять.
Redo (вернуть)		Возвращает самую последнюю команду, кото-рую вы отменили.
Cut (вырезать)	Ctrl+X	Вырезает выделенный текст или объект и помещает его в Windows Clipboard. Выделенный текст или объект удаляется из модуля или формы.
Сору (копировать)	Ctrl+C	Копирует выделенный текст или объект и помещает его в Windows Clipboard. Выделенный текст или объект остается неизменным.
Справочные таблицы книги
659
Команда	Горячая клавиша	Действие
Paste (вставить)	Ctrl+V	Вставляет текст или объект из Windows Clipboard в текущий модуль или форму.
Clear (очистить)	Del	Удаляет выделенный текст или объект из модуля или формы.
Select АП (выделить все)	Ctrl+A	Выделяет весь текст в модуле или все объекты в форме.
Find (найти)	Ctrl+F	Подобно команде Find в Word или Excel, позволяет находить указанный текст в модуле.
Find Next (найти далее)	F3	Повторяет последнюю операцию Find.
Replace (заменить)	Ctrl+H	Подобно команде Replace в Word или Excel, позволяет находить указанный текст в модуле и заменять его другим текстом.
Indent (увеличить отступ)	Tab	Смещает весь выделенный текст вправо на интервал табуляции.
Outdent (уменьшить отступ)	Shift+ Tab	Смещает весь выделенный текст влево на интервал табуляции.
List Properties/ Methods (список свойств/ме-тодов)	Ctrl+J	Открывает список в List Properties/ Methods, отображая свойства и методы объекта, имя которого вы только что ввели. Когда курсор вставки находится на пустом месте в List Properties/ Methods эта команда открывает список глобально доступных свойств и методов.
List Constants (список констант)	Ctrl+ Shift+J	Открывает список в Code Window, отображающий допустимые константы для свойства, которое вы только что ввели с предшествующим знаком
Quick Info (сведения)	Ctrl+I	Открывает всплывающее окно подсказки, отображающее правильный синтаксис для процедуры, функции или метода, который вы только что ввели в Code Window.
Parameter Info (параметры)	Ctrl+ Shift+I	Открывает всплывающее окно подсказки, отображающее параметры (называемые также аргументами) процедуры, функции или оператора, который вы только что ввели в Code Window.
Complete Word ^завершить слово)	Ctrl+ Space	Редактор VB заканчивает слово, которое вы вводите, как только вы введете достаточно символов для того, чтобы VBA распознал ключевое слово.
.Bookmarks (закладки)		Открывает подменю с пунктами для помещения, удаления или перехода к закладкам, которые вы ранее поместили в ваш модуль. В отличие от закладок в Word, закладки Редактора VB не имеют имен.
660
Приложение А
Таблица 2.3. Команды меню View
Команда	Горячая клавиша	Действие
Code (программа)	F7	Активизирует Code Window для отображения исходного кода VBA, ассоциированного с выбранным модулем или формой.
Object (объект)	Shift+F7	Отображает объект текущего выбора в Project Explorer.
Definition (описание)	Shift+F2	Отображает исходный код VBA для процедуры или функции, на которую указывает курсор; отображает Object Browser для объектов в справке VBA.
Last Position (вернуться к последней позиции)	Ctrl+ Shift+F2	Переходит в последнюю позицию в модуле после использования команды меню Definition или после редактирования кода.
Object Browser (просмотр объектов)	F2	Открывает Object Browser, позволяющий определять, какие макросы доступны в данный момент.
Immediate Window (окно отладки)	Ctrl+G	Отображает окно отладчика Immediate Window VBA.
Locals Window (окно локальных переменных)		Отображает окно отладчика Locals Window.
Watch Window (окно контрольного значения)		Отображает окно отладчика Watch Window (контрольные значения).
Call Stack (стек вызова)	Ctrl+L	Отображает список последовательности вызовов для текущей функции или процедуры VBA.
Project Explorer (окно проекта)	Ctrl+R	Отображает Project Explorer.
Properties Window (окно свойств)	F4	Отображает Properties Window.
Toolbox (панель элементов)		Отображает Toolbox. Toolbox используется для добавления элементов управления в пользовательские диалоговые окна.
Tab Order (последовательность перехода)		Отображает диалоговое окно Tab Order, которое используется при создании пользовательских диалоговых окон.
Toolbars (панели инструментов)		Отображает подменю, позволяющее показывать или скрывать различные панели инструментов Редактора VB или открывать диалоговое окно для настройки одной из панелей инструментов Редактора VB.
Справочные таблицы книги
661
Команда	Горячая клавиша	Действие
<Host application (host-приложение)	Alt+Fll	Возвращает вас в host-приложение, из которого был запущен Редактор VB, но оставляет Редактор VB открытым. Конкретное , имя этого пункта меню зависит от того, из какого host-приложения VBA вы запустили Редактор VB.
Таблица 2.4. Команды меню Insert
Команда	Действие
Procedure (процедура)	Вставляет новую процедуру (Sub, Function или Property) в текущий модуль. (Процедура — это еще одно название макроса).
UseForm	Добавляет новую форму (используется для создания пользовательских диалоговых окон) в проект.
Module (модуль)	Добавляет новый модуль в проект. Редактор VB дает этому модулю имя в соответствии с правилами, описанными ранее в этой главе.
Class Module (модуль класса)	Добавляет в проект class module (модуль класса). Модули класса используются для создания пользовательских объектов в проекте.
File (файл)	Позволяет вставлять текстовый файл, содержащий исходный код VBA, в модуль.
Таблица 2.5. Команды меню Format
Команда	Действие
Align (выровнять)	Открывает подменю команд, которые позволяют выравнивать выбранные объекты в форме по отношению друг к другу. Здесь можно выравнивать объекты по верхней/нижней, правой/левой границам, по центру или середине создаваемого объекта.
Make Same Size (выровнять размер)	Открывает подменю команд, позволяющих изменять размер выделенных объектов до размера указанного объекта.
Size to Fit (подогнать размер)	Одновременно изменяет ширину и высоту объекта до соответствия размеру его содержимого.
Size to Grid, (выровнять размер по сетке)	Одновременно изменяет ширину и высоту объекта до ближайших меток сетки. При разработке форм Редактор VB отображает в форме сетку, чтобы было легче располагать и изменять размеры объектов в форме.
Horizontal Spacing (интервал по горизонтали)	Открывает подменю команд, позволяющих устанавливать горизонтальный интервал для выбранных объектов. Здесь можно устанавливать равномерный горизонтальный интервал, уменьшать или увеличивать его или удалять всякий горизонтальный интервал между объектами.
662
Приложение А
Команда	Действие	
Vertical Spacing (интервал по вертикали)	Открывает подменю команд, позволяющих устанавливать вертикальный интервал для выбранных объектов. Здесь можно устанавливать равномерный вертикальный интервал, уменьшать или увеличивать его или удалять всякий вертикальный интервал между объектами.	
Center in Form (разместить по центру в форме)	Открывает подменю команд, позволяющих изменять положение выбранных объектов, чтобы они были центрированы в форме горизонтально или вертикально.	
Arrange Buttons (разместить кнопки)	Открывает подменю команд, позволяющих автоматически располагать командные кнопки в форме в ряд с равным интервалом по нижнему или правому краю формы.	
Group (группировать)	Связывает несколько выбранных объектов вместе в одну группу, чтобы вы могли перемещать, изменять размер, вырезать или копировать объекты, обращаясь с ними, как с одним целым.	
Ungroup (разделить)	Отменяет группировку объектов, которые перед этим были связаны вместе с помощью команды Group.	
Order (порядок)	Открывает подменю команд, позволяющих изменять упорядочение сверху вниз (называемое z-order ) перекрывающихся объектов в форме. Используйте команду Order, чтобы обеспечить, например, появление текстового окна всегда поверх графического объекта в форме.	
Таблица 2.6. Команды меню Debug		
Команда	Горячая клавиша	Действие
Compile <project> (компилировать <про-ект>)		Компилирует проект, выбранный в данный момент в Project Explorer.
Step Into (шаг с заходом)	F8	Выполняет исходный код вашего макроса по одному оператору каждый раз.
Step Over (шаг с обходом)	Shift+F8	Подобно команде Step Into команда Step Over позволяет выполнять все инструкции в макросе без паузы на каждой отдельной инструкции.
Step Out (шаг с выходом)	Ctrl+ Shift+F8	Выполняет все остающиеся операторы в макросе без паузы на каждом отдельном операторе.
Run to Cursor (выполнить до текущей позиции )	Ctrl+F8	Выполняет операторы исходного кода макроса от оператора, выполняющегося в данный момент, до текущей позиции курсора.
Add Watch (добавить контрольное значение)		Позволяет указывать переменные или выражения, значения которых можно наблюдать во время выполнения исходного кода VBA.
Справочные таблицы книги
663
Команда	Горячая клавиша	Действие
Edit Watch (изменить контрольное значение)	Ctrl+W	Позволяет редактировать спецификации для наблюдаемых переменных и выражений, которые были созданы ранее с помощью команды Add Watch.
Quick Watch (контрольное значение)	Shift+F9	Отображает текущее значение выбранного выражения.
Toggle Breakpoint (точка останова)	F9	Отмечает место (или отменяет отметку) в исходном коде VBA, где необходимо остановить выполнение макроса.
Clear All Breakpoints (снять все точки останова)	Ctrl+Shift +F9	Удаляет все точки останова в модуле.
Set Next Statement (задать следующую инструкцию)	Ctrl+F9	Позволяет менять обычное выполнение кода путем указания вручную следующей строки исходного кода, которая должна выполняться.
Show Next Statement (показать следующую инструкцию)		Приводит к подсветке Редактором VB следующей строки кода, которая будет выполняться.
Таблица 2.7. Команды меню Run
Команда	Горячая клавиша	Действие
Run Sub/User Form (запуск подпрограм-мы/User Form)	F5	Приводит к тому, что VBA запускает макрос, который редактируется в данный момент, то есть VBA запускает макрос, на тексте которого находится курсор вставки. Если какая-либо форма активна, VBA запускает эту форму.
Break (прервать)	Ctrl+Break	Прерывает выполнение вашего кода VBA и приводит к тому, что Редактор VB переходит в режим прерывания (Break mode). (Break mode используется при отладке кода VBA.)
Resert <project> (сброс)		Устанавливает все переменные модульного уровня и Call Stack (список последовательности вызовов) в исходное состояние.
Design Mode (конструктор)		Включает и выключает Design mode (режим проектирования или разработки) для 1 проекта. В этом режиме никакой код в вашем проекте не выполняется, и события от элементов управления не обрабатываются.
664
Приложение А
Таблица 2.8. Команды меню Tools
Команда	Действие
References (ссылки)	Отображает диалоговое окно References, позволяющее устанавливать ссылки на библиотеки объектов, библиотеки типов или другой проект VBA. После установления ссылки объекты, методы, свойства, процедуры и функции в этой ссылке появляются в диалоговом окне Object Browser.
Additional Controls (дополнительные элементы)	Отображает диалоговое окно Additional Controls, позволяющее настраивать Toolbox (панель элементов) так, чтобы вы могли добавлять элементы управления в формы, помимо встроенных в VBA. Диалоговое окно Additional Controls предназначено для добавления к панели элементов кнопок, которые позволяют добавлять к форме объекты, такие как рабочий лист Excel или документ Word.
Macros (макросы)	Отображает диалоговое окно Macros, позволяющее создавать, редактировать, выполнять или удалять макросы.
Options (параметры)	Отображает диалоговое окно Options, позволяющее выбирать различные опции для Редактора VB, такие как число пробелов в интервале табуляции (tab stop), когда VBA проверяет синтаксис ваших операторов, и так далее.
<project> Properties (свойства проекта)	Отображает диалоговое окно Project Properties, позволяющее устанавливать различные свойства вашего проекта VBA, такие как имя проекта, описание и файл контекстной справки. Это диалоговое окно позволяет также защищать проект, чтобы никто не мог его редактировать без указания пароля.
Digital Signature (цифровая подпись)	Отображает диалоговое окно Digital Signature, в котором можно задать для проекта сертификат цифровой подписи.
Таблица 2.9. Кнопки панели инструментов Standard
Кнопка	Действие
View <host application (вид <host-npuwxHce-ние>)	Переключает на host-приложение VBA, из которого вы запустили Редактор VB. Значок этой кнопки изменяется в зависимости от конкретного приложения, из которого вы запускали редактор VB.
Insert UserForm (вставить UserForm)	Щелкните на кнопке со стрелкой вниз справа от этой кнопки, чтобы отобразить список объектов, которые вы можете вставить в текущий проект: UserForm, Module, Class Module или Procedure. Это можно выполнить и при использовании одноименных команд меню Insert (вставка).
Save (сохранить)	Сохраняет текущий проект так же, как File | Save.
Cut (вырезать)	Вырезает выделенный текст или объект и помещает его в Clipboard; так же, как команда Edit | Cut.
Справочные таблицы книги
665
Кнопка	Действие
Сору (копировать)	Копирует выделенный текст или объект в Clipboard; так же, как команда Edit | Сору (правка | копировать).
Paste (вставить)	Вставляет текст или объект из Clipboard в Code Windaw или форму пользователя в позицию курсора; так же, как команда Edit | Paste (правка | вставить).
Find (найти)	Открывает диалоговое окно Find для нахождения определенного слова или фразы в модуле; так же, как команда Edit | Find (правка | найти).
Undo (отменить набор)	Отменяет самую последнюю команду, если это возможно (не все действия могут быть отменены); так же, как команда Edit | Undo (правка | отменить набор).
Redo (вернуть набор)	Возобновляет самую последнюю отмененную команду; так же, как команда Edit | Redo.
Run Macro (запуск подпрограммы/UserForm)	Запускает текущую процедуру или форму; так же, как команда Run | Sub/UserForm.
Break (прервать)	Прерывает выполнение кода VBA; так же, как команда Run | Break (запуск | прервать).
Reset (сброс)	Перезапускает код VBA, как команда Run | Reset (запуск | сброс).
Design Mode (конструктор)	При нажатии этой кнопки Редактор VB переходит в режим Design (конструктора); так же, как команда Run | Design Mode (запуск | конструктор).
Project Explorer (окно проекта)	Отображает Окно проекта (Project Explorer); так же, как команда View | Project Explorer) (вид | окно проекта).
Properties Window (окно свойств)	Отображает Properties Window (окно свойств); так же, как команда View | Properties Window (вид | окно свойств).
Object Browser (просмотр объектов)	Отображает диалоговое окно Object Browser (просмотр объектов); так же, как команда View | Object Browser (вид | просмотр объектов).
Toolbox (панель элементов)	Отображает Toolbox (панель элементов); так же, как команда View | Toolbox (вид | панели элементов).
Office Assistant (помощник по Office)	Отображает окно Справочной системы Microsoft Office для контекстно-зависимой подсказки по текущей задаче.
Cursor position (положение курсора)	Эта область панели инструментов Standard, фактически, не является командной кнопкой и появляется только тогда, когда курсор находится в Code Window. Эта область показывает, в какой строке модуля и в каком столбце строки находится курсор вставки.
More Buttons	Позволяет добавлять или удалять кнопки панели.
ббб
Приложение А
Таблица 2.10. Команды панели инструментов Edit
Кнопка	Действие
List Properties/Methods (список свойств/мето-дов)	Отображает раскрывающийся список свойств и мето- I дов, принадлежащих объекту, который вы только что ввели; так же, как Edit List Properties/Methods (правка | список свойств/методов).
List Constants (список констант)	Отображает раскрывающийся список предопределенных констант; так же, как Edit | List Constants (прав- ; ка | список констант).	|
Quick Info (сведения)	Отображает всплывающее окно, показывающее правильный синтаксис для объектного метода; так же, как Edit | Quick Info (правка | сведения).
Parameter Info (параметры)	Отображает всплывающее окно, показывающее параметры (называемые также аргументами [arguments]) функции или оператора VBA; так же, как Edit | Parameter Info (правка | параметры).
Complete Word (завершить слово)	Завершает текущее ключевое слово VBA, как только вы введете достаточно символов, чтобы VBA идентифицировал слово, которое вы вводите; так же, как Edit | Complete Word) (правка | завершить слово).
Indent (увеличить отступ)	Сдвигает выделенный текст вправо на одну позицию табуляции; так же, как Edit | Indent (правка | увеличить отступ).
Outdent (уменьшить отступ)	Сдвигает выбранный текст влево на одну позицию табуляции; так же, как Edit | Outdent (правка | уменьшить отступ).	I
Toggle Breakpoint | (точка останова)	Устанавливает или отменяет точку прерывания в исходном коде VBA; так же, как Debug | Toggle Breakpoint (отладка | точка останова).
Comment Block (закомментировать блок)	Превращает выделенный блок текста в Code Window в комментарии, добавляя символ комментария в начало каждой выделенной строки. Эквивалентной команды меню не имеется.
Uncomment Block (раскомментировать блок)	Удаляет символ комментария из блока выделенного текста в Code Window. Эквивалентной команды меню нет.
Toggle Bookmark (закладка)	Устанавливает или отменяет закладку в вашем исход- ; ном коде VBA; так же, как Edit | Bookmarks | Toggle Bookmark (правка | закладки | закладка).
Next Bookmark (следующая закладка)	Перемещает курсор вставки в Code Window к следую- ' щей закладке; так же, как Edit | Bookmarks | Next Bookmark (правка | закладки | следующая закладка).
Previous Bookmark (предыдущая закладка)	Перемещает курсор вставки в Code Window к предыдущей закладке; так же, как Edit | Bookmarks | Previous । Bookmark (правка | закладки | предыдущая закладка).
Clear All Bookmarks (снять все закладки)	Удаляет все закладки в модуле; так же, как Edit | Bookmarks | Clear All Bookmarks (правка | закладки |	 снять все закладки).
Справочные таблицы книги
667
Таблица 4.1. Типы данных VBA
Название типа	Размер в байтах	Описание и диапазон значения
Byte	1	Для хранения положительного числа от 0 до 255.
Boolean	2	Для хранения логическиих значений; может содержать только значения True или False
Currency	8	От -922337203685477.5808 до 922337203685477.5807.
Date	8	Для хранения комбинации информации о дате и времени. Диапазон дат может быть от 1 января 100 года до 31 декабря 9999 года. Диапазон времени от 00:00:00 до 23:59:59.
Decimal	12	Переменные типа Decimal сохраняются как 96-битовые знаковые целые, масштабируемые значением некоторой степени числа 10. Степень десяти определяет число десятичных знаков справа от десятичной точки и может быть в диапазоне от 0 до28. Если степень масштабного коэффициента равна 0, наибольшее число типа Decimal может быть равно ±79,228,162,514,264,337,593,543,950,335. Для степени 28 наибольшее число: ±7.9228162514264337593543950335, а самое меньшее ненулевое значение равно ±0.0000000000000000000000000001.
Double	8	Отрицательные числа: рт -1.79769313486232Х10308 до -4.94065645841247Х Ю”324. Положительные числа: от 4.94065645841247Х Ю 324 до 1.79769313486232Х Ю308.
Integer	2	Все целые числа от -32768 до 32767.
Long	4	Все целые числа от -2147483648 до 2147483647.
Object	4	Используется для доступа к любому объекту, распознаваемому VBA. Сохраняет адрес объекта в памяти.
Single	4	Отрицательные числа: от -3.402823Х1038 до -1.401298х 10~45 Положительные числа: от 1.401298Х10-45 до 3.402823Х1038
String (переменной длины)	10 байт + длина строки	Используется для хранения текста. Может содержать от 0 символов до (приблизительно) 2 миллиардов символов.
String (фиксированной длины)	Длина строки (один байт на один символ)	Используется для хранения текста. Может содержать от одного до (приблизительно) 654000 символов.
668
Приложение А
Название типа	Размер в байтах	Описание и диапазон значения
Variant	16 байт, «плюс» 1 байт/ символ	Тип Variant может хранить любой другой тип данных. Диапазон для данных типа Variant зависит от фактически сохраняемых данных. В случае текста диапазон соответствует строковому типу; в случае чисел диапазон такой, как у типа Double.
Таблица 4.2. Символы определения типа
Символ определения	Тип
!	Single
@	Currency
#	Double
$	String
%	Integer
&	Long
Таблица 5.1. Знаки (обозначения) операций, используемые в арифметических VBA-выражениях
Знак	Синтаксис	Имя/Описание
+	Nl + N2	Сложение. Прибавляет Nl к N2.
-	Nl - N2	Вычитание. Вычитает N2 из N1.
*	Nl * N2	Умножение. Умножает N1 на N2.
/	Nl/ N2	Деление. Делит N1 на N2.
\	Nl\ N2	Целочисленное деление. Делит N1 на N2, отбрасывая любую дробную часть так, чтобы результат был целым числом.
Mod	Nl Mod N2	Деление по модулю. Делит N1 на N2, возвращая только остаток операции деления.
	Nl " N2	Возведение в степень. Возводит N1 в степень N2.
Таблица 5.2. Знаки (обозначения) операций сравнения
Оператор	Синтаксис	Имя/описание
=	El = Е2	Равенство. True, если Е1 равно Е2, иначе — False.
<	El < Е2	Меньше, чем. True, если Е1 меньше, чем Е2, иначе — False.
<=		Меньше, чем или равно. True, если Е1 меньше или равно Е2, иначе — False.
>	>	Больше, чем. True, если Е1 больше, чем Е2, иначе — False.
Справочные таблицы книги
669
Оператор	Синтаксис	Имя/описание
>=	>=	Больше, чем или равно. True, если Е1 больше или равно Е2, иначе — False.
<>	о	Не равно. True, если Е1 не равно Е2, иначе — False.
Is	El Is Е2	Оба операнда должны быть значениями типа Object. True, если El ссылается на тот же самый объект, что и Е2, иначе — False.
Like	El Like Е2	Подобие. Оба операнда должны быть значениями типа String. True, если El совпадает с образцом, содержащимся в Е2, иначе — False.
Таблица 5.3. Символы совпадения с образцом для оператора Like
Символ образца	Соответствие
#	Любая одиночная цифра от 0 до 9.
*	Любое количество символов в любой комбинации или отсутствие символов.
?	Любой одиночный символ.
[list]	list — это список определенных символов. Совпадение с любым одиночным символом в списке.
[Hist]	list — это список определенных символов. Совпадение с любым одиночным символом, не имеющимся в списке.
Таблица 5.4. Логические операторы
Оператор	Синтаксис	Имя/Описание
And	El And E2	Конъюнкция. True, если оба Е1и Е2 имеют значение True, иначе — False.
Or	El Or E2	Дизъюнкция. True, если одно выражение или оба (Е1 и Е2) являются равными True; иначе — False.
Not	Not El	Отрицание. True, если Е1 имеет значение False; False, если El является равным True.
Xor	El Xor E2	Исключение. True, если Е1 является равным True или Е2 является равным True; иначе — False.
Eqv	El Eqv E2	Эквивалентность. True, если Е1 имеет то же самое значение, что и Е2; иначе — False.
Imp 1 		El Imp E2	Импликация. False, когда Е1 является равным True и Е2 равно False; иначе — True.
Таблица 5.5. Иерархия операторов от наивысшего до самого низкого приоритета
Оператор	Комментарии
А	Возведение в степень, наивысший приоритет.
	Унарный минус.
670
Приложение А
Оператор	„	Ii Комментарии
*, /	Умножение и деление имеют равные приоритеты; они вычисляются по мере появления в выражении слева направо.
\	
Mod	
+, -	Сложение и вычитание имеют равный приоритет; они вычисляются по мере появления в выражении слева направо.
&	Всякая конкатенация строк выполняется после любых арифметических операций в выражении и перед любыми операциями сравнения или логическими операциями.
>=, Like=, о, Is	Все операторы сравнения имеют равные приоритеты и вычисляются по мере появления в выражении слева направо. Используйте круглые скобки для группирования операторов сравнения в выражениях.
Not	
And	
Or	
Xor	
Eqv	
Imp	
Таблица 6.1. Аргументы-константы функции MsgBox
Константа	Назначение
I vbAbortRetrylgnore	Отображает командные кнопки Стоп, Повтор, Пропустить (Abort, Retry, Ignore).
vbApplicationModal	Для продолжения работы с приложением пользователь должен ответить на запрос (или закрыть) этого диалогового окна. Любые другие приложения Windows, работающие в фоновом режиме, продолжают выполняться.
vbCritical	Отображает в диалоге значок критического предупредительного сообщения (Critical Message) Windows (красный кружок).
vbDefaultButtonl	Первая командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbDefaultButton2	Вторая командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbDefaultButton3	Третья командная кнопка в диалоговом окне является кнопкой по умолчанию.
vbDefaultButton4	Четвертая командная кнопка в диалоговбм окне является кнопкой по умолчанию.
| vbExclamation	Отображает значок ("I") предупреждения (Warning Message); обычно используется для отображения важной информации или предупреждения, не требующего ответа.
Справочные таблицы книги
671
Константа	Назначение
vblnformation	Отображает значок ("I") информации (InFormation Message); обычно используется для отображения важной информации, кроме предупреждения.
vbMsgBoxHelpButton	Добавляет к диалоговому окну кнопку Справка (Help); при щелчке на кнопке Справка открывается файл, который задан в аргументе HelpFile, в разделе, заданном аргументом Context.
vbOKCancel	Отображает кнопки ОК и Отмена (OK, Cancel).
vbOKOnly	Отображает только кнопку ОК; то же самое происходит при опускании аргумента Buttons.
vbQuestion	Отображает значок запроса (Query icon) Windows (“?”); обычно используется, чтобы задать пользователю очень важный вопрос или выдать предупредительное сообщение, требующее ответа.
vbRetryCancel	Отображает кнопки Повтор и Отмена (Retry, Cancel).
vbSystemModal	При отображении диалоговое окно остается впереди других окон (даже при переключении на другое приложение), пока не будет закрыто.
vbYesNo	Отображает кнопки Да и Нет (Yes, No).
vbYesNoCancel	Отображает кнопки Да, Нет и Отмена (Yes, No, Cancel).
Таблица 6.2. Возвращаемые значения-константы функции MsgBox
Константа	Что означает
vbAbort	Пользователь выбирает кнопку Стоп (Abort)
vbCancel	Пользователь выбирает кнопку Отмена (Cancel)
vblgnore	Пользователь выбирает кнопку Пропустить (Ignore)
vbNo	Пользователь выбирает кнопку Нет (No)
vbOK	Пользователь выбирает кнопку ОК
vbRetry	Пользователь выбирает кнопку Повтор (Retry)
vbYes	Пользователь выбирает кнопку Да (Yes)
Таблица 6.3. Математические функции VBA
[функции | (аргументы)	Возвращает/действие
Abs(N)	Возвращает абсолютное значение N.
Atn(N)	Возвращает арктангенс N как угол в радианах.
Cos(N)	Косинус угла N, где N — это угол, измеренный в радианах.
Exp(N)	Возвращает константу е, возведенную в степень N. (е — это основание натуральных логарифмов и она (приблизительно) равна 2,718282).
672
Приложение А
Функции (аргументы)	Возвращает/действие
Fix(N)	Возвращает целую часть N. Fix не округляет число, а отбрасывает любую дробную часть. Если N является отрицательным, Fix возвращает ближайшее отрицательное целое большее, чем или равное N.
Int(N)	Возвращает целую часть N. Int не округляет число, а отбрасывает любую дробную часть. Если N является отрицательным, Int возвращает ближайшее отрицательное целое меньшее, чем или равное N.
Log(N)	Возвращает натуральный логарифм N.
Rnd(N)	Возвращает случайное число; аргумент является необязательным. Используйте функцию Rnd только после инициализации VBA-генератора случайных чисел оператором Randomize.
Sgn(N)	Возвращает знак числа: -1, если N — отрицательное; 1, если N — положительное; 0, если N равно 0.
Sin(N)	Возвращает синус угла; N — это угол, измеренный в радианах.
Sqr(N)	Возвращает корень квадратный из N. VBA отображает ошибку времени исполнения, если N — отрицательное.
Tan(N)	Возвращает тангенс угла; N — угол в радианах.
Таблица 6.4. Функции преобразования данных
Функция (Аргументы)	Возвращает/действие
Asc(S)	Возвращает число кода символа, соответствующее первой букве строки S. Буква "А", например, имеет код символа 65.
Chr(N)	Возвращает строку из одного символа, соответствующего коду символа N, который должен быть числом между 0 и 255, включительно. Код символа 65, например, возвращает букву "А".
Format(E, S)	Возвращает строку, содержащую значение, представленное выражением Е, в формате в соответствии с инструкциями, содержащимися в S.
Hex(N)	Возвращает строку, содержащую шестнадцатиричное представление N.	[
Oct(N)	Возвращает строку, содержащую восьмиричное представление N.
RGB(N, N, N)	Возвращает целое типа Long, представляющее значение основных цветов изображения. N в каждом аргументе должно быть целым в диапазоне 0 — 255, включительно. Аргументы (слева направо) — это значения для красного, зеленого и синего цвета.
Str(N)	Возвращает строку, эквивалентную численному выражению N.
Val(S)	Возвращает численное значение, соответствующее числу, представленному строкой S, которая должна содержать только цифры и одну десятичную точку, иначе VBA не может преобразовать ее в число. Если VBA не может преобразовать строку в S, то функция Vai возвращает 0.
Справочные таблицы книги
673
Функция (Аргументы)	Возвращает/действие
CBool(N)	Возвращает Boolean-эквивалент численного выражения N.
CByte(E)	Возвращает численное значение типа Byte (от 0 до 255); Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CCur(E)	Возвращает численное значение типа Currency; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CDate(E)	Возвращает значение типа Date. Е может быть любым допустимым выражением (строкой или числом), представляющим дату в диапазоне 1/1/100 — 12/31/9999, включительно.
CDbl(E)	Возвращает численное значение типа Double; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
Cint(E)	Возвращает численное значение типа Integer; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CLng(E)	Возвращает численное значение типа Long; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CSng(E)	Возвращает численное значение типа Single; Е — любое допустимое численное или строковое выражение, которое может быть преобразовано в число.
CStr(E)	Возвращает значение типа String; Е — любое допустимое численное или строковое выражение.
CVar(E)	Возвращает значение типа Variant; Е — любое допустимое численное или строковое выражение.
Таблица 6.5. Функции даты и времени
Функции (аргументы)	Возвращает/действие
Date	Возвращает системную дату. Можно также использовать эту функцию как процедуру для установки системных часов компьютера. Больше информации можно получить в справочной системе VBA.
Time	Возвращает системное время компьютера как значение типа Date. Можно также использовать эту функцию как процедуру для установки системных часов. Больше информации можно получить в справочной системе VBA.
Now	Возвращает системную дату и время.
Year(D)	Возвращает целое, являющееся частью выражения типа Date и содержащее год. Год возвращается как число между 100 и 9999.
Month(D)	Возвращает целое, являющееся частью выражения типа Date и содержащее месяц. Месяц возвращается как число между 1 и 12, включительно.
22 Программирование на VBA 2002
674
Приложение А
1 Функции (аргументы)	Возвращает/действие
Day(D)	Возвращает целое, являющееся частью выражения типа Date и содержащее день. День возвращается как число между 1 и 31, включительно.
Weekday(D)	Возвращает целое, содержащее день недели для выражения типа Date. День недели возвращается как число между 1 и 7, включительно; 1 — это воскресенье, 2 — понедельник и так далее.
Hour(D)	Возвращает целое, содержащее часы как часть времени, содержащегося в выражении типа Date. Часы возвращаются как число между 0 и 23, включительно. Если выражение D не содержит значения времени, то Hour возвращает 0.
Minute(D)	Возвращает целое, содержащее минуты как часть времени в выражении типа Date. Минуты возвращаются как число между 0 и 59, включительно. Если выражение D не содержит значения времени, Minute возвращает 0.
Second(D)	Возвращает целое, содержащее секунды как часть времени в выражении типа Date. Секунды возвращаются как число между 0 и 59, включительно. Если выражение D не содержит значения времени, Second возвращает 0.
DateAdd(S, N, D)	Возвращает Variant-значение, содержащее дату, к которой добавлен некоторый временной интервал.
DateDiff(S, DI, D2 [,D3[,D4]])	Возвращает число временных интервалов между двумя заданными датами.
DatePart(S, D1[,D2[,D3]])	Возвращает указанную часть заданной даты.
DateSerial(Nl, N2, N3)	Возвращает значение последовательной даты для заданной даты. Слева направо аргументы представляют год, месяц и день. Аргумент года должен быть целым числом между 100 и 9999, месяца — между 1 и 12, дня — между 1 и 31 (все диапазоны являются включающими).
DateValue(E)	Возвращает значение типа Date, эквивалентное дате, заданной аргументом Е, который должен быть строкой, числом или константой, представляющей дату.
TimeSerial (Nl, N2, N3)	Возвращает значение последовательного времени. Слева направо аргументы представляют часы, минуты и секунды. Аргумент часов должен быть целым числом между 0 и 23, аргументы минут и секунд должны оба быть числами 0 и 59 (все диапазоны являются включающими).
TimeValue(E)	Возвращает значение типа Date, содержащее время, заданное аргументом Е, который может быть строкой, числом или константой, представляющей время.
Timer	Возвращает число, представляющее количество секунд от полуночи в соответствии с системным временем компьютера.
Справочные таблицы книги
675
Таблица 6.6. Строковые функции
Функция (аргумент)	Возвращает/действие
InStr([Nl,] SI, S2[, N2])	Возвращает положение S2 в SI. Nl — начальное положение для поиска; N2 определяет тип сравнения. N1 и N2 необязательны. Если N2 опускается, то для поиска используется текущая установка Option Compare.
InStrRev(Sl, S2 [, Nl[, N2]])	Возвращает позицию появления строки S2 внутри S1, в направлении от конца (или N1) к началу строки. N2 определяет тип сравнения. Если N2 опускается, то для поиска используется текущая установка Option Compare.
Lcase(S)	Возвращает строку (тип String), содержащую копию S со всеми символами верхнего регистра, преобразованными в символы нижнего регистра.
Left(S, N)	Возвращает строку; копирует N символов из S, начиная с левого крайнего символа S.
Len(S)	Возвращает число символов в S, включая начальные и конечные пробелы.
Ltrim(S)	Возвращает копию строки S после удаления символов пробела из левой части строки (начальные пробелы).
Mid(S, Nl, N2)	Возвращает строку; копирует N2 символов из S, начиная с позиции символа в S, заданной аргументом Nl. N2 является необязательным; если N2 опущен, то Mid возвращает все символы в строке S от позиции N1 до конца строки.
Right(S, N)	Возвращает значение типа String; копирует N символов из S, начиная с правого крайнего символа S. Например, Rightf’outright", 5) возвращает строку "right".
Rtrim(S)	Возвращает копию строки S после удаления символов пробела из правой части строки (конечные символы).
Space(N)	Возвращает строку пробелов длиной N символов.
StrComp(Sl, S2, N)	Сравнивает SI с S2 и возвращает число, обозначающее результат сравнения: -1, если SI < S2; 0, если SI = S2; 1, если S1 > S2. N является необязательным и указывает, следует ли выполнять сравнение с учетом регистра. Если N опускается, строки сравниваются с использованием текущей установки Option Compare.
StrConv(S, N)	Возвращает строку, преобразованную в новую форму в зависимости от числового кода, заданного аргументом N. VBA предоставляет внутренние константы для использования с функцией StrConv; наиболее полезными являются: vbProperCase (преобразует строку так, что каждая буква, начинающая слово, становится заглавной), vbLowerCase (преобразует строку в буквы нижнего регистра) и vbUpperCase (преобразует строку в буквы верхнего регистра).
String(N, S)	Возвращает строку длиной N символов, состоящую из символа, заданного первым символом в S. Например, String (5, "х") возвращает строку "ххххх".
22*
676
Приложение А
Функция (аргумент)	Возвращает/действие
Trim(S)	Возвращает копию строки S после удаления начальных и конечных символов пробела из этой строки.
Ucase(S)	Возвращает S со всеми символами нижнего регистра, преобразованными в символы верхнего регистра.
Таблица 6.7. Именованные форматы для использования с функцией Format
Именованный формат	Действие
General Date	Форматирует информацию о дате и времени в последовательное число даты, используя установки формата даты и времени для вашего компьютера. То же, что VBA-преобразование по умолчанию последовательных дат в строки.
Long Date	Форматирует в последовательной дате только часть, содержащую дату, используя установки компьютера для Long-формата даты.
Medium Date	Форматирует в последовательной дате только часть, содержащую дату, используя установки компьютера для Medium-формата даты.
Short Date	Форматирует в последовательной дате только часть, содержащую дату, используя установки компьютера для Short-формата даты.
Long Time	Форматирует в последовательной дате только часть, содержащую время, используя установки компьютера для Long-формата времени.
Medium Time	Форматирует в последовательной дате только часть, содержащую время, используя установки компьютера для Medium-формата времени.
Short Time	Форматирует в последовательной дате только часть, содержащую время, используя установки компьютера для Short-формата времени.
General Number	Форматирует число в строку без каких-либо особых символов. Действие такое же, как VBA-преобразование по умолчанию чисел в строки.
Currency	Форматирует число с символом денежной единицы, разделителем тысяч и только двумя десятичными разрядами. Символ денежной единицы и десятичный разделитель определяются локальными установками Windows.
Fixed	Форматирует число так, чтобы всегда была, по крайней мере, одна цифра перед десятичным разделителем и, по крайней мере, две цифры после него.
Standard	Форматирует число с разделителем тысяч так, чтобы была, по крайней мере, одна цифра перед десятичным разделителем и, по крайней мере, две цифры после него.
Справочные таблицы книги
677
Именованный формат	Действие
Percent	Форматирует число как процентное отношение, умножая его на 100 и добавляя символ процента. Например, 0.21 возвращается как 21%.
Scientific	Форматирует Число в обычный экспоненциальный формат.
Yes/No	Использование этого формата приводит к тому, что функция Format возвращает строку "Да" ("Yes”), если форматируемое число ненулевое, и возвращает строку "Нет" ("No") для любого нулевого значения. Этот именованный формат наиболее часто используется со значениями типа Boolean.
True/False	Использование этого формата приводит к тому, что функция Format возвращает строку "Истина" ("True"), если форматируемое число ненулевое, и строку "Ложь" ("False") для любого нулевого значения. Этот именованный формат наиболее полезен со значениями типа Boolean.
On/Off	Использование этого формата приводит к тому, что функция Format возвращает строку "Вкл" ("On”), если форматируемое число ненулевое, и строку "Выкл" ("Off”) для любого нулевого значения. Наиболее часто используется со значениями Boolean.
Таблица 6.8. Символы-заполнители для создания пользовательских форматов
Символ-заполнитель	Действие
0	Цифровой символ, отображает цифру, если таковая находится в этой позиции, или 0, если — нет. Можно использовать символ 0 для отображения начальных нулей для целых чисел и конечных нулей в десятичных дробях; 00000.000 отображает 1234,5 как 01234,500.
#	Цифровой символ, отображает цифру, если таковая находится в этой позиции, иначе — не отображает ничего. Символ-заполнитель # эквивалентен 0, кроме того, что начальные и конечные нули не отображаются; #####.### отображает 1234,5 как 1234,5.
$	Отображает знак доллара; $###,###.00 отображает 1234,5 как $1 234,50.
	Десятичный символ-заполнитель, отображает десятичную точку в обозначенной позиции в строке символов-заполнителей 0; #.##.## отображает 1234,5 как 1234,5.
%	Символ процента, умножает значение на 100 и добавляет знак процента в позицию, указанную символами-заполнителями 0; #.#0.00% отображает число 0.12345 как 12,35% (12,345 округляется до 12,35).
, (запятая)	Разделитель тысяч, добавляет запятые как разделители тысяч в строках символов-заполнителей 0 и #; ###,###,###.00 отображает 1234,5 как 1 234,50.
Е-, е-	Отображает значения в экспоненциальном формате со знаком порядка только для отрицательных значений; #.####Е—00 отображает 1,2345Е03; 0,12345 отображается как 1.2345Е-01.
678
Приложение А
Символ-заполнитель	Действие
Е+, е+	Отображает значения в экспоненциальном формате со знаком порядка для положительных и отрицательных значений; #.####Е+00 отображает 1234,5 как 1,2345Е+03.
/	Отделяет день, месяц и год для форматировайия значений дат. mm/dd/yy отображает 06/06/97. Символы "/” можно заменять на символы дефиса для отображения как 06-06-97.
m	Указывает, как отображать месяцы в датах; ш отображает 2, mm — 02, mmm — фев, mmmm — Февраль.
d	Указывает, как отображать дни в датах; d отображает 1, dd отображает 01, ddd — Пт, dddd — пятница.
У	Отображает день года как число от 1 до 366.
УУ	Указывает, как отображать годы в датах; уу отображает 99, УУУУ — 1999.
q	Отображает квартал года как число от 1 до 4.
W	Отображает день недели как число (1 — это воскресенье).
WW	Отображает неделю года как число от 1 до 54.
:(двоеточие)	Отделяет часы, минуты и секунды в значениях формата времени; hh:mm:ss отображает 02:02:02.
h	Указывает, как отображать часы; для значения времени 02:01:38 h отображает 2, hh отображает 02.
И	Минутный символ-заполнитель для времени; для значения времени 02:01:08 п отображает 1, а пп отображает 01.
S	Секундный символ-заполнитель для времени; для значения времени 02:01:08 s отображает 8, и ss отображает 08.
АМ/РМ	Отображает время в 12-часовом формате времени с добавленными AM и PM; h:nn АМ/РМ отображает 4:00 РМ. Альтернативные форматы включают am/pm, А/P и а/р.
@	Символьный заполнитель, отображает пробел, если не имеется соответствующего символа в форматируемой строке. @@@@ отображает строку Hi с двумя начальными пробелами, (порядок заполнения по умолчанию — справа налево).
<	Отображает все символы в верхнем регистре.
>	Отображает все символы в нижнем регистре.
Таблица 10.1. Общие объекты Excel 2000
Объект	Описание
Application	Само приложение Excel 2000 (host-приложение).
Chart	Диаграмма в рабочей книге.
Font	Этот объект содержит атрибуты шрифта и стиля для текста, отображаемого в рабочем листе.
Name	Заданное имя для диапазона ячеек рабочего листа.
Справочные таблицы книги
679
Объект	Описание
Range	Диапазон ячеек (одна или более) или именованный диапазон в рабочем листе.
Window	Любое окно в Excel; окна используются для отображения рабочих листов, диаграмм и т.д.
Workbook	Открытая рабочая книга.
Worksheet	Рабочая таблица в книге.
Таблица 10.2. Общие объекты Word 2000
Объект	Описание
Application	Само приложение Word 2000 (host-приложение).
Bookmark	Отдельная закладка в документе.
Document	Открытый документ.
Font	Содержит атрибуты шрифта и стиля для текста, отображаемого в объекте.
Paragraph	Отдельный параграф в документе.
Range	Непрерывная область в документе.
Style	Встроенный или определенный пользователем форматирующий стиль в документе.
Table	Отдельная таблица в документе.
TableOf- Contents	Отдельная таблица содержания документа.
Template	Шаблон документа.
Window	Любое окно в Windows.
Таблица 10.3. Наиболее употребительные свойства объектов в Excel 2000
Свойство	Тип/Что означает	Где найти
ActiveCell	Object: активная ячейка в рабочем листе	Application, Window
ActiveChart	Object: активная диаграмма	Application, Window, Workbook
ActiveSheet	Object: активный лист	Application, Window, Workbook
Address	Возвращает координаты ячейки указанного объекта	Range
Cells	Диапазон объекта Range	Application, Range, Worksheet
Charts	Коллекция диаграмм	Application, Workbook
Count	Integer: число объектов в коллекции	Все объекты коллекции
680
Приложение А
Свойство	Тип/Что означает	Где найти
Fofmula	String: формула для ячейки рабочего листа	Диапазон
Index	Integer: число объектов в коллекции	Worksheet
Name	String: имя объекта	Application, Workbook и- в других объектах
Path	String: драйвер и каталог, в котором сохранен объект	Addin, Application, Workbook
Saved	Boolean: сохранялась ли рабочая книга после последних изменений	Workbook
Selection	Object: текущий выделенный фрагмент	Application, Window
Sheets	Коллекция листов рабочей книги	Application, W orkbook
StatusBar	String: сообщение в статусной строке	Application
ThisWorkBoo k	Object: рабочая книга, из которой выполняется текущая процедура	Application
Type	Integer: число, указывающее тип объекта	Window, Worksheet, Chart
Visible	Boolean: отображается или нет объект на экране	Application, Worksheet, Range и в других объектах
Value	(варьируется): действительное значение, отображаемое в ячейке	Range
Workbooks	Коллекция рабочих книг	Application
Worksheets	Коллекция рабочих листов	Application, W orkbook
Таблица 10.4. Употребительные и полезные свойства объектов Word 2000
Свойство	Тип/Значение	Имеется в объектах
ActiveDocument	Object: активный документ	Application
ActivePrinter	String: имя активного принтера	Application
ActiveWindow	Object: активное окно	Application, Document
Count	Long: число объектов в коллекции	Во всех объектах коллекций
Name	String: имя объекта	Application, Bookmark, Dictionary, Document и в других
Path	String: драйвер и путь к папке, в которой сохранен объект	Addin, Application, Dictionary, Document и в других ,
Range	Object: часть документа, содержащаяся в указанном объекте	Bookmark, Paragraph, Selection, Table и в других
Saved	Boolean: был ли сохранен текст после последнего изменения	Document, template
Справочные таблицы книги
681
Свойство	Тип/Значение	Имеется в объектах
Selection	Object: текущий выделенный фрагмент	Application, Pane, Window
StatusBar	String; сообщение строки состояния	Application
Visible	Boolean: отображается объект на экране или нет	*	Application, Border
Таблица 10.5. Общеупотребительные и полезные методы объектов Excel 2000
Метод	Назначение	Имеется в объектах
Activate	Активизирует объект	Window, Workbook, Worksheet, Range и в других объектах
Calculate	Выполняет вычисления в открытой рабочей книге, рабочем листе или диапазоне	Application, Range, Worksheet
Clear	Удаляет данные, сохраненные в указанном объекте	Range
Close	Закрывает указанный объект	Window, Workbook, Workbooks
Justify	Выравнивает текст, сохраненный в указанном объекте	Range
Run	Выполняет указанную процедуру или функцию	Application, Range
Save	Сохраняет файл рабочей книги	Application, Workbook
SaveAs	Сохраняет указанный объект в другом файле	Workbook, Worksheet
Select	Выбирает указанный объект	Range, Sheets, Worksheets
SendKeys	Пересылает нажатия клавиши в диалоговые окна в host-приложении	Application
Volatile	Регистрирует функцию как изменяющуюся (см. гл. 6)	Application
Таблица 10.6. Наиболее употребительные и полезные методы объектов Word 2000
Метод	Назначение	Имеется в этих объектах
Activate	Активизирует объект	Window, Document, Pane и в других объектах
CheckSpelling	Проверяет орфографию указанного документа или диапазона	Document, Range
Close	Закрывает указанный объект	Window, Document
682
Приложение А
Метод	Назначение	Имеется в этих объектах
Delete	Удаляет указанный объект или удаляет символы и слова	Bookmark, Range и в других объектах
GoTo	Перемещает курсор в начальное положение элемента, такого как страница, закладка или иоле; возвращает объект Range	Document, Range, Selection *
Printout	Печатает указанный объект	Application, Document, Envelope, Window
Run	Выполняет указанную процедуру или функцию	Application
Save	Сохраняет указанный объект	Document, Template
SaveAs	Сохраняет документ в другом файле	Document
Select	Выбирает указанный объект	Bookmark, Document, Field и в других объектах
Таблица 10.7. Общие коллекции Excel 2000
Коллекция	Назначение
Addins	Коллекция надстроек приложения.
Charts	Коллекция всех таблиц (Chart sheets) в рабочей книге.
ChartObjects	Коллекция всех объектов Chart в рабочем листе.
Dialogs	Коллекция всех диалогов в приложении.
Windows	Коллекция всех окон в приложении, независимо от того, отображается ли окно на экране.
Workbooks	Коллекция всех открытых в данных момент рабочих книг в приложении.
Worksheets	Коллекция всех рабочих листов в рабочей книге.
Таблица 10.8. Общие коллекции Word 2000
Коллекция	Назначение
Addins	Коллекция надстроек приложения.
Bookmarks	Коллекция всех закладок в документе, разделе или диапазоне (в зависимости от контейнера).
Characters	Коллекция всех символов в документе, разделе или диапазоне (в зависимости от контейнера). Каждый элемент в коллекции Characters является объектом Range, содержащим один символ.
Comments	Коллекция всех комментариев документа.
Dialogs	Коллекция диалогов приложения.
Documents	Коллекция всех открытых в данный момент документов.
Справочные таблицы книги
683
Коллекция	Назначение
Paragraphs	Коллекция объектов Paragraph в документе, разделе или диапазоне (в зависимости от контейнера).
Sections	Коллекция разделов в документе, разделе или диапазоне (в зависимости от контейнера).
Styles	Коллекция описаний стилей в документе для встроенных	, и определенных пользователем стилей.
Templates	Коллекция всех шаблонов приложения.
Windows	Коллекция всех окон в приложении или коллекция всех окон (отображающих документ в зависимости от контейнера).
Таблица 13.1. Функции, методы и операторы управления файлами
Имя	Категория	Назначение
ChDir	Оператор	Изменяет текущий каталог (папку).
ChDrive	Оператор	Изменяет текущий драйвер диска.
CurDir	Функция	Возвращает текущий каталог (папку).
Dir	Функция	Возвращает имя каталога или файла, совпадающее с определенным именем файла (включая символы универсального сопоставления), передаваемым как строковый аргумент. Предназначена для нахождения одного или нескольких файлов на диске.
FileCopy	Оператор	Копирует файл.
FileDateTime	Функция	Возвращает значение типа Date, содержащее дату и время, когда этот файл был изменен последний раз.
FileLen	Функция	Возвращает длину файла в байтах.
GetAttr	Функция	Возвращает число, представляющее объединенные атрибуты файла или каталога диска, такие как System, Hidden и так далее.
GetOpenFile-Name	Метод	Отображает Excel-диалоговое окно Open и возвращает имя файла, выбранное пользователем. В Word не имеется.
GetSaveAsFile-Name	Метод	Отображает Excel-диалоговое окно (Save As) и возвращает имя файла, выбранное пользователем. В Word не имеется.
Kill	Оператор	Удаляет файлы с диска.
MkDir	Оператор	Создает каталог диска (папку).
Name	Оператор	Переименовывает или перемещает файл.
RmDir	Оператор	Удаляет каталог диска (папку).
SetAttr	Оператор	Устанавливает атрибуты файла.
684
Приложение А
Таблица 13.2. Константы атрибутов файла Visual Basic for Applications
Константа VBA	Значение	Что означает
vbNormal	0	Normal
vbReadOnly	1	Read-Only
vbHidden	2	Hidden
vbSystem	4	System
vbVolume	8	Volume Label
vbDirectory	16	Каталог или подкаталог диска.
vbArchive	32	Archive. Если установлен, указывает, что этот файл был изменен со времени последнего резервирования.
vbAlias	64	Указанное имя файла является алиасным. Доступна только в Macintosh.
Таблица 13.3. Возвращаемые значения метода Display
Числовое значение	Что означает
-2	Диалоговое окно было закрыто с помощью кнопки Close (Закрыть).
-1	Диалоговое окно было закрыто щелчком кнопки ОК или эквивалентной ей (Open (Открыть) в диалоговых окнах wdDialogFileOpen и wdDialogFileSaveAs).
°	Диалоговое окно было отменено.
> 0	Командная кнопка; 1 — для первой командной кнопки, 2 — для второй и так далее.
Таблица 14.1. Наиболее часто используемые свойства объектов UserForm
Свойство	Описание
ActiveControl	Возвращает объектную ссылку на элемент управления, находящийся в фокусе в данный момент. Только для чтения.
BackColor	Целое типа Long определяет цвет фона формы. Самый простой способ установить это свойство — использовать Properties Window; чтобы выбрать желаемый цвет (если необходимо), можно скопировать номер цвета из Properties Window в свою программу.
Caption	Текст, выводимый в качестве заголовка формы. Запись/Чтение.
Controls	Возвращает коллекцию всех элементов управления формы. Только для чтения.
Cycle	Определяет, должно ли нажатие клавиши табуляции вызывать последовательный выбор всех элементов управления во всех группах и на каждой странице многостраничных элементов управления или только в пределах текущей группы или страницы. Может содержать одну из двух встроенных констант: fmCycleAllForms или fmCycleCurrentForm. Чтение/Запись.
Справочные таблицы книги
685
Свойство	Описание
Enabled	Содержит значение типа Boolean, указывающее, доступна ли форма. Если его значение равно False, ни один из элементов управления формы не доступен. Чтение/Запись.
Font	Возвращает ссылку на объект Font, посредством которого вы можете выбрать параметры шрифта формы или элемента управления.
ForeColor	То же самое, что и свойство BackColor, но устанавливает цвет, используемый для переднего плана (обычно — это цвет текста) объекта формы.
Таблица 14.2. Наиболее часто используемые методы для объектов UserForm
Метод	Назначение
Сору	Копирует выделенный в элементе управления текст в буфер обмена Windows.
Cut	Вырезает выделенный в элементе управления текст и помещает его в буфер обмена Windows.
Hide	Скрывает UserForm, не выгружая ее из памяти, сохраняя значения элементов управления формы и всех переменных, объявленных в модуле класса формы.
Paste	Вставляет содержимое буфера обмена Windows в текущий элемент управления.
PrintForm	Выводит на используемый в Windows по умолчанию принтер изображение формы, включая все данные, введенные в элементы управления.
Repaint	Перерисовывает форму, выведенную на экран. Используйте этот метод, если хотите перерисовать форму, не ожидая, когда она будет перерисована через обычный период времени.
Show	Выводит форму на экран. Если форма еще не загружена в память, то данный метод сначала ее загружает.
Таблица 14.3. События объектов UserForm
Событие	Синтаксис заголовка процедуры обработки события	Описание
Activate	Private Sub ob/ect_Activate()	Инициируется всякий раз, когда окно формы становится активным. Используйте это событие для обновления содержимого диалоговых элементов управления, чтобы отразить любые изменения, которые произошли, пока окно формы было неактивным.
Click	Private Sub object_Click(index As Long)	Инициируется всякий раз, когда по форме (любой ее части, не занятой элементами управления) щелкают мышью.
686
Приложение А
Событие	Синтаксис заголовка процедуры обработки события	Описание
DblClick	Private Sub ob/ect_DblClick(index As Long, By Vai Cancel As MSForms.ReturnBoolean)	Инициируется всякий раз, когда по форме (любой ее части, не занятой элементами управления) дважды щелкают мышью.
Deactivate	Private Sub obyect_Deactivate()	Инициируется всякий раз, когда форма] перестает быть активной.
Initialize	Private Sub ob/ect_Initialize()	Инициируется всякий раз, когда форма впервые загружается в память посредством выполнения оператора Load или с помощью метода Show. Используйте это событие для инициализации элементов управления формы при ее появлении на экране.
Resize	Private Sub UserF orm_Resize()	Инициируется при изменении размеров формы.
Terminate	Private Sub ob/ect_Terminate()	Инициируется всякий раз, когда форма выгружается из памяти. Используйте это событие для осуществления любых специальных служебных задач, которые необходимо выполнить прежде, чем переменные формы будут выгружены.
Таблица 14.4. Стандартные элементы управления, включенные в VBA
Элемент управления	Назначение
Label (надпись, метка)	Позволяет создавать заголовки элементов управления, которые не имеют собственных встроенных заголовков. Используйте этот элемент для того, чтобы поместить на форму статический текст, например, инструкции, советы по заполнению других диалоговых элементов управления.
TextBox (текстовое поле)	Окно редактируемого текста свободной формы для ввода дан-1 ных. Может быть одно- или многострочным.
ComboBox (поле со списком)	Этот элемент управления объединяет окно редактирования и окно списка. Используйте, когда хотите предложить пользователю выбрать значение, но при этом дать ему возможность ввести данные, отсутствующие в списке. Вы можете также ограничить выбор только теми значениями, которые появляются в ComboBox для эмуляции ниспадающего списка.
ListBox (список)	Отображает список значений, из которых пользователь может сделать выбор. Окна списка можно использовать, чтобы дать возможность пользователю выбрать только одно значение или же несколько.
CheckBox (флажок)	Стандартный флажок (квадратное окно, содержащее, если элемент выбран, «галочку»). Используйте флажки для выбора вариантов, которые не являются взаимоисключающими.
Справочные таблицы книги
687
Элемент управления	Назначение	i
OptionButton (переключатель)	Стандартная кнопка-переключатель (круглое окно, при выборе в центре него находится черная точка). Используйте OptionButton, когда пользователю необходимо сделать выбор между «включено/выключено», «истина/ложь». Кнопки-переключатели, как правило, объединяются вместе при помощи рамки для создания группы переключателей.
ToggleButton (выключатель)	Выключатели служат для той же цели, что и флажки, но выводят установки в виде кнопки находящейся в «нажатом» или «отжатом» состоянии.
Frame (рамка)	Визуально и логически объединяет некоторые элементы управления (особенно флажки, переключатели и выключатели). Используйте Frame, чтобы показать пользователю, какие элементы управления в диалоговом окне связаны между собой, или чтобы выделить группу элементов управления, отделяя ее от остальных элементов управления, находящихся в диалоговом окне.
CommandButton (кнопка)	Используйте кнопки для выполнения таких действий как Cancel (Отмена), Save (Сохранить), ОК и так далее. Когда пользователь щелкает по кнопке, выполняется VBA-процедура, закрепленная за данным элементом управления.
TabStrip (набор вкладок)	Этот элемент управления состоит из области, в которую вы помещаете другие элементы управления (такие как текстовые поля, флажки и так далее) и полосы кнопок табуляции. Используйте элемент управления TabStrip для создания диалоговых вкладок, отображающих одни и те же данные в различных категориях.
MultiPage (набор страниц)	Этот элемент управления состоит из нескольких страниц. Вы можете выбрать любую из них, щелкнув по соответствующей вкладке. Используйте элемент управления MultiPage для создания диалоговых окон с вкладками, такими, например, как диалоговое окно, появляющееся при выборе команды Tools | Options (панели инструментов | настройка).
ScrollBar (полоса прокрутки)	Элемент управления ScrollBar позволяет выбирать линейное значение, аналогично тому, как это можно сделать при помощи счетчика.
SpinButton (счетчик)	Элемент управления SpinButton является специальной разновидностью текстового поля. Обычно счетчики используются для того, чтобы ввести число, дату или какие-либо иные последовательные величины, которые заведомо находятся в опреде-
	ленном интервале значений. Щелчок по указывающей вверх стрелке счетчика увеличивает значение в окошке, а щелчок по стрелке, направленной вниз, соответственно уменьшает его.
Image (рисунок) /	Элемент управления Image позволяет вывести на форме графическое изображение. Используйте Image для вывода графических изображений в любом из следующих форматов: *.bmp, *.cur, *.gif, *.ico, *.jpg, или *.wmf. Вы можете обрезать и масштабировать графическое изображение, чтобы подобрать размер элемента Image, но только не редактировать графическое изображение. Можно даже написать специальную VBA-процедуру, выполняющуюся, если пользователь щелкнет по элементу управления Image.
688
Приложение А
Таблица 14.5. Наиболее часто используемые свойства стандартных элементов управления
Свойство	Где применяется	Описание
Accelerator	Checkbox, Tab, CommandButton, Label, Page, OptionButton, ToggleButton	Содержит символ, используемый, в качестве быстрой клавиши вызова, элемента управления. При нажатии АИ+<клавиша быстрого вызова> происходит выбор элемента управления.
BackColor	Все элементы	Число, представляющее определенный цвет фона элемента управления.
Caption	CheckBox, CommandButton, Frame, Label, OptionButton, ToggleButton, Page, Tab, UserForm	Для надписи — текст, отображаемый, элементом управления. Для других элементов управления — надпись, которая появляется на кнопке или вкладке или рядом с рамкой, флажком или переключателем.
Cancel	CommandButton	Задает кнопку отмены диалогового окна. При нажатии на эту кнопку или клавишу Esc диалоговое окно исчезает. Только одна кнопка формы может иметь данное свойство.
ControlTipText	Все элементы управления	Устанавливает текст, который отображается в виде всплывающей подсказки (ControlTip, называемой также ToolTip), когда указатель мыши помещается на элемент управления.
Default	CommandButton	Определяет заданную по умолчанию кнопку. Когда пользователь нажимает в процессе диалога клавишу Enter, эта кнопка ведет себя так, как если бы по ней щелкнули мышью.
Enabled	Все элементы управления	Хранит значение типа Boolean, определяющее доступен или нет элемент управления. Если Enabled имеет значение False, то элемент управления продолжает отображаться в диалоговом окне, но не может быть выбран.
ForeColor	Все элементы управления	То же самое, что и BackColor, но устанавливает цвет для переднего плана элемента управления, как правило, символов текста.
List	ComboBox	Массив типа Variant (одно- или многомерный), представляет список содержащийся в элементе управления. Используйте индекс Value как нижний индекс в коллекции List, чтобы получить текст для выбранного пункта списка. Используйте методы элемента управления Additem и Removeitem для добавления или удаления пунктов списка.
Справочные таблицы книги
689
Свойство	Где применяется	Описание
Мах	ScrollBar, SpinButton	Переменная типа Long, определяющая максимальное значение счетчика, или значение, при котором полоса прокрутки находится в самом верху (для вертикальной полосы) или справа (для горизонтальной).
Min	ScrollBar, SpinButton	Переменная типа Long, определяющая минимальное значение счетчика, или значение, при котором полоса прокрутки находится в самом низу (для вертикальной полосы) или слева (для горизонтальной).
Name	Все элементы управления	Содержит имя элемента управления. Вы можете установить данное свойство только с помощью Properties Window.
RowSource	ComboBox	Задает источник, из которого ListBox берет список объекта. В Excel VBA RowSource обычно использует диапазон рабочего листа.
Selected	ListBox	Возвращает массив значений типа Boolean для списка, который допускает множественный выбор. Каждый элемент массива содержит по одному элементу, соответствующему каждому пункту списка. Если значение элемента в массиве Selected равно True, то соответствующий пункт списка выбран.
Tabindex	Все элементы управления	Число, указывающее положение элемента управления в порядке табуляции (может иметь значение от 0 до значения, равного количеству элементов управления на форме).
TabStop 	Все элементы управления	Значение типа Boolean, указывающее может ли элемент управления быть выбран клавишей Tab. Если значение TabStop равно False вы, тем не менее, можете щелкнуть на элементе и таким образом его выбрать.
Value	Все элементы управления	I Значение текущих установок элемента управления: текст в текстовом поле, какие выбраны флажки и переключатели, индекс выбранного раздела списка или число, указывающее текущее положение полосы прокрутки или счетчика.
J Visible	Все элементы управления	Значение типа Boolean, указывающее, является ли элемент управления видимым.
Таблица 14.6. Наиболее часто используемые события объектов управления
Событие	Синтаксис процедуры обработки	Описание
AddControl	См. приложение Е	Инициируется всякий раз, когда к форме (или элементам Frame, Page, MultiPage) добавляется какой-либо элемент управления.
690
Приложение А
Событие	Синтаксис процедуры обработки	Описание
AfterUpdate	Private Sub object_AfterUpdate()	Инициируется после обновления значения элемента управления.
BeforeUpdate	Private Sub obj ect_BeforeUpdate( By Vai Cancel As MSForms.ReturnBoolean)	Инициируется после того, как было изменено значение элемента управления, но перед тем, как был обновлен сам элемент управления.	t
Change	Private Sub object_Change()	Инициируется всякий раз, когда изменяется значение элемента управления.
Click	Private Sub object_Click()	Инициируется всякий раз, когда по элементу управления щелкают мышью. Используйте данное событие для того, чтобы выполнить действие при помощи кнопки.
DblClick	Private Sub object_DblClick(ByVal Cancel As MSForms.ReturnBoolean)	Инициируется всякий раз, когда по элементу управления дважды щелкают мышью. Используйте данное событие для вывода дополнительных форм.
Enter	Private Sub object_Enter()	Инициируется всякий раз, когда выделяется элемент управления.
Exit	Private Sub object_Exit( ByVai Cancel As MSForms.ReturnBoolean)	Инициируется всякий раз, когда с элемента управления снимается выделение.
Error	Private Sub obj ect_Error( Index As Long, ByVai Number As integer, ByVai Description As MSForms .Returnstring)	Инициируется всякий раз, когда элемент управления обнаруживает ошибку и не может возвратить информацию об ошибке в вызывающую программу.
KeyDown	Private Sub object_KeyDown(ByVal KeyCode As MSForms.Returninteger, ByVai Shift As fmShiftState)	Инициируется при нажатии пользователем какой-либо клавиши в тот момент, когда форма выполняется и имеет фокус.
KeyPress	Private Sub object KeyPress(ByVal KeyANSI As MSForms. Returninteger)	Инициируется, когда пользователь нажимает алфавитно-цифровую клавишу.
Ke у Up	Private Sub object_KeyUp(ByVal KeyCode As MSForms. Returninteger, ByVai Shift As fmShiftState)	Инициируется, когда пользователь отпускает клавишу.
Layout	Private Sub object_Layout()	Инициируется, когда изменяются размеры элемента Frame (или MultiPage).
Справочные таблицы книги
691
Событие	Синтаксис процедуры обработки	Описание
MouseDown, MouseUp	См. приложение Е	Инициируются при щелчке мышью: MouseDown, когда пользователь нажимает на клавишу мыши; MouseUp, когда пользователь отпускает клавишу мыши.
MouseMove	См. приложение Е	Инициируется, когда пользователь перемещает мышь.
SpinDown, SpinUp	Private Sub object_SpinDown() Private Sub object_SpinUp()	Событие SpinDown инициируется, когда пользователь щелкает стрелку «вниз» (или «влево») кнопки счетчика. Событие SpinUp инициируется, когда пользователь щелкает стрелку «вверх» (или «вправо») кнопки счетчика.
Zoom	Private Sub object_Zoom(index As Long, Percent As Integer)	Инициируется при изменении свойства Zoom.
Таблица 16.1. Встроенные константы WdUnits
Константа	Описание
wdCell	Ячейка таблицы.
wdCharacter	Символ, включая скрытые и непечатаемые символы.
wdColumn	Столбец таблицы.
wdLine	Строка текста. Вы можете использовать данную константу только для аргумента Unit, если используемый метод применяется к объекту Selection.
wdParagraph	Абзац. Абзац ограничивается символом конец абзаца (1|). Символ конца абзаца не отображается на экране пока вы не щелкните кнопку Показать все символы (Show АП) панели инструментов Word.
wdRow	Строка таблицы.
wdSection	Раздел документа.
wdSentence	Предложение. Предложение ограничивается знаками пунктуации, такими как точка (.), знак вопроса (?), и восклицательный знак (!).
wdStory	Область документа.
wdTable	Таблица.
wdWord	Слово. Слово ограничено пробелами и символами пунктуации.
Таблица 16.2. Встроенные константы WdGoToItem
Константа	Описание
wdGoToBookmark	Закладка.
wdGoToField	Поле, например поле даты или номера страницы.
692
Приложение А
Константа	Описание
wdGoToHeading	Заголовок, то есть текст отформатированный с помощью одного из стилей заголовка: Заголовок!, Заголовок2 и так далее.
wdGoToLine	Строка документа.
wdGoToPage	Страница документа.
wdGoToPercent	Местоположение в документе, выраженное в процентах от длины документа.
Таблица 17.1. Типы классов для часто используемых объектов
Объект	Тип класса
1-2-3 Worksheet	123Worksheet
Приложение Microsoft Access	Access.Application.10
Приложение Microsoft Excel	Excel. Application. 10
Диаграмма Microsoft Excel	Excel.Chart
Лист Microsoft Excel	Excel.Sheet
Приложение Microsoft Graph	MSGraph .Application
Приложение MS PowerPoint	PowerPoint. Application
Приложение Microsoft Word	Word. Application. 10
Документ Microsoft Word	Word.Document
Таблица 17.2.а Значения ClassType (ClassName) для ActiveX Controls
Значение аргумента ClassType (ClassName)	Создаваемый элемент управления
Forms.Ch eckBox. 1	CheckBox
Forms.ComboBox. 1	ComboBox
Forms.CommandButton.!	CommandButton
Forms.Frame. 1	Frame
Forms.Image. 1	Image
Forms.Label.1	Label
Forms.ListBox. 1	ListBox
Forms.MultiPage.l	MultiPage
Forms.OptionButton. 1	OptionButton
Forms.ScrollBar. 1	ScrollBar
Forms.SpinButton. 1	SpinButton
Forms.TabStrip. 1	TabStrip
Forms.TexBox.l	TexBox
Forms.ToggleButton.l	ToggleButton
Справочные таблицы книги
693
Таблица 17.2.Ь Значения ClassType (ClassName) для объектов Microsoft Access
Значение аргумента ClassType (ClassName)	Создаваемый объект
Access. Application	Application
Access.CodeData, Access.CurrentDat a	CurrentData
Access. CodeProj ect, Access. CurrentPrоj ect	CurrentProject
Access.DefaultWebOptions	Def aultW ebOptions
Таблица 17.2.С Значения ClassType (ClassName) для объектов Microsoft Excel
Значение аргумента ClassType (ClassName)	Создаваемый объект
Excel. Application	Application
Excel. Addin	Workbook
Excel. Chart	Workbook
Excel.Sheet	Workbook
Таблица 17.2.d Значение ClassType (ClassName) для объекта Microsoft Outlook
Значение аргумента ClassType (ClassName)	Создаваемый объект
Outlook. Application	Application
Таблица 17.2.е Значение ClassType (ClassName) для объекта Microsoft PowerPoint
Значение аргумента ClassType (ClassName)	Создаваемый объект
PowerPoint .Application	Application
Таблица 17.2.f Значения ClassType (ClassName) для объектов Microsoft Word
Значение аргумента ClassType (ClassName)	Создаваемый объект
Word. Application	Application
Word.Document, Word.Template	Document
Word.Global	Global
Таблица 17.3. Некоторые свойства OLE-объектов
Свойство	Приложение	Объект-носитель	Назначение
Anchor	Word	Shape	Объект Range указывает диапазон документа, с которым связывается объект Shape.
694
Приложение А
Свойство	Приложение	Объект-носитель	Назначение
AutoUpdate	Excel, Word, PowerPoint	LinkFormat	Имеет значение True, если связанный OLE-объект автоматически обновляется, когда изменяются данные приложения-сервера.
BottomRightCell	Excel	Shape	Возвращает объект Range, определяющий ячейку рабочего листа под правым нижним углом объекта Shape.
Height	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает высоту объекта Shape, измеряемую в точках.
Left	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает позицию левого края объекта относительно левого края рабочего листа или документа (в точках).
Line	Excel, Word, PowerPoint	Shape	Возвращает объект LineFormat, свойства которого управляют видом рамки OLE-объекта.
LinkFormat	Excel, Word, PowerPoint	Shape	Возвращает объект LinkFormat, свойства которого сохраняют информацию о связанном OLE-объекте.
Name	Excel, Word, PowerPoint	Shape	Имя объекта. Используйте это свойство, чтобы вернуть имя OLE-объекта или переименовать OLE-объект.
Object	Excel, Word, PowerPoint	OLEFormat	Возвращает Automation-объект, связанный с объектом.
OLEFormat	Excel, Word, PowerPoint	Shape	Возвращает объект OLEFormat, свойства которого содержат информацию как о связанных, так и о внедренных объектах.
OnAction	Excel	Shape	Вы можете использовать это свойство в Excel, чтобы установить или вернуть имя процедуры события для данного объекта Shape.
Progid	Excel, Word, PowerPoint	OLEFormat	Возвращает строку, содержащую тип класса OLE-объекта.
Shadow	Excel, Word, PowerPoint	Shape	Возвращает ссылку на объект ShadowFormat, который сохраняет информацию о состоянии тени, отбрасываемой объектом: видима она или — нет, ее цвет, величину сдвига относительно объекта и т.д.
Справочные таблицы книги
695
Свойство	Приложение	Объект-носитель	Назначение
Тор	Excel, Word, PowerPoint »	Shape	Устанавливает или возвращает позицию верхнего края объекта относительно верхнего края рабочего листа или документа (в точках).
TopLeftCell	Excel	Shape	Возвращает объект Range, определяющий ячейку рабочего листа, расположенную под верхним левым углом объекта Shape. Используйте TopLeftCell и Bottom-RightCell для поиска ячеек, перекрытых объектом Shape.
Туре	Excel, Word, PowerPoint	Shape	Возвращает численное значение, указывающее тип объекта Shape. Используйте встроенные константы MsoShapeType для определения типа Shape.
Visible	Excel, Word, PowerPoint	Shape	Установите это свойство в состояние False, чтобы скрыть объект, или в состояние True, чтобы сделать его видимым.
Width	Excel, Word, PowerPoint	Shape	Устанавливает или возвращает ширину объекта Shape (в точках).
Таблица 18.1. Встроенные константы VBA для аргумента WindowStyle функции Shell
WindowStyle	Вид окна
vbHide	Скрытое, с фокусом
vbNormalFocus	Нормальный размер, с фокусом
vbMinimizedFocus	Минимизированное, с фокусом
vbMaximizeFocus	Максимизированное, с фокусом
vbNormalNoFocus	Нормальный размер, без фокуса
vbMinizedNoFocus	Минимизированное, без фокуса
Таблица 18.2. Строки, используемые в качестве аргумента String в методе SendKeys
Клавиши	Коды
BACKSPACE	{BACKSPACE}, {BS} или {BKSP}
BREAK	{BREAK}
CAPS LOCK	{CAPSLOCK}
DEL или DELETE	{DELETE}или{DEL}
696
Приложение А
Клавиши	Коды
DOWN ARROW	{DOWN}
END	{END}
ENTER	{ENTER} или -
ESC	{ESC}
HELP	{HELP}
HOME	{HOME}
INS или INSERT	{INSERT} или {INS}
LEFT ARROW	{LEFT}
NUM LOCK	{NUMLOCK}
PAGE DOWN	{PGDN}
PAGE UP	{PGUP}
PRINT SCREEN	{PRTSC}
RIGHT ARROW	{RIGHT}
SCROLL LOCK	{SCROLLLOCK}
TAB	{TAB}
UP ARROW	{UP}
F1-F16	{F1}-{F16}
Таблица 18.3. Коды для клавиш Alt, Ctrl и Shift
клавиша	знак
SHIFT	+
CTRL	
ALT	%
Таблица 19.1. Часто используемые события объектов Excel
Событие	Относится к	Когда происходит
Activate	Chart, Workbook, Worksheet	Когда объект активизируется VBA-кодом или действиями пользователя.
Addininstall	Workbook	Когда рабочая книга устанавливается как надстройка (add-in).
AddinUninstall	Workbook	Когда выгружается рабочая книга-надстройка.
BeforeClose	Workbook	Перед тем, как закрывается рабочая книга и перед тем, как пользователю выдается запрос о сохранении изменений.
Справочные таблицы книги
697
Событие	Относится к	Когда происходит
BeforeDoubleClick	Chart, Worksheet	При выполнении двойного щелчка внедренной диаграммы или рабочего листа, но перед заданным по умолчанию ответным действием на двойной щелчок.
BeforePrint	Workbook	Перед печатью рабочей книги или ее частью.
BeforeRightClick	Chart, Worksheet	При выполнении правого щелчка внедренной диаграммы или рабочего листа, но перед заданным по умолчанию ответным действием на правый щелчок.
BeforeSave	Workbook	Перед сохранением рабочей книги.
Calculate	Chart, Worksheet	После того как рабочий лист повторно вычислен или после рисования диаграммы по новым или обновленным данным.
Change	Worksheet	Когда свойство Value ячейки изменяется либо кодом VBA, либо в результате действий пользователя.
Deactivate	Chart, Workbook, Worksheet	Когда объект деактивизируется либо кодом VBA, либо в результате действий пользователя.
NewSheet	Workbook	При создании в рабочей книге нового листа (диаграммы или рабочего листа).
NewWorkbook	Application	Когда создается новая рабочая книга.
< Open	Workbook	Когда открывается рабочая книга.
SelectionChange	Worksheet	При изменении выделенного фрагмента в рабочем листе.
SheetActivate	Application, Workbook	Когда активизируется любой лист.
SheetBeforeDoubleClick	Application, Workbook	При выполнении двойного щелчка рабочего листа, но до ответного действия по умолчанию на двойной щелчок.
SheetBeforeRightClick	Application, Workbook	При выполнении правого щелчка рабочего листа, но до ответного действия по умолчанию на правый щелчок.
SheetCalculate	Application, Workbook	Когда рабочий лист перерасчитывается или изменяются данные на диаграмме.
Sheetchange	Application, Workbook	Когда ячейка в рабочем листе изменяется пользователем или внешней связью.
SheetDeactivate	Application, Workbook	Когда лист (рабочий лист или диаграмма) деактивизируется.
SheetSelectionChange	Application, Workbook	При изменении выделенного фрагмента в рабочем листе.
Window Activate 1	Application, Workbook	Когда активизируется любое окно рабочей книги.
698
Приложение А
Событие	Относится к	Когда происходит
WindowDeactivate	Application, Workbook	Когда деактивизируется любое окно рабочей книги.
WindowResize	Application, Workbook	При изменении размеров любого окна рабочей книги.
WorkbookActivate	Application	При активизации любой рабочей книги.
W orkbook Addininstall	Application	Когда любая рабочая книга устанавливается как надстройка (add-in).
WorkbookAddinUninstall	Application	Когда выгружается любая рабочая книга-надстройка.
WorkbookBeforeClose	Application	Непосредственно перед закрытием любой рабочей книги.
WorkbookBeforePrint	Application	Непосредственно перед печатью любой рабочей книги (или ее части).
WorkbookBeforeSave	Application	Непосредственно перед сохранением любой открытой рабочей книги.
WorkbookDeactivate	Application	Когда любая открытая книга деактивизируется.
WorkbookNewSheet	Application	При создании в любой открытой рабочей книге нового листа (рабочего листа или диаграммы).
WorkbookOpen	Application	При открытии рабочей книги.
Таблица 19.2. Текстовые строки, использующиеся для аргумента Key метода ОпКеу
Клавиша	Строка
BACKSPACE	{BACKSPACE}, {BS} или {BKSP}
BREAK	{BREAK}
CAPS LOCK	{CAPSLOCK}
DEL или DELETE	{DELETE} или {DEL}
DOWN ARROW	{DOWN}
END	{END}
ENTER	{ENTER} или -
ESC	{ESC}
HELP	{HELP}
HOME	{HOME}
INS или INSERT	{INSERT} или {INS}
LEFT ARROW	{LEFT}
NUM LOCK	{NUMLOCK}
PAGE DOWN	{PGDN}
Справочные таблицы книги
699
Клавиша	Строка
PAGE UP	{PGUP}
PRINT SCREEN	{PRTSC}
RIGHT ARROW	{RIGHT}
SCROLL LOCK	{SCROLLLOCK}
TAB	{TAB}
UP ARROW	{UP}
F1-F16	{F1}-{F16}
Таблица 19.4. События Word-объекта Application
Событие	Когда происходит
DocumentBeforeClose	Перед тем, как закрывается любой документ.
DocumentBeforePrint	Перед тем, как печатается любой открытый документ.
DocumentBeforeSave	Перед тем, как сохраняется любой открытый документ.
Documentchange	Когда изменяется открытый документ.
DocumentOpen	Когда открывается документ.
EPostageinsert, EPostageProperty Dialog, MailMergeAf terMerge, MailMergeAfterRecordMerge, MailMergeBeforeMerge, MailMergeBeforeRecordMerge, MailMergeDataSourceLoad, MailMergeDataSourceValidate, MailMergeDataSourceValidate, MailMergeWizardSendToCustom, MailMergeWizardStateChange	При возникновении событий, связанных с использованием аппарата рассылки писем. i
NewDocument	При создании нового документа.
Quit	Когда пользователь завешает работу с Word.
WindowActivate	Когда любое окно документа становится активным.
WindowBeforeDoubleClick	Когда в редактируемой области окна документа выполняется двойной щелчок, перед выполнением действия по умолчанию.
WindowBeforeRightClick	Когда в редактируемой области окна документа выполняется правый щелчок, перед выполнением действия по умолчанию.
WindowDeactivate	Когда любое окно документа перестает быть активным.
WindowSelectionChange I	Когда в окне активного документа изменяется выделенный фрагмент.
700
Приложение А
Событие	Когда происходит
WindowSize	Когда окно приложения изменяется в размерах или перемещается.
Таблица 19.5. События Word-объекта Document
Событие	Когда происходит
Close	Когда закрывается документ.
New	Когда новый документ создается на основе шаблона.
Open	При открытии документа.
Приложение Б
Приоритеты операций в Visual Basic *
В следующей таблице приведены операции языка Visual Basic в порядке их приоритетов (сначала следуют операции с более высоким приоритетом).
Обозначение	Наименование	Обозначение	Наименование
*	возведение в степень	О	неравенство
+	унарный «плюс»	<	меньше чем
-	унарный «минус»	<=	меньше либо равно
*	умножение	>	больше чем
/	деление	>=	меньше либо равно
\	деление без остатка	Like	шаблонное сравнение
Mod	деление по модулю	Is	ссылочное сравнение
+	сложение	Not	логическое отрицание
-	вычитание	And	логическое «И»
&	конкатенация	Or	логическое включающее «ИЛИ»
	равенство	Xor	логическое исключающее «ИЛИ»
ел	О Wr
Операторы в VBA
AppActivate
Активизирует окно приложения (application window).
Синтаксис
AppActivate title], wait]
Оператор AppActivate имеет следующие именованные аргументы:
title	Обязательный. Строковое выражение, определяющее строку заголовка для окна активизируемого приложения. ID-задачи, возвращаемый функцией Shell, может использоваться в качестве параметра для title.
wait	Необязательный. Тип Boolean. Значение, определяющее, должно ли вызывающее приложение иметь фокус перед активизацией другого приложения. Если этот параметр равен значению False (по умолчанию), указанное приложение немедленно активизируется, даже если вызывающее приложение не имеет фокуса. Если этот параметр равен значению True, вызывающее приложение ожидает получение фокуса, после чего активизируется указанное приложение.
Оператор AppActivate переносит фокус на именованное приложение или окно, но не воздействует на их максимизацию или минимизацию. Для запуска приложения (которое затем можно активизировать) можно использовать функцию Shell. Shell запускает исполняемую программу и возвращает значение, представляющее ID-задачи, если запуск выполнен успешно, или нуль — в противном случае.
В процессе определения того, какое приложение следует активизировать, аргумент title сравнивается со строкой заголовка каждого выполняющегося приложения. Если точного совпадения нет, то активизируется любое приложение, строка заголовка которого начинается с title. Если одновременно выполняются несколько экземпляров приложения с заголовком title, активизируется один из них, выбранный произвольно.
Пример
Sub Call_Excel()	'
'	в качестве аргумента оператора AppActivate можно использовать
'	возвращаемое значение функции Shell
MyAppID = Shell(
"e:\Program Files\Microsoft Office\OfficelO\EXCEL.EXE", 1) AppActivate MyAppID
End Sub
Beep
Выдает звуковой сигнал посредством встроенного динамика.
Синтаксис
Веер
Операторы в VBA
703
Частота и длительность сигнала зависят от оборудования и программного обеспечения компьютера.
Пример
Function MyBeep(n As Integer) ' n - "длительность" звучания For I - 1 То n
Веер Next
End Function
Call
Передает управление (вызывает) Sub-процедуре, Function-процедуре или процедуре DLL-библиотеки.
Синтаксис
[Call] name [argumentlist]
Синтаксис оператора Call состоит из элементов:
Call	Необязательный; (ключевое слово). Если указан, список аргументов argumentlist необходимо заключать в круглые скобки. |
name	Обязательный. Имя вызываемой процедуры.
argumentlist	Необязательный. Список разделенных запятыми переменных, массивов или выражений для передачи вызываемой процедуре в качестве аргументов. Компоненты списка argumentlist могут включать ключевые слова ByVai или ByRef для описания способа передачи аргументов (по значению или по ссылке) процедуре.
При вызове процедуры ключевое слово Call использовать необязательно. Но, если вы используете Call для вызова процедуры, которая принимает аргументы, необходимо список аргументов заключать в круглые скобки. Если ключевое слово Call не используется, скобки вокруг списка аргументов также не нужны.
Пример
В этом примере описаны три процедуры (с именами a_sub, b_sub и c_sub). Процедура a_sub вызывает процедуру b_sub и передает ей в качестве аргумента строку. Процедура b_sub вызывает процедуру c_sub и передает ей в качестве аргумента принятую от процедуры a_sub строку. Процедура c_sub с помощью MsgBox выводит содержимое переданной из b_sub строки.
Sub a_sub()
Call Ь("Привет от процедуры а!")
End Sub	,
Sub b_sub(StrMy As String)
c_sub (StrMy)
End Sub		I
Sub c_sub(StrMy As String)
MsgBox StrMy
End Sub
704
Приложение В
ChDir
Изменяет текущий каталог или папку.
Синтаксис
ChDir path
Обязательный аргумент path — строковое выражение, которое определяет новый текущий каталог или папку. Аргумент path может включать имя драйвера. Если имя*Драйвера не указывается, используется текущий драйвер.
Оператор ChDir изменяет каталог по умолчанию, но не драйвер по умолчанию. Например, если драйвер по умолчанию — F, следующий оператор изменит каталог по умолчанию на драйвере Е, но F останется драйвером по умолчанию:
ChDir "E:\TMP"
Пример
ChDir "MYDIR"
ChDir "D:\WIN2000\SYSTEM"
ChDrive
Изменяет текущий драйвер.
Синтаксис
ChDrive drive
Обязательный аргумент drive — строковое выражение, определяющее имеющийся драйвер. Если аргумент drive — строка из нескольких символов, оператор ChDrive использует только первую букву.
Пример
ChDrive "F"
Close
Закрывает ввод/вывод для файла, открытого с использованием оператора Open.
Синтаксис
Close [filenumberlist]
Необязательный аргумент filenumberlist может быть списком номеров файлов (file numbers) со следующим синтаксисом (filenumber — допустимый номер файла):
[[#]filenumber] [, [#]filenumber] . . .
Если filenumberlist не указан, оператор Close закрывает все активные файлы, открытые оператором Open.
Когда вы закрываете файлы, открытые для Output или Append, окончательный буфер вывода записывается в буфер операционной системы для этого файла. Все буферное пространство, связанное с этим файлом, удаляется, и связь файла с его файловым номером прекращается.
Пример
В этом примере в цикле For...Next открываются три файла для записи (Output), в каждый файл записывается текстовая строка; после окончания цикла при помощи оператора Close файлы закрываются.
Sub Close'Iest ()
Dim I, FileName
For I = 1 To 3	,
Операторы в VBA
705
FileName = "TEST" & I	'	создать имя файла
Open FileName For Output	As #1	'	открыть файл
Print #1, "запись в файл	" & FileName	'	записать строку в	файл
Next I Close ' закрыть все три файла
End Sub
Const
Объявляет константы.
Синтаксис
[Public I Private] Const constname [As type] = expression
Синтаксис оператора Const включает три элемента:
Public	Необязательный. Ключевое слово, используемое на уровне модуля для объявления констант, которые доступны всем процедурам во всех модулях. Нельзя использовать в процедурах.
Private	Необязательный. Ключевое слово, используемое на уровне модуля для объявления констант, которые доступны только в том модуле, в котором объявлены. Нельзя использовать в процедурах.
constname	Обязательный. Имя константы; должно отвечать стандартным соглашениям об именовании переменных.
type	Необязательный. Тип (данных) константы; может быть типом Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String или Variant.
expression	Обязательный. Литерал, другая константа или любая комбинация, включающая все арифметические или логические операции, кроме Is.
Константы по умолчанию являются закрытыми. В процедурах константы всегда являются закрытыми; их «видимость» не может быть изменена. В стандартных модулях видимость по умолчанию констант модульного уровня может быть изменена с использованием ключевого слова Public. Однако в модулях классов константы могут быть только закрытыми, их видимость нельзя изменить ключевым словом Public. Константы, объявляемые в Sub-, Function- или Property-процедурах, локальны для этих процедур. Константы, объявленные вне процедуры, «видимы» в модуле, в котором объявлены.
Для объединения нескольких объявлений констант на одной строке следует отделять их друг от друга запятыми.
Примеры
Const IntMyVarl = 429
Public Const StrMyVarl = "Word"
Private Const IntMyVar2 As Integer = 15
Const StrMyVarl = "Excel", DblPi As Double = 3.14
Date
Устанавливает системную текущую дату.
Синтаксис
Date = date
23 Программирование на VBA 2002
706
Приложение В
Для системы Microsoft Windows 9Х обязательный элемент синтаксиса date может быть в диапазоне от 1 января 1980 года до 13 декабря 2099 года. Для Microsoft Windows NT этот диапазон имеет верхнюю границу 31 декабря 2079 года. Для Macintosh date может принимать значения от 1 января 1904 года до 5 февраля 2040 года.
Пример
В следующем примере объявляется константа DateMy и переменная DateNow для сохранения текущей системной даты. С помощью функции Now в переменной запоминается текущая дата. Затем оператор Date (с аргументом DateMy) изменяет системную дату, a MsgBox выдает в диалоговом окне подтверждение выполнения оператора Date. Далее оператор Date с аргументом DateNow восстанавливает системную дату, a MsgBox в диалоговом окне дает возможность убедиться в «восстановлении справедливости» по отношению к системной дате.
Sub DateTest ()
Const DateMy = #2/11/1986#
Dim DateNow
DateNow = Now() ' запомнить текущую дату (и время)
Date = DateMy ' установить новую дату
MsgBox Now ()	' проверить изменение даты на новую
Date = DateNow ' восстановить правильную дату
MsgBox Now()	' проверить изменение даты сохраненную
End Sub
Declare
Используется на уровне модуля для объявления ссылок на внешние процедуры в DLL-библиотеке.
Синтаксис 1
[Public I Private] Declare Sub пате Lib <libname>
[Alias <aliasname>] [([arglist])]
Синтаксис 2
[Public | Private] Declare Function name Lib <libname>
[Alias <aliasname>] [([arglist])] [As type]
Синтаксис оператора Declare включает следующие элементы:
Public	Необязательный. Используется для объявления процедур, которые доступны всем другим процедурам во всех модулях.
Private	Необязательный. Используется для объявления процедур, которые доступны только внутри модуля, содержащего эти объявления.
Sub	Необязательный (должно быть либо Sub, либо Function). Указывает, что процедура не возвращает значения.	।
Function	Необязательный (должно быть либо Sub, либо Function). Указывает, что процедура возвращает значение, которое может быть использовано в каком-либо выражении.
name	Обязательный. Любое допустимое имя процедуры.
Lib	Обязательный. Указывает, что DLL- или код-источник содержит процедуру, которая объявляется.
hbname	Обязательный. Имя DLL- или код-источника, который содержит объявляемую процедуру.
Операторы в VBA
707
Alias	Необязательный. Указывает, что вызываемая процедура имеет другое имя в DLL. Это полезно, когда имя внешней процедуры совпадает с ключевым словом или когда имя DLL-процедуры совпадает с public-переменной, константой или именем другой процедуры в той же области действия. Alias также используется, если некоторые символы в имени DLL-процедуры недопустимы стандартными соглашениями об DLL-именовании.
aliasname	Необязательный. Имя процедуры в DLL- или код-источнике. Если первый символ не является символом #, aliasname — имя точки входа в процедуру в DLL. Если # — первый символ, все последующие символы указывают порядковый номер точки входа в процедуру.
arglist	Необязательный. Список переменных, представляющих аргументы, передаваемые в процедуру при вызове.
type	Необязательный. Тип значения, возвращаемого Function-процедурой; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), Variant, типом, определенным пользователем, или объектным типом.
Синтаксис аргумента arglist состоит из следующих элементов: [Optional] [ByVai | ByRef] [ParamArray] varname[( )] [As type]
Optional	Необязательный. Указывает, что аргумент — необязательный. Если используется, все последующие аргументы в arglist должны быть также необязательными и объявляться с ключевым словом Optional. Если используется ParamArray слово Optional не может использоваться ни для какого аргумента.
ByVai	Необязательный. Указывает, что аргумент передается по значению.
ByRef	Указывает, что аргумент передается по ссылке (в Visual Basic по умолчанию).
ParamArray	Необязательный. Используется только в качестве последнего аргумента в списке arglist для указания того, что последний аргумент является Optional-массивом Variant-элементов. Ключевое слово ParamArray позволяет использовать переменное число аргументов и не может применяться с ByVai, ByRef или Optional.
varname	Обязательный. Имя переменной, передаваемой процедуре; должно удовлетворять стандартным соглашениям об именовании переменных.
()	Обязательны для переменных-массивов. Указывают, что varname —массив.
type	Необязательный. Тип аргумента, передаваемого процедуре; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
Для Function-процедур тип данных процедуры определяет тип возвращаемого значения. Пустые скобки указывают, что Sub- или Function-процедура не имеет аргументов. Если процедура имеет список аргументов, их тип и количество проверяются при вызове процедуры.
23'
708
Приложение В
Deftype
Используется на уровне модуля для определения типа по умолчанию переменных, аргументов, передаваемых процедурам, и возвращаемого типа Function-и Property Get-процедур, имена которых начинаются с определенных символов.
Синтаксис
DefBool letterrange[, letterrange] DefByte letterrange[, letterrange] Deflnt letterrange[, letterrange] . DefLng letterrange], letterrange] . DefCur letterrange], letterrange] . DefSng letterrange[, letterrange] . DefDbl letterrange[, letterrange] . DefDec letterrange[, letterrange] .
DefDate letterrange[, letterrange] DefStr letterrange[, letterrange] . DefObj letterrange[, letterrange] . DefVar letterrange], letterrange] .
Обязательный аргумент letterrange имеет следующий синтаксис: let ter1[-letter2]
Аргументы letterl и letter2 определяют диапазон имен, для которого устанавливается тип данных по умолчанию. Каждый аргумент представляет первый символ имени переменной, аргумента, Function- или Property Get-процедуры и может быть любым алфавитным символом.
Имя оператора определяет тип данных:
оператор	тип данных	оператор	тип данных
DefBool	Boolean	DefDbl	Double
DefByte	Byte	DefDate	Date
Deflnt	Integer	DefStr	String
DefLng	Long	DefObj	Object
DefCur	Currency	DefVar	Variant
DefSng	Single		
Если в коде указывается буквенный диапазон, он обычно определяет тип да-ных для переменных, которые начинаются с букв первых 128-и символов символьного набора. Однако когда задается буквенный диапазон А-Z, устанавливается значение по умолчанию на определенный тип данных для всех переменных, включая переменные, которые начинаются с международных символов из расширенной части символьного набора (128-255).
После того как диапазон А-Z определен, можно в дальнейшем переопределять любой поддиапазон переменных, используя операторы Defti/pe. Если в следующем операторе Defti/pe окажется символ из ранее используемого диапазона, это вызовет ошибку. Однако при этом можно, используя оператор Dim со спецификатором As type, явно указать для некоторой переменной ее тип. Например, если вы указали, что переменные, начинающиеся с символов диапазона i-n, по умолчанию будут иметь тип Integer (именно эти символы очень часто используются для именования переменных циклов For...Next), для конкретной переменной iTaxRate можно указать тип Double:
Deflnt A-Z
Dim TaxRate As Double
Операторы в VBA
709
Оператор Deftype не оказывает воздействия на элементы типов, определенных пользователем, поскольку эти элементы должны объявляться явно.
Пример
De fl nt I-К
DefStr L-Z
DeleteSetting
Удаляет секцию или ключевую настройку (key setting) из раздела приложения в Windows-реестре.
Синтаксис
DeleteSetting appname, section[, key]
Синтаксис оператора DeleteSetting включает следующие именованные аргументы:
appname	Обязательный. Строковое выражение, содержащее наименование приложения или проекта (project), для которого предназначена эта секция или ключевая настройка.
section	Обязательный. Строковое выражение, содержащее наименование секции или ключевой настройки для удаления. Если указываются и appname, и section, то удаляется заданная секция и все связанные с ней настройки.
key	Необязательный. Строковое выражение, содержащее наименование ключевой настройки для удаления.
Пример
Далее приведены две процедуры, одна из которых (TestSave) создает секцию и ключевые настройки в Реестре, а другая (TestDelete) удаляет всю секцию. Выполните первую процедуру и запустите программу Regedit.exe (из меню Пуск). Найдите секцию МуАрр и посмотрите установленные ключи. Затем запустите процедуру TestDelete и убедитесь в том, что секция МуАрр действительно удалена.
Sub TestSave()
' поместить некоторые настройки в Реестр
SaveSetting appname:="МуАрр", Section:="Startup", _
Кеу:="Тор", setting:=75
SaveSetting "МуАрр", "Startup", "Left", 50
End Sub
Sub TestDelete()
' удалить секцию из Реестра DeleteSetting "МуАрр" End Sub
Dim
Объявляет переменные и резервирует память.
Синтаксис
Dim [WithEvents] varname[([subscripts])] [As [New] type]
[, [WithEvents] varname[([subscripts])] [As [New] type]] ...
Синтаксис оператора Dim включает следующие элементы:
710
Приложение В
WithEvents	Необязательный. Ключевое слово, которое указывает, что varname — объектная переменная, используемая для реакции на событие, инициированное ActiveX-объектом. WithEvents допускается только в модулях класса. Отдельных переменных с использованием ключевого слова WithEvents можно объявлять столько, сколько необходимо, но массив, используя его, создавать нельзя. Также нельзя использовать ключевое слово New при наличии WithEvents.
varname	Обязательный. Имя переменной; должно соответствовать стандартным соглашениям об именовании переменных.
subscripts	Необязательный. Размерность переменной-массива; объявить можно до 60 размерностей. Аргумент subscripts использует следующий синтаксис: [lower То] upper [, [lower То] upper] ... lower — нижний предел допустимых индексов массива; upper — верхний предел (является обязательным) для индексов массива. При наличии в операторе Dim только upper нижний предел определяется в зависимости от установки оператора Option Base.
New	Необязательный. Ключевое слово, позволяющее неявно создать объект. Если вы используете New при объявлении объектной переменной, создается новый экземпляр объекта, поэтому нет необходимости использовать оператор Set для назначения объекту ссылки.
Type	Необязательный. Тип данных переменной; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), String * length (для строк фиксированной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
Переменные, объявляемые оператором Dim на уровне модуля, доступны всем процедурам этого модуля. На уровне процедуры переменные доступны только внутри этой процедуры. Оператор Dim следует использовать на уровне модуля или процедуры для объявления типа переменной. Например, следующая переменная объявляется как String:
Dim StrName As String
Оператор Dim можно использовать и для объявления переменной объектного типа. В следующем примере объявляется новый экземпляр объекта Worksheet:
Dim WorkShNew As New Worksheet
Если ключевое слово New не используется при объявлении объектной переменной, то переменной, которая ссылается на объект, должна быть присвоена ссылка на существующий объект с использованием оператора Set. До тех пор, пока этого не сделано, объектная переменная будет иметь значение Nothing, которое указывает, что объектная переменная не ссылается ни на какой конкретный экземпляр объекта.
Оператор Dim можно использовать с пустыми круглыми скобками для объявления динамического массива. Используя затем оператор ReDim, можно указать размерность и число элементов массива.
Do...Loop
Повторяет блок операторов до тех пор, пока некоторое условие имеет значение True или пока оно не станет равным True.
Операторы в VBA
711
Синтаксис
Do [(While I Until} condition]
[statements]
[Exit Do]
[statements]
Loop
или
Do
[statements]
[Exit Do]
[statements]
Loop [(While | Until} condition]
Синтаксис оператора Do Loop включает следующие элементы:
condition	Необязательный. Численное или строковое выражение, имеющее значение True или False. Если condition имеет значение Null, оно интерпретируется как False.
statements	Один или более операторов, которые повторяются, пока condition — True, или до тех пор пока оно не станет равным True.
В теле оператора (цикла) может быть любое количество операторов Exit Do, которые являются дополнительными средствами для окончания цикла (выхода из оператора Do...Loop). Оператор Exit Do часто используется внутри Do...Loop с применением оператора If...Then, который проверяет некоторое дополнительное условие для выхода из цикла.
End
Заканчивает процедуру или блок.
Синтаксис
End End Function End If	'
End Property End Select End Sub End Type End With
Синтаксис оператора End имеет следующие формы:
End	Немедленно прекращает выполнение. He является обязательным, но может располагаться в любом месте процедуры для окончания работы этой процедуры, закрытия файлов, открытых оператором Open и «очистки» переменных.
End Function	Обязателен для окончания Function-процедуры.
End If	Обязателен для окончания блока оператора If...Then...Else.
End Property	Обязателен для окончания Property Let-, Property Get- или Property Set-процедуры.
End Select	Обязателен для окончания оператора Select Case.
End Sub	Обязателен для окончания Sub-процедуры.
712
Приложение В
End Type	Обязателен для окончания определения пользовательского типа (оператора Туре).
End With	Обязателен для окончания оператора With.
При выполнении оператор End «переустанавливает» все переменные уровня модуля и все статические локальные переменные во всех модулях. Чтобы сохранить значения этих переменных используйте оператор Stop.
Оператор End останавливает выполнение кода аварийно, без вызова событий (и соответствующих им программ обработки) Unload, QueryUnload или Terminate, а также какого-либо другого кода. Объекты, созданные с помощью модулей класса, уничтожаются, файлы, открытые оператором Open, закрываются, память, используемая программой, освобождается.
Пример
В этом примере при загрузке формы с помощью функции InputBox запрашивается пароль. Если пароль введен неправильно, программа завершает работу. Конечно, этот пример следует использовать только в учебных целях, так как пароль, находящийся рядом с кодом его запроса, легко извлечь.
Sub Form_Load
Dim strPassword, StrPw
strPassword = "Привет Шишкину1"
StrPw = InputBox("Введите пароль:") If StrPw <> strPassword Then
MsgBox "К сожалению, пароль неверен1" End End If
' полезные операторы процедуры:
End Sub
Enum
Объявляет тип для перечисления.
Синтаксис
[Public | Private] Enum name membername [= constantexpression] membername [= constantexpression]
End Enum	K,
Синтаксис оператора Enum включает следующие элементы:
Public	Необязательный. Указывает, что тип Enum является видимым во всем проекте. Типы Enum являются Public по умолчанию.
Private	Необязательный. Указывает, что тип Enum является видимым только внутри модуля, в котором он определяется.
пате	Обязательный. Имя типа Enum. Имя должно быть допустимым для Visual Basic идентификатором.
membername	Обязательный. Допустимый для Visual Basic идентификатор, определяющий имя, посредством которого будет известен составной элемент типа Enum.
Операторы в VBA
713
constantexpression
Необязательный. Значение элемента (приводится к Long). Если constantexpression не указан, этому значению присваивается либо ноль (если это первый membername), либо на единицу больше, чем значение непосредственно предыдущего membername.
Переменные перечисления — это переменные, объявленные при помощи оператора Enum. В качестве типа Enum могут быть объявлены как переменные, так и аргументы. Элементы типа Enum инициализируется константными значениями. Эти значения не могут быть изменены в режиме исполнения программы и могут включать как положительные, так и отрицательные значения.
Оператор Enum можно использовать только на уровне модуля. Сразу после описания Enum-типа этот тип можно использовать для объявления переменных, параметров процедур или типов данных, возвращаемых процедурами. Public Enum-типы в модуле класса не являются членами этого класса, хотя они записываются в библиотеку типов1. Типы Enum, определенные в стандартных модулях2, записываются в библиотеки типов. Типы Public Enum с одним и тем же именем не могут определяться и в стандартном, и модуле класса, поскольку они совместно используют (разделяют) одно и то же пространство имен. Если два типа Enum в различных библиотеках типов имеют одно и то же имя, но различные элементы, ссылка на переменную типа зависит от того, какая библиотека типов имеет более высокий приоритет в References.
Erase
Повторно инициализирует элементы фиксированного массива и освобождает память, занимаемую элементами динамического массива.
Синтаксис
Erase arraylist
Обязательный аргумент arraylist — один (или более разделенных запятыми) массив.
Оператор Erase действует по разному для массивов фиксированного и переменного размера (динамических). Массивы фиксированного размера не уничтожаются: занимаемая ими память не освобождается. Оператор Erase устанавливает элементы массивов фиксированного размера следующим образом:
Тип массива	Действие оператора Erase
Фиксированный массив чисел	Устанавливает каждый элемент массива в ноль.
Фиксированный массив строк (переменной длины)	Присваивает каждому элементу массива значение строки нулевой длины ("").
Фиксированный массив строк (фиксированной длины)	Устанавливает каждый элемент массива в ноль.
Фиксированный Variant-массив	Устанавливает каждый элемент массива в Empty.
1 Файл или компонент внутри другого файла, который содержит стандартное описание объявленных объектов, свойств и методов, доступных для Automation.
2 Модуль, содержащий только процедуру, тип и объявления данных н определения. Объявления и определения модульного уровня в стандартном модуле по умолчанию являются открытыми (Public).
714
Приложение В
Тип массива	Действие оператора Erase
Массив данных определенных пользователем типов	Устанавливает каждый элемент, как будто это — отдельная переменная.
Массив объектов	Присваивает каждому элементу значение Nothing.
Оператор Erase освобождает память, занимаемую динамическим массивом. Прежде чем ваша программа сможет снова ссылаться на динамический массив, необходимо снова объявить массив с использованием оператора ReDim.
Error
Моделирует появление ошибки.	1
Синтаксис
Error errornumber
Обязательный аргумент errornumber может быть любым допустимым номером ошибки.
Оператор Error поддерживается для обратной совместимости. При разработке нового кода (особенно при создании объектов) для генерации run-time-ошибок используйте метод Raise объекта Err.
Если errornumber указывается, оператор Error вызывает обработчик ошибок (error handler) после того, как свойства Err-объекта принимают следующие значения по умолчанию:
Number	Значение, определенное как аргумент для оператора Error. Может быть любым допустимым номером ошибки.
Source	Наименование текущего проекта Visual Basic.
Description	Строковое выражение, относящееся к возвращаемому значению функции Error для определенного Number, если эта строка существует. Если строка не существует, Description содержит строку нулевой длины ("").
HelpFile	Драйвер, путь и имя соответствующего Help-файла Visual Basic.
HelpContext	ID соответствующего Help-файла Visual Basic.
LastDLLError	Ноль.
Event
Объявляет определенное пользователем событие.
Синтаксис [Public] Event procedurename [(arglist)] Синтаксис оператора Event включает следующие элементы:
Public	Необязательный. Определяет «видимость» события во всем проекте (используется по умолчанию).
procedurename	Обязательный. Имя события; должно соответствовать стандартным соглашениям об именовании переменных.
Операторы в VBA
715
Аргумент arglist имеет следующий синтаксис:
[ByVai | ByRef] varname[( )] [As type]
ByVai	Необязательный. Указывает, что аргумент передается по значению.
ByRef	Необязательный. Указывает, что аргумент передается по ссылке (по умолчанию).
varname	Обязательный. Имя переменной — аргумент, передаваемый процедуре; должно соответствовать стандартным соглашениям об именовании переменных.
Type	Необязательный. Тип (данных) аргумента, передаваемого процедуре; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
После объявления события для его инициализации используется оператор RaiseEvent:
Event LogonCompleted (UserName as String) Sub
RaiseEvent LogonCompleted("AntoineJan") End Sub
Аргументы для событий можно создавать так же, как это делается для обычных процедур, хотя имеются следующие исключения: события не могут иметь именованные аргументы, Optional-аргументы или РагатАггау-аргументы. События не возвращают значение.
Exit
Прерывает выполнение блока Do...Loop, For...Next, Function-, Sub- или Property-кода. ,
Синтаксис
Exit Do Exit For Exit Function Exit Property Exit Sub
Синтаксис оператора Exit имеет следующие формы:
Exit Do	Предназначен для прекращения работы оператора Do...Loop и может использоваться только внутри этого оператора. Оператор Exit Do «передает управление» выполнением программы оператору, следующему за словом Loop оператора Do...Loop. Если Exit Do используется во вложенных операторах Do...Loop, то «управление передается» во внешний Do...Loop по отношению к тому, в котором встретился оператор Exit Do.
Exit For	Обеспечивает способ выхода из цикла For. Может использоваться в циклах For...Next или For Each...Next. Оператор Exit For «передает управление» выполнением программы оператору, следующему за словом Next. При использовании внутри вложенного цикла For оператор Exit For «передает управление» во внешний For-цикл по отношению к тому, в котором встретился оператор Exit For.
716
Приложение В
। Exit Do	Предназначен для прекращения работы оператора Do...Loop и может использоваться только внутри этого оператора. Оператор Exit Do «передает управление» выполнением программы оператору, следующему за словом Loop оператора Do...Loop. Если Exit Do используется во вложенных операторах Do...Loop, то «управление передается» во внешний Do...Loop по отношению к тому, в котором встретился оператор Exit Do.
Exit Function	Немедленно прекращает выполнение Function-процедуры, в которой встречается. «Управление передается» оператору, следующему за тем, который вызвал Function-процедуру.
Exit Property	Немедленно прекращает выполнение Property-процедуры, в которой встречается. «Управление передается» оператору, следующему за тем, который вызвал Property-процедуру.
Exit Sub	Немедленно прекращает выполнение Sub-процедуры, в которой встречается. «Управление передается» оператору, следующему за тем, который вызвал Sub-процедуру.
Не следует путать Exit и End операторы. Оператор Exit не определяет конец структуры.
Пример
Sub ExitStatementTest()
, Dim I, MyNum	,
Do For I = 1 To 1000 MyNum = Int(Rnd * 1000) Select Case MyNum Case 7: Exit For Case 29: Exit Do Case 54: Exit Sub End Select Next I Loop End Sub
FileCopy
Копирует файл.
Синтаксис FileCopy source, destination
Синтаксис оператора FileCopy включает следующие именованные аргументы:
Source	Обязательный. Строковое выражение, определяющее имя файла, который будет копироваться; может включать каталог (папку) и драйвер диска.
Destination,	Обязательный. Строковое выражение, определяющее имя файла, в который будет производиться копирование.	|
Оператор FileCopy нельзя использовать для текущего открытого файла.
Пример FileCopy "Filer', "File2"
Операторы в VBA
717
For Each...Next
Повторяет группу операторов для каждого элемента массива или коллекции.
Синтаксис
For Each element In group	'
[statements!] [Exit For] [statements2]
Next [element]
Синтаксис оператора For...Each...Next включает следующие элементы:
element	Обязательный. Переменная, используемая для итерации по элементам коллекции или массива. Для коллекций element может быть только Variant-переменной, обобщенной объектной переменной или определенной объектной переменной. Для массива element может быть только Variant-переменной.
group	Обязательный. Имя коллекции объектов или массива (исключая массив типов, определенных пользователем).
statements	Необязательный. Один или более операторов, которые выполняются для каждого элемента в group.
Блок For...Each выполняется, если в group имеется, по крайней мере, один элемент. Все операторы цикла выполняются для каждого элемента в group. После этого «управление передается» оператору, следующему за ключевым словом Next.
Пример
Sub ForEachtest()
Dim а() As Integer, i As Integer, j As Integer i = 1
Do While Not i = 0
i = Int (InputBox("Введите целое число"))
If i > 0 Then
ReDim Preserve a(i)
For ] = 1 To i
a(l) = 1
Next
Call PrintArray(a) End If
Loop
End Sub	'	,
Sub PrintArray(aa)
1 для печати массива aa не нужно знать его размер For Each dd In aa
Debug.Print dd Next
Debug.Print "------------"
End Sub
For...Next
Повторяет группу операторов определенное число раз.
Синтаксис
For counter = start То end [Step step] [statements!]	>
718
Приложение В
[Exit For]
[statements2]
Next [counter]
Синтаксис оператора The For...Next содержит следующие элементы:
counter	Обязательный. Числовая переменная, используемая в качестве счетчика цикла (loop counter). Тип этой переменной не может быть 1 типом Boolean или элементом массива.
start	Обязательный. Начальное значение для counter.
end	Обязательный. Конечное значение для counter.
step	Необязательный. Шаг изменения значения counter после каждого цикла. Если не указывается, по умолчанию используется значение 1.
statements	Необязательный. Один или более операторов, выполняемых определенное число раз.
Аргумент step может быть как положительным, так и отрицательным. После выполнения всех операторов в цикле значение step добавляется к значению counter. После этого либо все операторы цикла выполняются снова, либо цикл прекращается и «управление передается» следующему за словом Next оператору. Не следует пытаться изменять значение counter внутри цикла. Это может затруднить чтение и отладку кода.
В качестве альтернативных выходов их цикла For...Next можно внутри цикла располагать любое количество операторов Exit For.
Пример
Sub Fortest()
Dim a (33) As Integer, j As Integer
For ] = 1 To 33 aU) - ]
Next
End Sub
Function
Объявляет имя, аргументы и код тела Function-процедуры.
Синтаксис
[Public ] Private | Friend] [Static] Function name [(arglist)] [As type] [statements!]	>
[name = expression!]
[Exit Function]
[statements.?]
[name = expressions]
End Function
Синтаксис оператора Function включает следующие элементы:
Public	Необязательный. Указывает, что Function-процедура доступна всем другим процедурам во всех модулях. Если используется в модуле, который содержит Option Private, процедура недоступна вне этого проекта.
Private	Необязательный. Указывает, что Function-процедура доступна другим процедурам только в модуле, в котором объявлена.
Операторы в VBA
719
Friend	Необязательный. Используется только в модуле класса. Указывает, что Function-процедура доступна всем модулям проекта.
Static	Необязательный. Указывает, что локальные переменные Function-процедуры сохраняются между вызовами процедуры. Атрибут Static не действует на переменные, объявленные вне Function, даже если они используются в коде процедуры.
name	Обязательный. Имя Function-процедуры; должно отвечать стандартным соглашениям об именовании переменных.
arglist	Необязательный. Список переменных, представляющих передаваемые процедуре аргументы.
type	Необязательный. Тип данных, возвращаемый Function-процедурой; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String, Object, Variant или типом, определенным пользователем.
statements	Необязательный. Любая группа операторов, которая выполняется при вызове Function-процедуры.
expression	Необязательный. Возвращаемое значение Function-процедуры.
Аргумент arglist должен соответствовать следующему синтаксису:
[Optional] [ByVai | ByRef] [ParamArray] varname[( )] [As type] [= defaultvalue]
Optional	Необязательный. Указывает, что аргумент необязательный. Если используется, все последующие аргументы в arglist должны быть
*	также необязательными и объявляться с ключевым словом Optional. Если применяется ParamArray, слово Optional не может использоваться ни для какого аргумента.
ByVai	Необязательный. Указывает, что аргумент передается по значению.
ByRef	Необязательный. Указывает, что аргумент передается по ссылке. Используется по умолчанию.
ParamArray	Необязательный. Используется только в качестве последнего аргумента в списке arglist для указания того, что последний аргумент является Optional-массивом Variant-элементов. Ключевое слово ParamArray позволяет использовать переменное число аргументов и не может применяться с ByVai, ByRef или Optional.
varname	Обязательный. Имя переменной, передаваемой процедуре; должно удовлетворять стандартным соглашениям об именовании переменных.
type	Необязательный. Тип аргумента, передаваемого процедуре; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), Object, Variant или определенным объектным типом. Если параметр не описан как Optional, может быть указан тип, определенный пользователем.
defaultvalue	Необязательный. Любая константа или константное выражение. Допускается только для аргументов, описанных как Optional. Если типом является Object, то явное значение по умолчанию может быть только значением Nothing.
720
Приложение В
Если явно не определено использование Public, Private или Friend, Function-процедура является Public по умолчанию. Если не используется Static, значения локальных переменных не сохраняются между вызовами. Ключевое слово Friend может быть использовано только в модулях класса. Однако Friend-процедуры могут быть доступны процедурам в любом модуле проекта.
Function-процедуры могут быть рекурсивными. Это означает, что они могут вызывать сами себя. Иногда в результате рекурсивных вызовов может происходить переполнение программного стека. Ключевое слово Static обычно не используется при описании рекурсивных Function-процедур.
Весь выполняемый код помещается в теле Function-процедуры. Нельзя определить Function-процедуру внутри другой Function-, Sub- или Property-процедуры.
Оператор Exit Function приводит к немедленному завершению Function-процедуры. При этом программа продолжает выполняться с оператора, следующего за тем, который вызвал Function-процедуру. В качестве альтернативных выходов внутри Function-процедуры может встречаться любое количество операторов Exit Function.
Подобно Sub-процедуре Function-процедура — это отдельная процедура, которая может принимать аргументы, выполнять ряд операторов и изменять значения ее аргументов. Однако в отличие от Sub-процедуры выражение с вызовом Function-процедуры может появляться в правой части операции присваивания в составе некоторого выражения. Например, как функции Chr, Cos и так далее. Для вызова функции используется ее имя, за которым в круглых скобках помещаются значения аргументов функции.
Чтобы функция возвращала значение, необходимо в теле (любом месте) функции поместить оператор, присваивающий это значение имени функции. Причем таких операторов может быть несколько. Если имени функции не присваивается внутри функции никакого значения, функция возвращает значение по умолчанию: функция, объявленная как числовая, возвращает 0, строковая функция — строку нулевой длины, Variant-функция — значение Empty, а объектная функция — значение Nothing.
Пример
В этом примере приведена функция проверки наличия файла на диске (IsDiskFile) и процедура, тестирующая эту функцию.
Function IsDiskFile(fName As String) As Boolean ' возвращает Истина (True), если файл на диске найден, ' иначе - Ложь (False) If (Dir(fName) о "") Then IsDiskFile = True Else IsDiskFile = False End If	\
End Function i Sub TestlsDiskFile() Dim namefun As String namefun = InputBox("Введите имя файла") If IsDiskFile(namefun) Then MsgBox ("Файл на диске!") Else MsgBox ("Файл на диске не найден!") End If End Sub	•'
Операторы в VBA
721
Get	,
Считывает данные из открытого файла на диске и помещает их в переменную. Синтаксис Get [#]flienumber, [recnumber], varname Синтаксис оператора Get включает следующие элементы:
filenumber	Обязательный. Любое допустимое имя файла.
recnumber	Необязательный. Variant (Long). Номер записи (record number) [для режима Random] или номер байта (byte number) [для режима Binary], с которого начинается чтение данных.
varname	Обязательный. Допустимое имя переменной, в которую считываются данные.
Данные, считываемые оператором Get, обычно предварительно записываются посредством оператора Put. Первая запись (или байт) в файле находится в позиции 1, вторая — в позиции 2 и так далее. Если аргумент recnumber опускается, происходит считывание следующей записи (или байта) после той, с которой использовались операторы Get или Put (или указанной функцией Seek). Не следует забывать, что для пропуска аргумента нужно использовать две запятые:
Get #2,,StrBuffer
Для файлов, открытых в Random-режиме, применяются следующие правила:
	Если длина считываемых данных меньше, чем длина, указанная в опции Len оператора Open, Get считывает последующие записи на границах длин записей. Пространство между концом одной записи и началом следующей записи заполняется имеющимся содержимым файлового буфера.
	Если считываемая переменная является строкой переменной длины, оператор Get сначала считывает 2-байтовый дескриптор (descriptor), содержащий длину строки, а затем — сами данные, которые помещаются в переменную. Поэтому длина записи (record), определяемая опцией Len в операторе Open, должна быть, по крайней мере, на 2 байта больше, чем действительная длина строки.
	Если считываемая переменная — Variant числового типа, Get считывает 2 байта, идентифицирующие VarType, а затем — сами данные, которые помещаются в переменную. Длина записи, определяемая опцией Len в операторе Open, должна быть, по крайней мере, на 2 байта больше, чем действительное число байтов, необходимое для сохранения переменной.
	Если считываемая переменная — Variant, значение VarType которой равно 8 (String), оператор Get считывает 2 байта, идентифицирующие VarType, 2 байта, указывающие длину строки, а затем — сами строковые данные. Длина записи, определяемая опцией Len в операторе Open, должна быть, по крайней мере, на 4 байта больше, чем действительная длина строки.
	Если считываемая переменная — динамический массив, оператор Get считывает дескриптор, длина которого равна 2 «плюс» 8, умноженное на число размерностей массива (2 + 8 * NumberOfDimensions). Длина записи, определяемая опцией Len в операторе Open, должна быть больше или равна сумме количества байтов, необходимых для хранения массива, и длины дескриптора. Например, объявленный ниже массив требует при записи на диск 218 байтов — 18 (2 + 8 * 2) байтов занимает дескриптор и 200 (5 * 20 * 2) необходимо для хранения массива:
Dim MyArray(l То 5,1 То 20) As Integer
722
Приложение В
	Если считываемая переменная — массив фиксированного размера, оператор Get считывает только данные.
	Если считываемая переменная — переменная любого другого типа (не строка переменной длины или Variant), Get считывает только данные. Длина записи, определяемая опцией Len в операторе Open, должна быть больше или равна длине считываемых данных.
	Оператор Get считывает элементы типов, определенных пользователем, как если бы они считывались отдельно, за исключением того, что между ними нет заполняющих элементов. На диске динамический массив определенного пользователем типа (записанный оператором Put) предваряется дескриптором, длина которого равна 2 «плюс» 8, умноженное на число размерностей: 2 + 8 * NumberOfDimensions. Длина записи, определяемая опцией Len в операторе Open, должна быть больше или равна сумме всех байтов, необходимых для чтения отдельных элементов, включая любые массивы и их дескрипторы.
Для файлов, открытых в Binary-режиме, применяются все Random-правила, за исключением:
	Len-опция (параметр) оператора Open не действует. Оператор Get считывает все переменные с диска непрерывно, т.е. без заполняющих символов между записями.
	Для любого массива, кроме массива пользовательского типа, Get считывает только данные. Дескриптор не читается.
	Get считывает строки переменной длины, которые не являются элементами пользовательских типов, без дескриптора 2-байтовой длины. Число считываемых байтов равно числу символов, имеющихся в строке.
Пример
В следующем примере описывается пользовательский тип данных (Record), процедура записи (TestPut) данных в файл и процедура чтения (TestGet) данных из файла.
Type Record 1 Определенный пользователем тип
ID As Integer
FirstName As String * 20
LastName As String * 20
End Type
Sub TestPut ()
' Тестирование Put
Dim MyRecord As Record, RecordNumber
Kill "TESTFILE"
Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
MyRecord.FirstName = "Петр"
MyRecord.LastName = "Петров"
MyRecord.ID = 333
Put #1, 2, MyRecord
MyRecord.FirstName = "Сидор"
MyRecord.LastName = "Сидоров"
MyRecord.ID = 111
Put #1, 3, MyRecord
v
MyRecord.FirstName = "Иван"
MyRecord.LastName = "Иванов"
MyRecord ID = 222
Put #1, 1, MyRecord
Операторы в VBA
723
Close #1
End Sub
Sub TestGetO	,
' тестирование Get
Dim MyRecord As Record, Position
Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
For i = 1 To 3
Get #1, i, MyRecord
Debug.Print MyRecord.FirstName & " : " & MyRecord.ID Next
Close #1
End Sub
GoSub...Return
Передает (и возвращает) управление выполнением процедуры подпрограмме (subroutine) внутри процедуры.
Синтаксис
GoSub line [statements of procedure] line [statements of subroutine]
Return
Аргумент line может быть любой строковой или числовой меткой.
Операторы GoSub и Return можно использовать в любом месте процедуры, но GoSub и соответствующий ему оператор Return должны быть в одной и той же процедуре. Подпрограмма может иметь более одного оператора Return.
Пример
В этом примере (практически, бессмысленном с математической точки зрения) приведена процедура, внутри которой для большей наглядности имеются две подпрограммы (именно подпрограммы с общими переменными!). Обратите внимание на то, что после оператора Return выполняется оператор Debug.Print Num.
Sub GosubDemo3() Dim Num Num = InputBox("Введите целое число")
Select Case Num Case Is > 0 GoSub MyRoutinel Case Is < 0 GoSub MyRoutine2	'
End Select	,
Debug.Print Num Exit Sub
MyRoutinel:
Debug.Print "значение/2:" Num = Num / 2 Return
MyRoutine2:
Debug.Print "(100+значение)/2" Num = 100 + Num Num = Num / 2 Return
End Sub
724
Приложение В
GoTo
Приводит к безусловной передаче управления выполнением программы на указанную строку внутри процедуры.
Синтаксис
GoTo line
Обязательный аргумент line может быть любой строковой или числовой меткой.
Оператор GoTo передает управление только на строку в процедуре, в которой этот оператор описан. С точки зрения структурного программирования этот оператор является «вредным», наносящим ущерб читабельности, создающим определенные трудности для отладки и сопровождения программного кода. Практика программирования показывает, что без этого оператора можно вполне обходиться. Чаще всего в VB этот оператор используется в программах обработки ошибок.
If...Then...Else
Выполняет группу операторов в зависимости от значения некоторого условия.
Синтаксис 1
If condition Then [statements] [Else elsestatements]
Синтаксис 2
If condition Then
[statements!]
[Elself condition-n Then [else!fstatements] ...
[Else
[elsestatements?]]	*-•
End If
Оператор If...Then...Else состоит из следующих элементов:
condition	Обязательный. Одно или более выражений следующих двух типов. Численное или строковое выражение, которое приводится к значениям True или False. Если значение condition — Null, интерпретируется как False.
statements	Необязательный в блочной форме (block form); обязательный в однострочной форме (single-line form), которая не имеет ветви Else. Один или более операторов; выполняются, если condition имеет значение True.
condition-n	Необязательный. То же, что и condition.
elseifstatements	Необязательный. Один или более операторов, выполняемых, если соответствующее condition-n имеет значение True.
elsestatements	Необязательный. Один или более операторов, выполняемых, если ни одно из предыдущих выражений condition или condition-n не равны значению True.
Самая простая форма оператора — однострочная. Например', следующая строка кода приводит к выводу диалогового окна с текстом "а больше, чем d", если в момент выполнения дтой строки значение переменной а больше, чем значение переменной d:
If а > d Then MsgBox "а больше, чем d"
Операторы в VBA
725
Если необходимо выполнить более одного оператора в однострочной структуре, можно записать их все в одной строке, используя в качестве разделителя символ двоеточия.
Блочная структура обеспечивает большую гибкость, чем однострочная форма, и обычно легче читается и отлаживается. Следующие строки эквиваленты предыдущей строке кода:
If а > d Then	•
MsgBox "а больше, чем d"	 -
End If
Пример
В этой процедуре обработки события — выбор кнопки-переключателя — Public-переменной пр присваивается тип подразделения. Далее вызывается функция загрузки наименований подразделений выбранного типа, например, в окно списка.
Private Sub OptionCklad__Click ()
If OptionCklad.Value Then
np = 2	' тип подразделения - СКЛАД
Else
np = 4	' тип подразделения - ОПТОВЫЙ МАГАЗИН
End If
t = ListBoxlLoad(np)
End Sub
Implements
Определяет интерфейс (interface) или класс (class), внедряемый в модуль класса, в котором используется этот оператор.
Синтаксис
Implements [InterfaceName I Class]
Обязательный аргумент InterfaceName или Class — имя интерфейса или класса в библиотеке типов (type library), методы которого внедряться соответствующими методами в VB-классе.
Интерфейс — коллекция прототипов, представляющая те члены (методы и свойства), которые инкапсулирует интерфейс; это означает, что он содержит только объявления для процедур-членов (member procedures). Класс обеспечивает реализацию (implementation) всех методов и свойств одного или более интерфейсов. Классы обеспечивают код, используемый при вызове любой функции контроллером (controller) класса. В Visual Basic любой член, который не является явно членом внедренного (implemented) интерфейса, — неявно член интерфейса по умолчанию.
Input #
Считывает данные из открытого файла последовательного доступа и присваивает их переменным.
Синтаксис
Input #flienumber, varlist
Синтаксис оператора Input # состоит из следующих элементов:
filenumber	Обязательный. Любой допустимый файловый номер.
varlist	Обязательный. Список разделенных запятыми переменных, которым присваиваются значения, считываемые из файла — массив или объектная переменная.
726
Приложение В
Данные, считываемые с помощью оператора Input #, — обычно то, что записано в этот файл оператором Write #. Используйте этот оператор только для файлов, открытых в режимах Input или Binary.
При чтении стандартной строки или числовых данных результат присваивается переменной без преобразования данных. В следующей таблице показано, как интерпретируются другие входные данные:
данные	значение, назначаемое переменной
Ограничивающая запятая или пустая строка	Empty
#NULL#	Null
#TRUE# или #FALSE#	True или False
#yyyy-mm-dd hh:mm:ss#	Дата и/или время, представленное выражением.
#ERROR errornumber#	errornumber (переменная — Variant, помеченная как ошибка).
Двойные кавычки во входных данных игнорируются.
Пример
Чтобы выполнить следующий пример, необходимо предварительно создать файл с именем "IWFILE" и при помощи оператора Write # занести в него данные в формате: <строка>,<число>.
Sub Testinput()
Dim StrMy, NumberMy
Open "IWFILE" For Input As #1	' открыть файл
Do While Not EOF(l)	1 цикл до конца файла
Input #1, StrMy, NumberMy 1 считать данные в две переменные
MsgBox StrMy & " : " & NumberMy ' результат -> на экран
Loop
Close #1	1 закрыть файл
End sub
Kill
Удаляет файлы с диска.
Синтаксис
Kill pathname
Обязательный аргумент pathname — строковое выражение, которое определяет одно или более файловых имен для удаления. Аргумент pathname может включать каталог (или папку) и имя драйвера.
В Microsoft Windows оператор Kill поддерживает использование символов множественной подстановки * или ?.
Пример
Kill "TestFile.TXT"	'
Kill "*.ВАК"
г
Let
Присваивает значение выражения переменной или свойству.
Операторы в VBA
727
Синтаксис
[Let] varname = expression
Синтаксис оператора Let состоит из следующих элементов:
Let	Необязательный. Явное использование ключевого слова Let — это оригинальный стиль, который обычно не применяется.
varname	Обязательный. Имя переменной или свойства; должен соответствовать стандартным соглашениям об именовании переменных.
expression	Обязательный. Значение, присваиваемое переменной или свойству.
Значение выражения может быть присвоено переменной или свойству, если только оно имеет тип данных, совместимый с типом переменной. Нельзя присвоить строковое выражение (string expression) числовой переменной (numeric variable); нельзя присвоить числовое выражение строковой переменной.
Переменные типа Variant могут присваиваться строчным или числовым переменным. Однако обратное не всегда верно. Строковой переменной может быть присвоена любая Variant-переменная, кроме Null, но числовой переменной может быть присвоена только та Variant-переменная, значение которой может интерпретироваться как число. Для определения того, может ли Variant-переменная преобразована в число, можно использовать функцию IsNumeric.
Пример
Dim StrMy, IntMy
Let StrMy = "Опять — весна..."
Let IntMy = 25
Line Input #
Считывает одну строку из файла последовательного доступа и присваивает эту строку String-переменной.
Синтаксис
Line Input #fllenumber, varname
Синтаксис оператора Line Input # состоит из следующих элементов:
filenumber	Обязательный. Допустимый файловый номер.
varname	Обязательный. Допустимое имя переменной типа Variant или String.
Данные, считываемые оператором Line Input #, обычно записываются в файл оператором Print #.
Оператор Line Input # считывает из файла по одному символу, пока не встретит символ «возврата каретки» (Chr(13)) или последовательность «возврат каретки» — «перевод строки» (Chr(13) + Chr(10)). Последовательность «возврат каретки» — «перевод строки» (carriage return-linefeed) не добавляется к считываемой символьной строке.
Пример -
В качестве примера приведены две процедуры: для записи данных в файл (TestPrint) и для чтения данных из файла (Testinput). Запустите на выполнение первую процедуру. Затем откройте в Редакторе VB окно Immediate и выполните вторую процедуру для просмотра содержимого тестового файла.
728
Приложение В
Sub TestPrint()
' запись данных в файл TESTFILE Dim TextLine
Open "TESTFILE" For Output As #1
Print #1, "А теперь мне жизнь - могила,”
Print #1, "Белый свет душе постыл,"
Print #1, "Грустен лес, поток уныл..."
Print #1, "Хлоя - другу изменила!.."	»
Print #1, "Я для милой... уж не мил!.."
Print #1,
Print #1, Tab(10); "А.С. Пушкин"
Close #1
End Sub
Sub Testinput()
' чтение данных из файла TESTFILE Dim TextLine
Open "TESTFILE" For Input As #1 Do While Not EOF(l)
Line Input #1, TextLine
Debug.Print TextLine
Loop
Close #1
End Sub
Load
Загружает, но не показывает объект.
Синтаксис
Load object
Шаблон object представляет объектное выражение (object expression), которое преобразуется к объекту в Applies То list.
При загрузке объект помещается в память, но остается невидимым. Чтобы объект стал видимым, необходимо выполнить его метод Show. Если объект остается невидимым, с невозможно «общаться».
Пример
Private Sub UserForm_Initialize()
Load UserForm2
UserForm2.Show
End Sub	i
Lock, Unlock
Управляет доступом ко всему или части файла, открытого с использованием оператора Open.
Синтаксис
Lock [#]filenumber[, recordrange]
Unlock [#]filenumber[, recordrange]
Синтаксис оператора Lock (и Unlock) состоит из следующих элементов:
filenumber	Обязательный. Любой допустимый файловый номер.
recordrange	Необязательный. Диапазон записей для открытия (закрытия) доступа.
Операторы в VBA
729
Аргумент recordrange имеет следующий синтаксис: recnumber | [start] То end
recnumber	Номер записи (файл в режиме Random) или номер байта (файл в режиме Binary), на который устанавливается или отменяется доступ.
start	Номер первой записи (или байта) для открытия или закрытия доступа.
end	Номер последней записи (или байта) для открытия или закрытия доступа.
Операторы Lock и Unlock используются в среде, где к одному и тому же файлу необходим доступ из нескольких процессов (processes), и всегда используются вместе. Аргументы этих операторов должны точно совпадать.
Первая запись (или байт) в файле находится в позиции 1, вторая запись (или байт) — в позиции 2 и т.д. Если указывается (в операторах Lock, Unlock) только одна запись, то только к этой записи будет открыт или закрыт доступ. Если определяется диапазон записей и опускается начальная запись (start), режим доступа задается для всех записей с первой до указанной последней записи (end). Использование Lock (Unlock) без аргумента recnumber управляет доступом ко всему файлу.
LSet
Выполняет левое выравнивание строки внутри строковой переменной или копирует переменную одного пользовательского типа в другую переменную пользовательского типа, отличного от первого.
Синтаксис
LSet stringvar = string
LSet varnamel = varname2
Синтаксис оператора LSet состоит из следующих элементов:
stringvar	Обязательный. Имя строковой переменной.
string	Обязательный. Строковое выражение, которое будет выравниваться внутри stringvar.
varnamel	Обязательный. Имя переменной пользовательского типа, в которое будет производиться копирование.
varname2	Обязательный. Имя переменной пользовательского типа, из которого будет производиться копирование.
Оператор LSet заменяет все левые символы в stringvar пробелами. Если string длиннее, чем stringvar, LSet помещает в stringvar только «наиболее левые» символы из string, количество которых равно длине строки stringvar.
Пример (см. пример для RSet)
Dim StrMyVar
StrMyVar = "0123456789"	' инициализация для задания длины строки
LSet StrMyVar = "<-Left"	' StrMyVar теперь: "<-Left ".
730
Приложение В
Mid
Выполняет замену указанного числа символов в Variant-переменной (String) на символы другой строки.
Синтаксис	»
Mid(stringvar, start], length]) — string
Синтаксис оператора Mid состоит из следующих элементов:
stringvar	Обязательный. Имя строчной переменной для модификации.
start	Обязательный; Variant (Long). Позиция символа в stringvar, с которой начинается заменяемая часть строки.
length	Необязательный; Variant (Long). Число заменяемых символов.
string	Обязательный. Строковое выражение для замены.
Число заменяемых символов всегда меньше или равно числу символов с stringvar.
Не следует путать оператор Mid с функцией Mid, которая возвращает значение [тип Variant (String)], содержащее указанное число символов из строки, и имеет похожий синтаксис.
Примеры
Dim StringMy
StringMy = "Мама Катю мыла"
Mid(StringMy, 5, 3) = "Сашу"
Mid(StringMy, 5) = "Катю"
Mid(StringMy, 5) = "кашу варила"
1 функция Mid возвращает значение SMidWords = Mid(StringMy, 1, 9) &
' StringMy = "Мама Сашу мыла"
' StringMy = "Мама Катю мыла"
' StringMy = "Мама кашу варила"
'Мама кашу не варила':
" не " & Mid(StringMy, 11, 6)
MkDir
Создает новый каталог (или папку).
Синтаксис
MkDir path
Обязательный аргумент path — строковое выражение, определяющее создаваемый каталог (или папку). Аргумент path может включать драйвер. Если драйвер не указывается, MkDir создает новый каталог (или папку) на текущем драйвере.
Пример
MkDir "NewDir" ' создать каталог на текущем драйвере
Name
Переименовывает дисковый файл, каталог (папку).
Синтаксис
Name oldpathname As newpathname	,
Синтаксис оператора Name состоит из следующих элементов:
oldpathname	Обязательный. Строковое выражение, определяющее текущее имя и местонахождение файла; может включать каталог (папку) и драйвер диска.
Операторы в VBA
731
newpathname	Обязательный. Строковое выражение, определяющее новое имя и местонахождение файла; может включать каталог (папку) и драйвер диска.
Оператор Name переименовывает файл и перемещает его в другой каталог (папку). Оператор Name может перемещать файл с одного драйвера (диска) на другой, но он может переименовать только существующий каталог (папку), если в обоих аргументах указан один и тот же драйвер. Оператор Name не может создать новый файл, каталог (папку).
Использование оператора Name с открытым файлом вызовет ошибку. Аргументы оператора Name не могут включать символ множественной подстановки (*) и одиночной подстановки (?).
Пример
Dim StrOldName As String, StrNewName As String
StrOldName = "OLDFILE"
StrNewName = "NEWFILE"
Name StrOldName As StrNewName
On Error
Делает доступным обработчик ошибок и определяет его положение внутри процедуры; используется также и для запрета обработки ошибок.
Синтаксис
On Error GoTo line
On Error Resume Next
On Error GoTo 0
Синтаксис оператора On Error имеет следующие формы:
On Error GoTo line	Делает доступным обработчик ошибок, который начинается со строки, определенной аргументом line. Аргумент line может быть меткой или числом. При возникновении ошибки управление выполнением программы передается на строку кода с меткой line. Таким образом происходит активизация обработчика ошибок. Метка line должна находиться в той же процедуре, что и оператор On Error.
On Error Resume Next	Указывает на то, что при возникновении ошибки управление выполнением программы передается на оператор, следующий непосредственно за тем, в котором произошла ошибка. Этот оператор позволяет продолжить выполнение программы, несмотря на возникновение run-time-ошибки. Оператор On Error Resume Next становится неактивным при вызове другой процедуры.
On Error GoTo 0	Отключает пользовательский обработчик ошибок в данной процедуре. Этот оператор не указывает метку 0 в качестве начала обработчика ошибки, даже если в процедуре действительно имеется такая метка. Без этого оператора обработчик ошибок «отключается» автоматически после окончания работы процедуры.
Пользовательские обработчики ошибок являются составной частью «дружественного» интерфейса. Если во время работы пользователя с вашим приложением
732
Приложение В
возникает непредвиденная вами ситуация, то в любом случае не стоит оставлять пользователя «наедине» с системой VBA, не настолько дружественной, как хороший разработчик приложений. VBA «знает» очень мало о том, в каких местах вашего программного кода и какие могут возникать ошибки. Разработчик же приложения должен знать все «тонкие» места в коде и ожидать те или иные ошибки. Даже если приложение просто пытается открыть файл, который нечаянно «убили», VBA-сообщение об отсутствии файла не так информативно, как могло бы быть сообщение разработчика, которое не только должно сообщить об отсутствии файла, но и предложить возможные пути его восстановления или замены этого файла его старой копией.
Следует различать состояния «доступность» («enabled») и «активность» («active») обработчика ошибок. Обработчик доступен, если оператор On Error выполнен, но ошибка еще не возникла. Обработчик активен, когда им выполняется обработка некоторой возникшей ошибки. Если ошибка возникает, когда обработчик активен (обрабатывает ранее возникшую ошибку), эта ошибка не обрабатывается и управление передается в вызывающую процедуру. Если вызывающая процедура имеет обработчик ошибок, находящийся в состоянии «enabled», он переходит в состояние «active» (т.е. обработки ошибки). Если обработчик вызывающей процедуры находится в состоянии «active», то управление передается предыдущей вызывающей процедуре с обработчиком в состоянии «enabled», но не «active». Т.е. в цепочке вызывающих процедур ищется обработчик ошибок в состоянии «enabled», готовый обработать ошибку.
Обычно в процедурах обработки ошибок для определения причины ошибки используется свойство Number объекта Err. Сообщение об ошибке (довольно «скупое»), связанное с Err.Number, содержится в Err.Description. Поэтому обычно на стадии отладки после метки, на которую передается управление выполнением программы в случае возникновения (ожидаемой) ошибки, помещается следующий оператор:
MsgBox "Error " & Err &	& Err.Description
Следующая функция использует On Error и предназначена для создания базы данных на SQL Server. Если подключение по каким-либо причинам невозможно, функция выдаст (при помощи функции MsgBox) сообщение, из которого можно будет понять причину неудачи.
Function DataBaseCreate(DataBaseName As String) As Boolean
' простая Функция создания базы данных на SQL Server ' DataBaseName - имя базы f
Dim wrk As Workspace, cnn As Connection, strConnect As String
On Error GoTo Err_DataBaseCreate
' строка подключения strConnect = "ODBC;DSN=finan;UID=sa;PWD="
Set wrk = DBEngine.CreateWorkspace("NewODBCDirect", _ "sa", dbUseODBC)
' устанавливаем тип драйвера курсора как wrk.DefaultCursorDriver = dbUseClientBatchCursor
' открываем соединение
Set cnn = wrk.OpenConnection("finan", dbDriverNoPrompt, _ False, strConnect)
' создать, наконец, указанную базу на сервере ' cnn.Execute "CREATE DATABASE " & DataBaseName cnn.Execute "CREATE TABLE T2 " &
"(C_KOD VARCHAR(12) NOT NULL, " &
Операторы в VBA
733
"C_NAMET VARCHAR(30) )"
Exit_DataBaseCreate: cnn. Close Exit Function
Err_DataBaseCreate:
If Err.Number = 3146 Then ' такой номер выдается при попытке создать уже имеющуюся базу MsgBox "Проверьте наличие такой базы на сервере"
Else ' вывод номера и описания ошибки MsgBox "Error " & Err.Number &	" & Err.Description
End If
Resume Exit_DataBaseCreate
End Function
В следующей процедуре используется On Error Resume Next для того, чтобы при определении отсутствия в системе экземпляра приложения Excel программа не завершалась с ошибкой.	*
Sub TestError()
Dim xlApp As Object
Dim xlSheet As Object On Error Resume Next Set xlApp = Nothing Set xlApp = GetObject(, "Excel.Application") If Err.Number <> 0 Then
Set xlApp = CreateObject("Excel.Application") End If Err.Clear
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook.Worksheets(1) xlSheet.Application.Visible = True End Sub
On...GoSub, On...GoTo
«Передают управление» выполнением программы на одну из нескольких определенных строк кода в зависимости от значения некоторого значения.
Синтаксис
On expression GoSub destinationlist On expression GoTo destinationlist
Синтаксис операторов On...GoSub и On...GoTo включает следующие элементы:
Expression	Обязательный. Любое численное выражение, которое приводится к целому числу в диапазоне от 0 до 255, включительно. Если expression — не является целым, оно предварительно округляется.
destinationlist	Обязательный. Список номеров строк (line numbers)1 или строковых меток (line labels)1 2, разделенных запятыми.
1 Используется для идентификации единственной строки кода. Номер строки может быть любой комбинацией цифр, которая уникальна внутри модуля, где используется этот номер. Номера строк должны начинаться в первой колонке.
2 Используется для идентификации единственной строки кода. Метка строки может быть любой комбинацией символов, которая начинается с буквы и завершается двоеточием (:). Метки строк нечувствительны к регистру и должны начинаться в первой колонке.
734
Приложение В
Значение expression определяет, на какую строку в списке destinationlist выполняется переход. Если значение expression меньше чем 1, или больше чем число элементов в списке, то происходит следующее:
если expression	ТО
равно 0	«Управление передается» на оператор, рледующий за операторами On...GoSub и On...GoTo.
больше числа элементов в списке	«Управление передается» на оператор, следующий за операторами On...GoSub и On...GoTo.
отрицательно	Инициируется ошибка.
больше, чем 255	Инициируется ошибка.
В одном списке можно смешивать номера строк и строковые метки. Можно использовать неограниченное количество номеров строк и строковых меток.
Пример
Sub OnGosubGotoDemo() Dim Number, MyString
Number = 2
On Number GoSub Subl, Sub2 ' On...GoSub.
On Number GoTo Linel, Line2
Exit Sub
Subl :
MyString = "In Subl" : Return
Sub2 :
MyString = "In Sub2" : Return
Linel:
MyString = "In Linel"
Line2:	'
MyString = "In Line2" End Sub
Open
Открывает файл для ввода/вывода.
Синтаксис
Open pathname For mode [Access access] [lock]
As [#]f lienumber [Len=reclength]	•
Синтаксис оператора Open состоит из следующих элементов:
pathname	Обязательный. Строковое выражение, которое определяет имя файла; может включать каталог (папку) и драйвер.
mode	Обязательный. Ключевое слово, определяющее режим файла: Append, Binary, Input, Output или Random.
access	Необязательный. Ключевое слово, определяющее операции, выполняемые с фалом: Read, Write или Read Write.
Lock	Необязательный. Ключевое слово, определяющее ограничения для других процессов: Shared, Lock Read, Lock Write и Lock Read Write.
Операторы в VBA
735
Filenumber	Обязательный. Допустимый файловый номер в диапазоне от 1 до 511, включительно. Для получения следующего допустимого файлового номера следует использовать функцию FreeFile.
reclength	Необязательный. Число, меньшее или равное 32767 (байтов). Для файлов, открытых в режиме прямого доступа (mode — Random), это значение равно длине записи. Для последовательного доступа это значение равно числу буферизованных символов.
Перед выполнением файловых операций чтения/записи файл необходимо открыть. Оператор Open выделяет буфер ввода/вывода для файла и определяет режим доступа к этому буферу. Если файл, указанный аргументом pathname, не существует, он создается для режимов Append, Binary, Output или Random.
Опция Len при mode со значением Binary игнорируется.
Пример
Sub OpenTestO
Dim I, FileName
For I = 1 To 3
FileName = "TEST"	& I	'	создать имя файла
Open FileName For	Output	As #1	'	открыть файл
Print #1, "запись	в файл	" & FileName	'	записать строку в	файл
Next I
Close	' закрыть все три файла
End Sub
Option Base
Используется на модульном уровне для объявления нижней границы массива по умолчанию.
Синтаксис
Option Base {0 | 1}
По умолчанию нижняя граница массива — это значение 0. При использовании этого оператора необходимо располагать его в модуле до объявления процедур. Оператор Option Base может появляться в модуле только один раз и предшествовать объявлению массивов. При этом он воздействует только на нижнюю границу (может быть определена при помощи функции LBound) массивов в модуле, в котором он определен.
Option Compare
Используется на модульном уровне для объявления метода по умолчанию при сравнении строчных данных.
Синтаксис
Option Compare {Binary | Text I Database}
Оператор Option Compare следует располагать в модуле перед определением процедур.
Оператор Option Compare определяет метод сравнения строк (string comparison) (Binary, Text или Database) для модуля. Если модуль не содержит оператор Option Compare, по умолчанию при текстовом сравнении используется метод Binary.
736
Приложение В
При использовании Option Compare Binary сравнение строк основывается на двоичном представлении символов, т.е. на порядке расположения символов в таблице двоичного представления. В Microsoft Windows порядок расположения символов определяется кодовой страницей.
Для Option Compare Text двоичный эквивалент для каждого символа не используется. При этом буквы верхнего регистра эквивалентны буквам нижнего регистра.
Option Compare Database может использоваться только в Microsoft Access. При этом сравнение строк основывается на параметре, определенном локальным ID базы данных, где возникают эти сравнения.
Option Explicit
Используется на модульном уровне для обязательного явного объявления всех переменных в модуле.
Синтаксис
Option Explicit
Оператор Option Explicit должен располагаться в модуле до объявления процедур.
При использовании оператора Option Explicit необходимо явно объявлять все переменные с помощью операторов Dim, Private, Public, ReDim или Static. Если этого не сделать, возникнет ошибка времени компиляции.
Если оператор Option Explicit не используется, все необъявленные переменные имеют тип Variant.
Пример
Option explicit
Dim VarMy
IntMy =103	' эта строка вызовет ошибку
VarMy = 101	1 эта строка не вызовет ошибку
Option Private
При использовании в host-приложениях, которые допускают ссылки на множество проектов, Option Private Module препятствует ссылкам на содержимое модуля из внешней среды этого проекта. В host-приложениях, которые не допускают таких ссылок, например, отдельные версии Visual Basic, оператор Option Private не действует.
Синтаксис
Option Private Module	v
Оператор Option Private на модульном уровне должен появляться перед описанием процедур. Если модуль включает оператор Option Private Module, public-элементы, переменные, объекты и определяемые пользователем типы, объявленные на модульном уровне, остаются доступными внутри проекта, содержащего этот модуль, но недоступными другим приложениям или проектам.
Пример
Option private Module
Print #
Записывает отформатированные для отображения данные в файл с последовательным доступом.
Операторы в VBA
737
Синтаксис
Print #filenumber, [outputlist]
Синтаксис оператора Print # включает следующие элементы:
Filenumber	Обязательный. Любой допустимый файловый номер.
outputlist	Необязательней. Выражение или список выражений для печати.
Аргумент [{Spc(n)	outputlist следующий синтаксис: ТаЬ[(л)]}] {expression] [charpos]
Spc(n)	Используется для вставки в вывод символов пробела; п — это число вставляемых символов пробелов.
Tab(n)	Используется для позиционирования точки (курсора) вставки в определенную колонку, где п — номер колонки. Использование Tab без аргументов приводит к позиционированию точки вставки в начало следующей зоны печати (print zone).
expression	Численные или строковые выражения для печати.
\ charpos	Определяет точку вставки для следующего символа. Чтобы позиционировать точку вставки сразу после последнего отображенного символа, используйте точку с запятой. Для позиционирования точки вставки в определенную колонку используйте Tab(n). Использование Tab без аргументов приводит к позиционированию точки вставки в начало следующей зоны печати. Если charpos опускается, очередной символ печатается на следующей строке.
Данные, записываемые оператором Print #, обычно считываются из файла при помощи операторов Line Input # или Input. Если outputlist не используется, а после filenumber включается разделитель списка, в файл записывается пустая строка. Несколько записываемых в файл выражений (на одной строке кода) могут разделяться либо пробелами, либо двоеточиями.
Пример
Sub TestPrint()
' запись данных в файл TESTFILE
Dim TextLine
Open "TESTFILE" For Output As #1
Print #1, "В Академии наук"
Print #1, "Заседает князь Дундук."
Print #1, "Говорят, не подобает "
Print #1, "Дундуку такая честь;"
Print #1, "Почему ж он заседает?"
Print #1, "Потому что есть чем сесть
Print #1,
Print #1, Tab(10); "А.С. Пушкин"
Close #1
End Sub
Private
Используется на модульном уровне для объявления private-переменных и выделения для них памяти.
24 Программирование на VBA 2002
738
Приложение В
Синтаксис
Private [WithEvents] varname[([subscripts])] [As [New] type] [,[WithEvents] varname[([subscripts])] [As [New] type]]
Синтаксис оператора Private включает следующие элементы:
WithEvent s	Необязательный. Ключевое слово, которое определяет varname — объектная переменная для реакции на события, вызываемые ActiveX-объектом. WithEvents допускается только в модулях класса. Это ключевое слово нельзя использовать при объявлении массивов. Нельзя использовать ключевое слово New с ключевым словом WithEvents.
varname	Обязательный. Имя переменной.
subscripts	Необязательный. Размерности массива-переменной; можно объявлять до 60 размерностей. Аргумент subscripts имеет следующий синтаксис: [lower То] upper [,[bower То] upper] ... Если явно не указывается lower, то нижняя граница массива определяется оператором Option Base. Если же оператор Option Base в коде не используется, значение нижней границы по умолчанию равняется 0.
New	Необязательный. Ключевое слово, позволяющее создание объекта. Использование New при объявлении объектной переменной приводит к созданию нового экземпляра объекта и ссылки на него, поэтому в операторе Set (назначает ссылку на объект) для этого объекта нет необходимости.
Type	Необязательный. Тип (данных) переменной; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), String * length (только фиксированной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
Оператор Private используется для объявления переменных (объектных переменных), доступных только в модуле, в котором они объявлены. Например, в следующей строке объявлены переменная целого типа j и объектная переменная типа Table с именем newT.
Private 3 As Integer, newT As New Table
Если при объявлении объектной переменной ключевое слово New не используется, то оператор Private не создает новый экземпляр объекта, а создает, практически, ссылочную переменную, которая пока не ссылается ни на какой конкретный объект (участок памяти). Чтобы таким образом объявленная объектная переменная ссылалась на объект, необходимо оператором Set указать этот объект. До тех пор, пока этого не сделано, объектная переменная имеет специальное значение Nothing, которое указывает на то, что переменная не ссылается ни на какой объект.
Если при объявлении переменных (объектных переменных) тип переменной не указывается, VB умолчанию объявляет для нее тип Variant. Из синтаксиса оператора Private следует, что с его помощью можно объявлять массивы (динамические — в том числе).
Property Get	'
Объявляет имя, аргументы и код, формирующие Property-процедуру, которая считывает (извлекает) значение свойства (property).
Операторы в VBA
739
Синтаксис
[Public | Private I Friend] [Static] Property Get name [(arglist)]
[As type]
[statements]
[name = expression]
[Exit Property]
[statements]
[name = expression^
End Property
Значение элементов синтаксиса оператора Property Get:
Public	Необязательный. Указывает на то, что процедура Property Get доступна всем другим процедурам во всех модулях. Если используется в модуле, содержащем оператор Option Private, эта процедура не доступна вне проекта.
Private	Необязательный. Указывает на то, что процедура Property Get доступна другим процедурам в модуле, в котором она объявлена.
Friend	Необязательный. Используется только в модуле класса. Указывает на то, что процедура Property Get видима во всем проекте.
Static	Необязательный. Указывает на то, что локальные переменные Property Get-процедуры сохраняют свои значения между вызовами. Static-атрибут не оказывает действия на переменные, которые объявляются вне процедуры Property Get, даже если они используются в этой процедуре.
name	Обязательный. Имя процедуры Property Get; должно соответствовать стандартным соглашениям об именовании переменных, за исключением того, что в одном модуле имя может быть таким же, как и в процедуре Property Let или Property Set.
arglist	Необязательный. Список разделенных запятыми переменных, представляющих аргументы, передаваемые процедуре Property Get при ее вызове. Имя и тип каждого аргумента в процедуре Property Get должны быть теми же, что и в соответствующей процедуре Property Let (если она имеется).
type	Необязательный. Тип (данных) значения, возвращаемого процедурой Property Get; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (кроме фиксированной длины), Object, Variant, пользовательским типом и массивом. Возвращаемый тип процедуры Property Get должен быть тем же, что и тип последнего аргумента в соответствующей процедуре Property Let (если она имеется), которая определяет значение, присваиваемое свойству.
statements	Необязательный. Любая группа операторов, которая выполняется в теле процедуры Property Get.
expression	Необязательный. Значение свойства, возвращаемое процедурой, определяемой оператором Property Get.
Аргумент arglist имеет следующий синтаксис: [Optional] [ByVai I ByRef] [ParamArray] varname]( )] [As type] [= defaultvalue]
24*
740
Приложение В
Optional	Необязательный. Указывает, что аргумент является необязательным. Если используется, все последующие аргументы в arglist должны быть необязательными и объявляться с использованием слова Optional.
By Vai	Необязательный. Указывает, что аргумент передается по значению (by value).
ByRef	Необязательный. Указывает, что аргумент передается по ссылке (by reference). В Visual Basic ByRef используется по умолчанию.
ParamArray	Необязательный. Используется только как последний аргумент в arglist для указания того, последний аргумент — это Optional-массив Variant-элементов. Ключевое слово Par am Array позволяет использовать переменное число аргументов и не может применяться с ByVai, ByRef или Optional.
varname	Обязательный. Имя переменной, представляющей аргумент; должно соответствовать стандартным соглашениям об именовании переменных.
type	Необязательный. Тип аргумента, передаваемого процедуре; может быть типом Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (фиксированной длины), Object, Variant или объектным типом. Если параметр — не Optional, может быть указан также пользовательский тип.
defaultvalue	Необязательный. Любая константа или константное выражение. Допустима только для Optional-параметров. Если тип — Object, явным значением по умолчанию может быть только Nothing.
Если явно не указано использование Public, Private или Friend, процедура Property является Public по умолчанию. Если не используется Static, локальные переменные не сохраняют свои значения между вызовами процедуры. Ключевое слово Friend можно использовать только в модуле класса. Однако Friend-процедура может быть доступна любой процедуре модуля проекта.
При программировании классов некоторые данные класса (обычно они называются свойствами) можно защитить от прямого обновления и даже считывания. Пользователь класса (в качестве которого выступают программы) может не иметь непосредственного доступа к данным класса, но может обращаться к ним посредством интерфейсных процедур. В качестве таких процедур в VB используются процедуры с наименованиями Property Let и Property Let. Особенно важным является возможность проверки корректности данных, записываемых в закрытые элементы класса при помощи кода процедур Property Let.
Пример
Пусть, например, необходимо разработать класс, в котором будут содержаться такие сведения о накладной: дата, номер накладной, код отправителя товара, код получателя товаров. Код для описания данных (в модуле класса в разделе объявлений) может иметь вид:
Private Dm_Date As Date
Private Im_Num As Integer
Private Cm_Sou As String
Private CmWne As String
Для получения значения закрытой переменной Dm_Date как общедоступного свойства D_Date можно написать следующий код:
Операторы в VBA
741
Public Property Get D_Date() As Date
D_Date = Dm_Date
End Property
Точно так же можно написать код для получения остальных свойств объекта класса:
Public Property Get I_Num() As Integer
I_Num = Im_Num
End Property	/
Public Property Get C_Sou() As String
C_Sou = Cm_Sou
End Property
Public Property Get C_Wne() As String
C_Wne = Cm_Wne
End Property
Property Let
Объявляет имя, аргументы и код, формирующие Property Let процедуру, которая присваивает значение свойству.
Синтаксис
[Public I Private | Friend] [Static]
Property Let name ([arglist,] value)
[statements]
[Exit Property]
[statements]
End Property
Значения элементов синтаксиса оператора Property Let:
Public	Необязательный. Указывает на то, что процедура Property Let доступна всем другим процедурам во всех модулях. Если используется в модуле, содержащем оператор Option Private, эта процедура недоступна вне проекта.
Private	Необязательный. Указывает на то, что процедура Property Let доступна другим процедурам в модуле, в котором она объявлена.
Friend	Необязательный. Используется только в модуле класса. Указывает на то, что процедура Property Let видима во всем проекте.
Static	Необязательный. Указывает на то, что локальные переменные Property Let-процедуры сохраняют свои значения между вызовами. Static-атрибут не оказывает действия на переменные, которые объявляются вне процедуры Property Let, даже если они используются в этой процедуре.
i name	Обязательный. Имя процедуры Property Let; должно соответствовать стандартным соглашениям об именовании переменных, за исключением того, что в одном модуле имя может быть таким же как и в процедуре Property Get или Property Set.
arglist	Обязательный. Список разделенных запятыми переменных, представляющих аргументы, передаваемые процедуре Property Let при ее вызове. Имя и тип каждого аргумента в процедуре Property Let должны быть теми же, что и в соответствующей процедуре Property Get (если она имеется).
742
Приложение В
Public	Необязательный. Указывает на то, что процедура Property Let доступна всем другим процедурам во всех модулях. Если используется в модуле, содержащем оператор Option Private, эта процедура недоступна вне проекта.
value	Обязательный. Переменная, значение которой присваивается свойству. При вызове процедуры этот аргумент появляется в правой части вызывающего выражения. Тип переменной value должен совпадать с типом возвращаемого значения соответствующей Property Get-процедуры.
statements	Необязательный. Любая группа операторов, которая выполняется в теле процедуры Property Let.
Аргумент arglist имеет следующий синтаксис: [Optional] [ByVai | ByRef] [ParamArray] varname[( )] [As type] [= defaultvalue]
Optional	Необязательный. Указывает, что аргумент является необязательным. Если используется, все последующие аргументы в arglist должны быть необязательными и объявляться с использованием слова Optional.
ByVai	Необязательный. Указывает, что аргумент передается по значению.
ByRef	Необязательный. Указывает, что аргумент передается по ссылке. В Visual Basic ByRef используется по умолчанию.
ParamArray	Необязательный. Используется только как последний аргумент в arglist для указания того, последний аргумент — это Optional-массив Variant-элементов. Ключевое слово ParamArray позволяет использовать переменное число аргументов и не может применяться с ByVai, ByRef или Optional.
varname	Обязательный. Имя переменной, представляющей аргумент; должно соответствовать стандартным Соглашениям об именовании переменных.
type	Необязательный. Тип аргумента, передаваемого процедуре; может быть типом Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (фиксированной длины), Object, Variant или объектным типом. Если параметр — не Optional, может быть указан также пользовательский тип.
defaultvalue	Необязательный. Любая константа или константное выражение. Допустима только для Optional-параметров. Если тип — Object, явным значением по умолчанию может быть только Nothing.
Каждый оператор Property Let должен определять, по крайней мере, один аргумент процедуры, которую этот оператор описывает. Этот аргумент (или последний, если их несколько) содержит значение, которое присваивается свойству при вызове процедуры, определенной оператором Property Let.
Если явно не указано использование Public, Private или Friend, процедура Property является Public по умолчанию. Если не используется Static, локальные переменные не сохраняют свои значения между вызовами процедуры. Ключевое слово Friend можно использовать только в модуле класса. Однако Friend-процедура может быть доступна любой процедуре модуля проекта.
Операторы в VBA
743
Оператор Exit Property (их может более одного в процедуре) приводит к немедленному выходу из Property Let-процедуры. Выполнение программы продолжается с оператора, следующего за тем, который вызвал Property Let-процедуру.
Подобно Function- и Property Get-процедурам, Property Let-процедура — это отдельная процедура, которая может принимать аргументы, выполнять набор операторов и изменять значения своих аргументов. Однако в отличие от Function-и Property Get-процедур, которые возвращают значение, Property Let-процедуры можно располагать только в левой части выражения присваивания свойства или оператора Let.
Пример
Для класса из примера оператора Property Get можно написать следующие процедуры Property Let:
Public Property Let D_Date(ByVai DatNew As Date) '
1 код для проверки корректности даты ' можно, например, исключить выходные и праздники
Dm_Date = DatNew
End Property
Public Property Let I_Num(ByVal NumNew As Integer)
' код для проверки корректности номера накладной
Im_Num = NumNew
End Property
Public Property Let C_Sou(ByVai SouNew As String)	y <
' код для проверки корректности кода источника
1	если такой код в базе данных отсутствует, функция ' может об этом сообщить
Cm_Sou = SouNew
End Property
Public Property Let C_Wne(ByVai WneNew As String)
'	код для проверки корректности кода приемника
'	если такой код в базе данных отсутствует, функция ' может об этом сообщить
Cm_Wne = WneNew
End Property
i
Property Set
Объявляет имя, аргументы и код, формирующие Property-процедуру, которая устанавливает ссылку на объект.
Синтаксис	>
[Public | Private I Friend] [Static]
Property Set name ([arg-list,] reference)
[ statements]
[Exit Property]
[statements]
End Property
744
Приложение В
Синтаксис оператора Property Set состоит из следующих элементов:
Public	Необязательный. Указывает на то, что процедура Property Set доступна всем другим процедурам во всех модулях. Если используется в модуле, содержащем оператор Option Private, эта процедура недоступна вне проекта.
Private	Необязательный. Указывает на то, что процедура Property Set доступна другим процедурам в модуле, в котором она объявлена.
Friend	Необязательный. Используется только в модуле класса. Указывает на то, что процедура Property Set видима во всем проекте.
Static	Необязательный. Указывает на то, что локальные переменные Property Set-процедуры сохраняют свои значения между вызовами. Static-атрибут не оказывает действия на переменные, которые объявляются вне процедуры Property Set, даже если они используются в этой процедуре.
name	Обязательный. Имя процедуры Property Set; должно соответствовать стандартным соглашениям об именовании переменных, за исключением того, что в одном модуле имя может быть таким же, как и в процедуре Property Get или Property Let.
arghst	Обязательный. Список разделенных запятыми переменных, представляющих аргументы, передаваемые процедуре Property Set при ее вызове.
reference	Обязательный. Переменная, содержащая объектную ссылку, используемую в правой части присвоения объектной ссылки.
statements	Необязательный. Любая группа операторов, которые должны выполняться в процедуре.
Аргумент arglist имеет следующий синтаксис: [Optional] [ByVai I ByRef] [ParamArray] varname[( )] [As type] [= defaultvalue]
Optional	Необязательный. Указывает, что аргумент является необязательным. Если используется, все последующие аргументы в arghst должны быть необязательными и объявляться с использованием слова Optional.
ByVai	Необязательный. Указывает, что аргумент передается по значению.
ByRef	Необязательный. Указывает, что аргумент передается по ссылке. В Visual Basic ByRef используется по умолчанию.
ParamArra У	Необязательный. Используется только как последний аргумент в arglist для указания того, что последний аргумент — это Optional-массив Variant-элементов. Ключевое слово ParamArray позволяет использовать переменное число аргументов и не может применяться с ByVai, ByRef или Optional.
varname	Обязательный. Имя переменной, представляющей аргумент; должно соответствовать стандартным соглашениям об именовании переменных.
Операторы в VBA
745
Optional	Необязательный. Указывает, что аргумент является необязательным. Если используется, все последующие аргументы в arghst должны быть необязательными и объявляться с использованием слова Optional.
Tz/pe	Необязательный. Тип аргумента, передаваемого процедуре; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (фиксированной длины), Object, Variant или объектным типом. Если параметр — не Optional, может быть указан также пользовательский тип.
defaultvalue	Необязательный. Любая константа или константное выражение. Допустима только для Optional-параметров. Если тип — Object, явным значением по умолчанию может быть только Nothing.
Каждый оператор Property Set должен определять, по крайней мере, один аргумент процедуры, которую этот оператор описывает. Этот аргумент (или последний, если их несколько) содержит объектную ссылку для свойства при вызове процедуры, определенной оператором Property Set. Это — reference в предыдущем синтаксисе. Может быть Optional.
Если явно не указано использование Public, Private или Friend, процедура Property является Public по умолчанию. Если не используется Static, локальные переменные не сохраняют свои значения между вызовами процедуры. Ключевое слово Friend можно использовать только в модуле класса. Однако Friend-процедура может быть доступна любой процедуре модуля проекта. Весь исполняемый код должен быть в процедуре. Нельзя определять процедуру Property Set внутри другой Property-, Sub- или Function-процедурьк
Оператор Exit Property (их может более одного в процедуре) приводит к немедленному выходу из Property Set-процедуры. Выполнение программы продолжается с оператора, следующего за тем, который вызвал Property Set-процедуру.
Подобно Function- и Property Get-процедурам, Property Set-процедура — это отдельная процедура, которая может принимать аргументы, выполнять набор операторов и изменять значения своих аргументов. Однако в отличие от Function-и Property Get-процедур, которые возвращают значение, Property Set-процедуры можно располагать только в левой части выражения присваивания свойства или оператора Set.
Public
Используется на модульном уровне для объявления public-переменных и выделения памяти для них.
Синтаксис
Public [WithEvents] varname[([subscripts])] [As [New] type]
[,[WithEvents] varname[([subscripts])] [As [New] type]] ...
Синтаксис оператора Public содержит следующие элементы:
WithEvents	Необязательный. Ключевое слово, которое указывает, что varname — объектная переменная, используемая для реакции на событие, инициированное ActiveX-объектом. WithEvents допускается только в модулях класса. Отдельных переменных с использованием ключевого слова WithEvents можно объявлять столько, сколько необходимо, но массив, используя его, создавать нельзя. Также нельзя использовать ключевое слово New при наличии WithEvents.
746
Приложение В
I varname	Обязательный. Имя переменной; должно соответствовать стандартным соглашениям об именовании переменных.
subscripts )	I	Необязательный. Размерность переменной-массива; можно объявить до 60 размерностей. Аргумент subscripts использует следующий синтаксис: [lower То] upper [, [lover То] upper] .... lower — нижний предел допустимых индексов массива; upper — верхний предел (является обязательным) для индексов массива. При наличии в операторе Dim только upper нижний предел определяется в зависимости от установки оператора Option Base.
New	Необязательный. Ключевое слово, позволяющее неявно создать объект. Если вы используете ключевое слово New при объявлении объектной переменной, создается новый экземпляр объекта, поэтому нет необходимости использовать оператор Set для назначения объекту ссылки.
type	Необязательный. Тип данных переменной; может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), String * length (для строк фиксированной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
Переменные, объявляемые оператором Public доступны всем процедурам всех модулей во всех приложениях, если используется оператор Option Private Module, при действии которого переменные имеют статус Public только в том проекте, в котором они находятся. Оператор Public нельзя применять в модуле класса для объявления переменной-строки фиксированной длины.
Оператор Public можно использовать для объявления типа переменной. Например, следующий оператор объявляет переменную типа Integer:
Dim IntName As Integer
Оператор Public можно использовать также для объявления переменной объектного типа:
Dim WorkShNew As Worksheet
ИЛИ
Dim WorkShNew As New Worksheet
Если при объявлении объектной переменной ключевое слово New не используется, то, чтобы объектная переменная ссылалась на объект, необходимо оператором Set указать этот объект. До тех пор, пока этого не сделано, объектная переменная имеет специальное значение Nothing, которое указывает на то, что переменная не ссылается ни на какой объект.
Оператор Public можно использовать (вместо оператора Dim) и для объявления массивов. После объявления динамического массива (при помощи пустых круглых скобок) следует для указания размерности массива применять оператор ReDim.
Put
Записывает данные из переменной в файл диска.
Синтаксис
Put [#] filenumber, [recnumber], varname
Операторы в VBA
747
Синтаксис оператора Put включает следующие элементы:
Filenumber	Обязательный. Любой допустимый файловый номер.
recnumber	Необязательный. Variant (Long). Номер записи (для режим доступа Random) или номер байта (для режим доступа Binary) для записи.
varnarrte	Обязательный. Имя переменной, содержащей записываемые в файл данные.
Данные, записанные оператором Put, обычно можно прочитать оператором Get.
Первая запись (или байт) в файле находится в позиции 1, вторая запись (или байт) — в позиции 2 и т.д. Если аргумент recnumber не указывается, номер записи (или байта) определяется как результат работы последнего оператора Get (или Put) или функции Seek.
Для файлов, открытых в Random-режиме, применяются следующие правила:
	Если длина записываемых данных меньше, чем длина, указанная в опции Len оператора Open, Put записывает последующие записи на границах длин записей. Пространство между концом одной записи и началом следующей записи заполняется имеющимся содержимым файлового буфера.
	Если записываемая переменная является строкой переменной длины, оператор Put записывает сначала 2-байтовый дескриптор (descriptor), содержащий длину строки, а затем — переменную. Поэтому длина записи, определяемая опцией Len в операторе Open, должна быть, по крайней мере, больше на 2 байта, чем действительная длина строки.
	Если записываемая переменная — Variant числового типа, Put записывает 2 байта, идентифицирующие VarType переменной Variant, а затем — само значение переменной. Длина записи (record), определяемая опцией Len в операторе Open, должна быть, по крайней мере, на 2 байта больше, чем действительное число байтов, необходимое для сохранения переменной.
	Если записываемая переменная — Variant, значение VarType которой равно 8 (String), оператор Put записывает 2 байта, идентифицирующие VarType, 2 байта, указывающие длину строки, а затем — сами строковые данные. Длина записи, определяемая опцией Len оператора Open, должна быть, по крайней мере, на 4 байта больше, чем действительная длина строки.
	Если записываемая переменная — динамический массив, оператор Put записывает дескриптор, длина которого равна 2 «плюс» 8, умноженное на число размерностей массива (2 + 8 * NumberOfDimensions). Длина записи, определяемая опцией Len в операторе Open, должна быть больше или равна сумме количества байтов, необходимых для записи массива, и длины дескриптора. Например, объявленный ниже массив требует при записи на диск 218 байтов — 18 (2 + 8 * 2) байтов занимает дескриптор и 200 (5 * 20 * 2) необходимо для хранения массива:
Dim MyArray(l То 5,1 То 20) As Integer
	Если записываемая переменная — массив фиксированного размера, оператор Put записывает только данные.
•	Если записываемая переменная — переменная любого другого типа (не строка переменной длины или Variant), Put записывает только данные. Длина записи, определяемая опцией Len в операторе Open, должна быть больше или равна длине записываемых данных.
	Оператор Put записывает элементы типов, определенных пользователем, как если бы они записывались отдельно, за исключением того, что между ними нет заполняющих элементов. На диске динамический массив определенного пользователем типа (записанный оператором Put) предваряется дескриптором, дли
748
Приложение В
на которого равна 2 «плюс» 8, умноженное на число размерностей: 2 + 8 * NumberOfDimensions. Длина записи, определяемая опцией Len в операторе Open, должна быть больше или равна сумме всех байтов, необходимых для чтения отдельных элементов, включая любые массивы и их дескрипторы.
Для файлов, открытых в Binary-режиме, применяются все Random-правила, кроме:
	Len-опция (параметр) оператора Open не действует. Оператор Put записывает все переменные на диск непрерывно, т.е. без заполняющих символов между записями.
 Для любого массива, кроме массива пользовательского типа, Put записывает только данные. Дескриптор не записывается.
» Put записывает строки переменной длины, которые не являются элементами пользовательских типов, без дескриптора 2-байтовой длины. Число записываемых байтов равно числу символов, имеющихся в строке
Пример
В следующем примере описывается пользовательский тип данных (Record) и процедура записи (TestPut) данных в файл.
Type Record 1 Определенный пользователем тип ID As Integer FirstName As String * 20 LastName As String * 20
End Type
Sub TestPut()
' Тестирование Put
Dim MyRecord As Record, RecordNumber
Kill "TESTFILE"
Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
MyRecord.FirstName = "Петр"
MyRecord.LastName = "Петров"
MyRecord.ID = 333
Put #1, 2, MyRecord
MyRecord.FirstName = "Сидор"
MyRecord.LastName = "Сидоров"
MyRecord.ID = 111
Put #1, 3, MyRecord
MyRecord.FirstName = "Иван"
MyRecord.LastName = "Иванов"
MyRecord.ID = 222
Put #1, 1, MyRecord	'
Close #1
End Sub
RaiseEvent
Инициирует событие, объявленное на модульном уровне в классе (class), форме (form) или документе (document).
Синтаксис
RaiseEvent eventname [(argumentlist)]
Обязательный аргумент eventname — имя события, объявляемого внутри модуля; должно соответствовать стандартным соглашениям об именовании переменных.
Операторы в VBA
749
Синтаксис оператора RaiseEvent включает следующие элементы:
eventname	Обязательный. Имя события.
argumentlist	Необязательный. Разделяемый запятыми список аргументов, в качестве которых могут использоваться переменные, массивы или выражения. Если аргументов нет, скобки не должны использоваться.
Randomize
Инициализирует генератор случайных чисел.
Синтаксис
Randomize [number]	'	.	.
Необязательный аргумент number — значение типа Variant или любое числовое выражение.
Оператор Randomize использует number для инициализации генератора случайных чисел функции Rnd (см. Приложение Г), задавая новое seed-значение. Если аргумент number опускается, то в качестве нового seed-значения используется значение системного таймера.
Пример
Следующий код генерирует строку из случайных чисел в диапазоне от 1 до 6.
Dim MyValue, MyString As String
Randomize
MyString = ""
For I = 0 To 9
MyValue = Int((6 * Rnd) + 1)
MyString = MyString & " " & MyValue
Next
ReDim
Используется на уровне процедуры для переопределения размеров динамический массивов.
Синтаксис
ReDim [Preserve] varname(subscripts) [As type] [, varname(subscripts) [As type]] ...
Синтаксис оператора ReDim состоит из следующих элементов:
Preserve	Необязательный. Ключевое слово, используемое для сохранения данных в существующем массиве при изменении последней размерности.
| varname	Обязательный. Имя переменной.
subscripts	Обязательный. Размерности массива-переменной; можно объявлять до 60 размерностей. Аргумент subscripts имеет следующий синтаксис: [lower То] upper [,[lower То] upper] ... Если lower явно не указан, нижняя граница массива определяется оператором Option Base. Если в коде не используется оператор Option Base, нижняя граница считается равной нулю.
750
Приложение В
type	Необязательный. Тип (данных) переменной (массива); может быть Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (для строк переменной длины), String * length (для строк фиксированной длины), Object, Variant, определенным пользователем типом или объектным типом.
Оператор ReDim используется для определения и переопределения размера динамического массива, который перед этим уже был формально объявлен при помощи операторов Private, Public или Dim с пустыми скобками (вместо указания размерностей).
Оператор ReDim можно применять повторно для изменения числа элементов и размерностей массива. Однако нельзя при помощи оператора ReDim изменить тип массива (не для Variant-массива). Если массив содержит данные типа Variant, тип его элементов можно изменить (предложением As type)-, это не относится к оператору ReDim, в котором используется ключевое слово Preserve, не допускающее изменения типа данных.
При использовании ключевого слова Preserve можно изменить размер только последней размерности; количество самих размерностей изменить нельзя.
Пример
Dim MyArrayO As Integer ' объявление динамического массива
Redim MyArray(lO)	' выделение памяти для массива
Redim Preserve MyArray(25) ' добавление 15-ти элементов
Rem
Используется для включения в код комментариев.
Синтаксис
Rem commen t
Можно также использовать следующий синтаксис: ' comment
Необязательный аргумент comment — текст комментария. Между ключевым словом Rem и comment обязательно следует помещать пробел.
Reset
Закрывает все файлы на диске, которые были открыты с использованием оператора Open.
Синтаксис
Reset
Оператор Reset закрывает все активные файлы, открытые оператором Open, и записывает содержимое всех файловых буферов на диск.
Resume
Возобновляет выполнение кода после того, как заканчивает работу процедура обработки ошибки.
Операторы в VBA
751
Синтаксис
Resume [0] Resume Next Resume line
Синтаксис оператора Resume может быть одной из следующих форм:
Resume	Если ошибкгС возникла в той же самой процедуре, в которой находится обработчик ошибок, выполнение кода возобновляется с того же оператора, который вызвал ошибку. Если ошибка возникла в вызванной процедуре, выполнение кода возобновляется с оператора, который последним вызвал процедуру, содержащую обработчик ошибок.
Resume Next	Если ошибка возникла в той же самой процедуре, в которой на- > ходится обработчик ошибок, выполнение кода возобновляется с оператора, находящегося сразу за тем, который вызвал ошибку. Если ошибка возникла в вызванной процедуре, выполнение кода возобновляется с оператора, непосредственно следующего за тем, который последним вызвал процедуру, содержащую обработчик ошибок (или оператор On Error Resume Next).
Resume line	Выполнение кода возобновляется со строки line, заданной в качестве аргумента. Аргумент line — метка или номер строки в той же самой процедуре, где находится обработчик.
Примеры
Далее приведены примеры на все упомянутые в таблице формы оператора Resume.
Private Sub Test_Resumel()
' Использование в обработчике оператора Resume Dim z, у As Integer On Error GoTo Err у = InputBox("Введите число") z = у + 10
MsgBox z
‘MsgBox "Спасибо!" Exit Sub
Err:
If Err.Number = 13 Then
MsgBox ("Просили же Вас ввести число!") Resume End If	*
End Sub
Private Sub Test_Resume2()
' Использование в обработчике оператора Resume Next Dim z, у As Integer
On Error GoTo Err
у = InputBox("Введите число")
z = у + 10
MsgBox z
MsgBox "Спасибо!" Exit Sub
Er r:
If Err.Number = 13 Then
MsgBox ("С Вашего разрешения введем 9999")
752
Приложение В
у = 9999
Resume Next
End If
End Sub
Public co As Integer
Private Sub Test_Resume3() ' Использование в обработчике оператора Resume line» Dim z, у As Integer On Error GoTo Err у = InputBox("Введите число") z = у + 10
Debug.Print z
Debug.Print "Спасибо’"
Exit Sub
err_exit:
Debug.Print "Что-то у Вас не получается"
Exit Sub
Err:
If Err.Number = 13 Then If co = 2 Then Resume err_exit
Else co = co + 1 Debug.Print ("У Вас осталось " & _ (3 - co) & " попытки") Resume
End End Sub	End If	If
Private	Sub	Form_Load()
co = 0 End Sub
' Обработчик ошибок в одной из процедур
Private Sub Test_Resume4()
Call A
End Sub
Sub A()
On Error GoTo Err
Call В
Debug.Print "В любом случае процедура а завершается" Exit Sub
Err:
Debug.Print "Где-то произошла ошибка!"
Resume Next
End Sub
Sub B()
Call C
End Sub
Sub C()
Dim d As Integer
d = 1 / 0
End Sub
Операторы в VBA
753
RmDir
Удаляет существующий каталог (или папку), не содержащий файлов.
Синтаксис	>	, .
RmDir path	,
Обязательный аргумент path — строковое выражение, которое определяет удаляемый каталог (или папку). Путь может включать драйвер (по умолчанию — текущий). Если каталог содержит файлы (т.е. — не пустой), при выполнении оператора возникает ошибка, которую можно «перехватить» и обработать оператором On Error; обработчик, например, может дать пользователю возможность либо удалить файлы каталога (оператором Kill), либо отказаться от удаления каталога, если пользователь «поспешил»).
Пример1
RmDir "WINDOWS" ' пользователь не любит WINDOWS
RSet
Выполняет правое выравнивание в строковой переменной. Не может быть использован с типами, определенными пользователем.
Синтаксис
RSet stringvar = string
Синтаксис оператора RSet состоит из следующих элементов:
stringvar	Обязательный. Имя строковой переменной.
string	Обязательный. Строковое выражение, которое выравнивается внутри stringvar.
Если stringvar длиннее, чем string, оператор RSet заменяет все символы с левой стороны строки stringvar пробелами.
Пример (см. пример для LSet)
Dim StrMyVar
StrMyVar = "0123456789"	' инициализация для задания длины строки
Rset StrMyVar = "Right->" ' StrMyVar теперь: ” Right->"
SaveSetting
Сохраняет или создает элемент настройки (ключевую настройку) определенного приложения в Windows-реестре.
Синтаксис
SaveSetting аррпате, section, key, setting
Синтаксис оператора SaveSetting имеет следующие именованные аргументы:
appname	Обязательный. Строковое, содержащее имя приложения или проекта, настройки которого предназначены настройки.
1 Не стоит выполнять этот пример, хотя из-за того, что каталог не пуст, оператор просто вызовет ошибку.
754
Приложение В
section	Обязательный. Строковое выражение, содержащее наименование секции, в которой сохраняется ключевая настройка.	|
key	Обязательный. Строковое выражение, содержащее имя настройки. |
setting	Обязательный. Выражение, содержащее значение ключевой настройки. |
Seek
Устанавливает позицию для следующей операции чтения/записи в открытом (при помощи оператора Open) файле.
Синтаксис	V
Seek [#)filenwnber, position
Синтаксис оператора Seek состоит из следующих элементов:
Filenumber	Обязательный. Любое допустимое число.
position	Обязательный. Число в диапазоне 1-2,147,483,647, включительно, которое указывает, номер элемента (записи) для операции чтения/записи.
Пример
В следующем примере описывается пользовательский тип данных (Record), процедура записи (TestPut) данных в файл и процедура чтения (TestSeek) данных из файла.
Type Record ' Определенный пользователем тип ID As Integer FirstName As String * 20 LastName As String * 20
End Type
Sub TestPut ()
' Тестирование Put Dim MyRecord As Record, RecordNumber
Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
MyRecord.FirstName = "Петр"
MyRecord.LastName = "Петров"
MyRecord.ID = 333
Put #1, 2, MyRecord	t
MyRecord.FirstName = "Сидор"
MyRecord.LastName = "Сидоров"
MyRecord.ID - 111 Put #1, 3, MyRecord
MyRecord.FirstName = "Иван"
MyRecord.LastName = "Иванов"
MyRecord.ID = 222 Put #1, 1, MyRecord
Close #1
End Sub
Sub TestSeek() ' тестирование Get
Операторы в VBA
755
Dim MyRecord As Record, MaxSize As Integer
' чтение записей без Seek:
Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
For i = 1 To 3
Get #1, i, MyRecord
Debug.Print MyRecord.FirstName & " : " & MyRecord.ID
Next
Close #1
' чтение c Seek:
Open "TESTFILE" For Random As #1 Len = Len(MyRecord)
' определить число записей в файле:
MaxSize = LOF(l) \ Len(MyRecord)
' чтение (и печать) записей в цикле в обратном порядке
For RecordNumber = MaxSize То 1 Step -1
Seek #1, RecordNumber ' Установка позиции
Get #1, , MyRecord ' чтение записи
Debug.Print MyRecord.FirstName & " : " & MyRecord.ID
Next RecordNumber
Close #1
End Sub
Select Case
Выполняет одну или несколько групп операторов, в зависимости от выражения.
Синтаксис
Select Case testexpression
[Case express!onlist-n
[statements-n] ) ...
[Case Else
[eisestatements) )
End Select
Синтаксис оператора Select Case состоит из следующих элементов:
testexpression	Обязательный. Любое числовое или строковое выражение.
expressionlist-n /	Обязателен в случае использования Case. Список (с разделителями) из одной или более следующих форм: expression expression То expression Is comparisonoperator expression Ключевое слово To определяет диапазон значений, в котором меньшее значение должно быть перед ключевым словом То. Ключевое слово Is следует использовать с операторами сравнения (кроме, Is и Like) для указания диапазона значений. Если этот аргумент не используется, автоматически поставляется ключевое слово Is.
statements-n	Необязательный. Один или более операторов, выполняемых, если testexpression совпадает с любым значением из expressionlist-n.
eisestatements	Необязательный. Один или более операторов, выполняемых, если testexpression не совпадает ни с каким Case-предложением.
Если testexpression совпадает с любым из Case-выражений expressionlist, выполняются операторы statements, следующие за этим Case-предложением (до еле-
756
Приложение В
дующего Case-предложения или последнего Case-предложения — до End Select). Управление выполнением программы передается оператору, следующему за предложением End Select. Если testexpression совпадает с expressionlist в нескольких Case-предложениях, выполняются операторы, соответствующие первому совпадению. Предложение Case Else используется для указания группы операторов elsestatements, которые следует выполнять, если ни в одном Case-предложении не нашлось совпадений.
Конструкция Select Case допускает вложения.
SendKeys
Посылает одно или более нажатий клавиш активному окну, как будто они выполнены с клавиатуры.
Синтаксис
SendKeys string [, wait]
Синтаксис оператора SendKeys включает следующие именованные аргументы:
string	Обязательный. Строковое выражение, определяющее посылаемые нажатия клавиш.
wait	Необязательный. Значение типа Boolean, определяющее режим ожидания (wait mode). Если — False (по умолчанию), управление возвращается процедуре немедленно после передачи клавиш. Если — True, нажатия клавиш должны быть обработаны прежде, чем управление будет возвращено процедуре.
Каждая клавиша представляет один или более символов. Для указания одиночного символа клавиатуры используйте сам символ. Например, для представления символа N используйте строку "N". Для представления нескольких символов используйте строку, например, "ABCD".
Знаки "плюс" (+), "каре" ('), "процент" (%), "тильда" (-), "парные скобки" () имеют для функции SendKeys специальные значения. Для указания любого из этих символов заключайте их в фигурные скобки ({}). Например, для определения знака "плюс” используйте строку "{+}”. Квадратные скобки ([ ]) не имеют специального значения для функции SendKeys, но их также следует заключать в фигурные скобки.
Для указания символов, которые не отображаются при нажатии на них (ENTER или TAB), и символов, которые представляют действие, а не символ, используйте следующие коды:
Клавиши	Коды
BACKSPACE	{BACKSPACE}, {BS} или {BKSP}
BREAK	{BREAK}
CAPS LOCK	{CAPSLOCK}
DEL or DELETE	{DELETE} или {DEL}
DOWN ARROW	{DOWN}
END	{END}
ENTER	{ENTER} или -
| ESC	{ESC}
Операторы в VBA
757
Клавиши	Коды
HELP	{HELP}
НОМЕ	{HOME}
INS or INSERT	{INSERT} или {INS}
LEFT ARROW	{LEFT}
NUM LOCK	{NUMLOCK}
PAGE DOWN	{PGDN}
PAGE UP	{PGUP}
PRINT SCREEN	{PRTSC}
RIGHT ARROW	{RIGHT}
SCROLL LOCK	{SCROLLLOCK}
TAB	{TAB}
UP ARROW	{UP}
Fl	{Fl}
F2	{F2}
F3	{F3}
F4	{F4}
F5	{F5}
F6	{F6}
F7	{F7}
F8	{F8}
F9	{F9}
F10	{F10}
Fll	{Fll}
Fl 2	{F12}
F13	{F13}
F14	{F14}
F15	{F15}
F16	{F16}
Для определения комбинаций клавиш с клавишами SHIFT, CTRL и ALT предваряйте код клавиши следующими знаками:
Клавиша	Знак
SHIFT	+
CTRL	
ALT	%
758
Приложение В
Для указания того, что некоторая комбинация клавиш SHIFT, CTRL и ALT остается нажатой в то время, как нажимаются другие клавиши, заключайте коды этих клавиш в скобки. Например, чтобы указать, что при нажатой клавише SHIFT «нажимаются» клавиши Е и Я, следует использовать строку ”+(ЕЯ)". А чтобы указать, что при нажатой клавише SHIFT нажимается клавиша Е, а затем — только Я (без SHIFT), следует использовать строку "+ЕЯ".
Для определения повторяющихся клавиш используйте следующую форму {клавиша число}. Например, {LEFT 43} означает нажатие клавиши LEFT ARROW (стрелка влево) 43 раза; {Y 12} означает нажатие клавиши Y 12 раз.
Пример
В этом примере с использованием функции Shell запускается приложение Microsoft Outlook и «нажимается» кнопка Send/Receive сочетанием клавиш Alt и С.
Sub TestSendKeys()
' Запустить почтовую программу
ReturnValue = Shell("OUTLOOK.EXE", 1)
' Нажать на кнопку Send/Receive
SendKeys "%С", True
End Sub
Set
Присваивает объекту ссылку на переменную или свойство.
Синтаксис
Set objectvar = {[New] ebjectexpression | Nothing)
Синтаксис оператора Set состоит из следующих элементов:
objectvar	Обязательный. Имя переменной или свойства; должно соответствовать стандартным соглашениям об именовании переменных.
New	Необязательный. New обычно используется для неявного создания объекта. Если New используется вместе с Set, создается новый экземпляр класса. Если objectvar содержал ссылку на некоторый объект, эта ссылка удаляется, когда присваивается новая. Ключевое слово New нельзя использовать для создания нового экземпляра встроенного типа данных.
objectexpression	Обязательный. Выражение, состоящее из имени объекта, другой объявленной переменной того же объектного типа или функции (метода), которая возвращает объект того же типа.
Nothing	Необязательный. Прекращение связи objectvar с любым указанным объектом.
Переменная objectvar должна быть объектного типа, совместимого с объектом, который ей присваивается. Операторы Dim, Private, Public, ReDim и Static только объявляют переменную, которая ссылается на объект. Действительное присваивание ссылки на определенный объект выполняет оператор Set.
Пример
Dim xlBook As Object
Dim xlSheet As Object
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook.Worksheets(1)
Операторы в VBA
759
SetAttr
Устанавливает информацию об атрибутах для файла.
Синтаксис
SetAttr pathname, attributes
Синтаксис оператора SetAttr включает следующие именованные аргументы:
pathname	Обязательный. Строковое выражение, определяющее имя файла (может включать каталог и драйвер диска).
attributes	Обязательный. Константное или числовое выражение, которое представляет сумму определенных атрибутов.
Аргумент attributes может принимать следующие значения:
Константа	Значение	Назначение
VbNormal	0	Normal (по умолчанию) [обычный].
VbReadOnly	1	Read-only [для чтения/записи].
VbHidden	2	Hidden [скрытый].
VbSystem	4	System [системный] файл.	|
VbArchive	32	Файл изменялся со времени последней архивации.
Пример
SetAttr "С:\Мои документы^.TESTFILE", vbHidden
SetAttr "С:\Мои документы\ТЕЗТГ1ЬЕ", vbHidden + VbSystem
Static
Используется на уровне процедуры для объявления переменных и выделяет для них память. Переменные, объявляемые при помощи оператора Static, сохраняют свои значения в течение всего времени выполнения программы.
Синтаксис
Static varname[([subscripts])] [As [New] type]
[, varname[([subscripts])] [As [New] type]] . . .
Синтаксис оператора Static включает следующие элементы:
varname	Обязательный. Имя переменной; должно соответствовать стандартным соглашениям об именовании переменных.
subscripts	Необязательный. Необязательный. Размерность переменной-массива; можно объявить до 60 размерностей. Аргумент subscripts использует следующий синтаксис: [lower То] upper [,[lower То] upper] ... lower — нижний предел допустимых индексов массива; upper — верхний предел (является обязательным) для индексов массива. При наличии в операторе Dim только upper нижний предел определяется в зависимости от установки оператора Option Base.
760
Приложение В
New	Необязательный. Ключевое слово, позволяющее неявно создать объект. Если вы используете New при объявлении объектной переменной, создается новый экземпляр объекта, поэтому нет необходимости использовать оператор Set для назначения объекту ссылки.
type	Необязательный. Тип данных переменной; может быть типом Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), String * length (для строк фиксированной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
Во время выполнения кода модуля переменные, объявленные оператором Static, сохраняют свои значения до «сброса» или перезапуска модуля. Переменные, объявленные оператором Static в модуле класса, сохраняют свои значения в каждом экземпляре класса до удаления экземпляра. Переменные, объявленные оператором Static в модуле формы, сохраняют свои значения до закрытия формы.
Stop
Останавливает выполнение кода.
Синтаксис
Stop
Для приостановки выполнения кода (в целях отладки) можно помещать оператор Stop в любом месте программы. Использование этого оператора подобно использованию точки прерывания (breakpoint). Оператор Stop останавливает выполнение программы, но в отличие от оператора End этот оператор не закрывает файлы и не очищает переменные (за исключением компилированных исполняемых файлов).
Пример
Sub Teststop()
Dim I
For I = 1 To 10
Debug.Print I & " Для продолжения выполните Run|Continue" Stop Next I
End Sub
Sub
Объявляет имя, аргументы и код тела Sub-процедуры.
Синтаксис
[Private I Public I Friend] [Static] Sub name [(arghst)] [s tatements] [Exit Sub] [statements]
End Sub
Синтаксис оператора Sub включает следующие элементы:
Public	Необязательный. Указывает, что Sub-процедура доступна всем другим процедурам во всех модулях. Если используется в модуле, который содержит оператор Option Private, эта процедура недоступна вне проекта.
Операторы в VBA
761
Private	Необязательный. Указывает, что процедура доступна другим процедурам только того модуля, в котором она объявлена.
Friend	Необязательный. Используется только в модуле класса. Указывает, что Sub-процедура видима во всем проекте.
Static	Необязательный. Указывает, что локальные переменные процедуры сохраняют свои значения между вызовами.
пате	Обязательный. Имя Sub-процедуры; должно соответствовать стандартным соглашениям об именовании переменных.
\ arglist	Необязательный. Список переменных, представляющих аргументы, передаваемые процедуре при ее вызове.
[statements	Необязательный. Любой набор операторов, которые будут выполняться при вызове процедуры.
Синтаксис параметра arglist имеет вид и включает:
[Optional] [ByVai | ByRef] [ParamArray] varname]( )] [As type] [= defaultvalue]
Optional	Необязательный. Ключевое слово, указывающее, что аргумент является необязательным. Если используется, все последующие аргументы в arglist должны быть также необязательными и объявляться с ключевым словом Optional. Если применяется ParamArray, слово Optional не может использоваться ни для какого аргумента.
ByVai	Необязательный. Указывает, что аргумент передается по значению.
ByRef	Необязательный. Указывает, что аргумент передается по ссылке. Используется по умолчанию.
ParamArray	Необязательный. Используется только в качестве последнего аргумента в списке arglist для указания того, что последний аргумент является Optional-массивом Variant-элементов. Ключевое слово ParamArray позволяет использовать переменное число аргументов и не может применяться с ByVai, ByRef или Optional.
varname	Обязательный. Имя переменной, передаваемой процедуре; должно удовлетворять стандартным соглашениям об именовании переменных.
type	Необязательный. Тип аргумента, передаваемого процедуре; может быть типом Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), Object, Variant или объектным типом. Если параметр не описан как Optional, может быть указан тип, определенный пользователем.
defaultvalue	Необязательный. Любая константа или константное выражение. Допускается только для аргументов, описанных как Optional. Если типом является Object, то явное значение по умолчанию может быть только значение Nothing.
Sub-процедуры — это основные программные единицы на языке Visual Basic. Они обеспечивают функционирование диалоговых форм, выполняют действия общего характера, вызывая при необходимости другие Sub-процедуры и Function-процедуры, обеспечивают работу с экземплярами классов.
762
Приложение В
Если явно не определено использование Public, Private или Friend, Sub-процедура является Public по умолчанию. Если не используется Static, значения локальных переменных не сохраняются между вызовами. Ключевое слово Friend может быть использовано только в модулях класса. Однако Friend-процедуры могут быть доступны процедурам в любом модуле проекта.
Sub-процедуры могут быть рекурсивными. Это означает, что они могут вызывать сами себя. Иногда в результате рекурсивных вызовов может происходить переполнение программного стека. Ключевое слово Static обычно не используется при описании рекурсивных Sub-процедур.
Весь выполняемый код помещается в теле процедуры. Нельзя определить Function-процедуру внутри другой Function-, Sub- или Property-процедуры.
Оператор Exit Sub приводит к немедленному завершению Sub-процедуры. При этом программа продолжает выполняться с оператора, следующего за тем, который вызвал Sub-процедуру. В качестве альтернативных выходов внутри Sub-процедуры может встречаться любое количество операторов Exit Sub.
Подобно Function-процедуре Sub-процедура — это отдельная процедура, которая может принимать аргументы, выполнять ряд операторов и изменять значения ее аргументов. Однако в отличие от Function-процедуры имя Sub-процедуры не может появляться в правой части операции присваивания в составе некоторого выражения.
Time
Устанавливает системное время.
Синтаксис
Time = time
Обязательный аргумент time — любое числовое, строковое выражение или любая комбинация, представляющая время. Если time — строка, оператор Time «пытается» преобразовать ее во время, используя разделители времени, которые определены в вашей системе.
Пример
TimeMy = #4:30:20 PM#
Time = TimeMy
Type
Используется на уровне модуля для определения типа данных пользователя.
Синтаксис
[Private I Public] Type varname
elementname [([subscripts])] As type [elementname [([subscripts])] As type]
End Type
Синтаксис оператора Type включает следующие элементы:
Public	Необязательный. Используется для объявления пользовательских типов, доступных всем процедурам во всех модулях всех проектов.
Private	Необязательный. Используется для объявления пользовательских типов, доступных только в модуле, где они объявляются.
Операторы в VBA
763
varname	Обязательный. Имя определенного пользователем типа; должно соответствовать стандартным соглашениям об именовании переменных.
elementname	Обязательный. Имя элемента пользовательского типа. Имена элементов также должны соответствовать стандартным соглашениям об именовании переменных.
subscripts	Если аргумент lower явно не указывается, нижняя граница массива определяется оператором Option Base. Нижняя граница равна 0, если оператор Option Base не используется.
type (	Обязательный. Тип данных элемента; может быть типом Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (только переменной длины), String * length (для строк фиксированной длины), Object, Variant, типом, определенным пользователем, или объектным типом.
После того как с использованием оператора Туре (можно использовать только на модульном уровне) описан пользовательский тип, вы можете объявлять переменные этого типа в любом месте внутри области действия описания типа. При этом следует использовать операторы Dim, Private, Public, ReDim или Static. В стандартных модулях и модулях класса типы пользователя являются public-типами по умолчанию, что легко изменить, используя ключевое слово Private.
Пример
Type Record ’ Определенный пользователем тип
ID As Integer
FirstName As String * 20
LastName As String * 20
End Type
Unload
Удаляет объект из памяти.
Синтаксис
Unload object
Обязательный аргумент object является объектным выражением, которое вычисляется до объекта в Applies То list.
Пример
Private Sub CanselCommand_Click()
Unload me ' удалить из памяти текущий диалог
End Sub
While...Wend
Выполняет серию операторов, пока некоторое условное выражение является равным True.
Синтаксис	'
While condition
[statements]
Wend
764
Приложение В
Синтаксис оператора While...Wend включает следующие элементы:
condition	Обязательный. Числовое или строковое выражение, результатом вычисления которого являются значения True или False. Если condition — Null, то оно интерпретируется как False.
statements	Необязательный. Один или более операторов; выполняемых, если условие является равным значению True.
Если condition является равным значению True, выполняются все операторы между словами While и Wend. Управление выполнением программы передается в начало структуры While...Wend и значение condition снова проверяется. Если оно остается равным значению True, процесс повторяется, иначе управление передается на оператор, следующий за словом Wend. Оператор While...Wend допускает вложения.
Пример
Sub TestWhileWend()
Dim i As Integer
i = 10	,	'	'
While i < 20	’	'
i = i + 2	J  ”	1
MsgBox i
Wend
MsgBox "Последнее выданное значение должно быть равно 20"
End Sub
Width #
Устанавливает ширину выводимой в файл строки (файл открывается оператором Open).
Синтаксис
Width #filenumber, width
Синтаксис оператора Width # включает следующие элементы:
filenumber	Обязательный. Любой допустимый файловый номер.	j
width	Обязательный. Числовое выражение в диапазоне 0-255, включительно, которое указывает количество символов, появляющихся в строке перед началом новой строки (т.е. количество символов в строке). Если значение width равно 0, то длина строки не имеет ограничений. По умолчанию значение width является равным 0.	|
With
Выполняет несколько операторов для единственного объекта или пользовательского типа.
Синтаксис
With object	4
[statements]
End With
Операторы в VBA
765
Синтаксис оператора With включает следующие элементы:
object	Обязательный. Имя объекта или пользовательского типа.
statements	Необязательный. Один или более операторов, которые должны быть выполнены.
Оператор With позволяет выполнить несколько операторов для определенного объекта без повторного указания имени объекта. Так, например, удобно сразу изменить несколько свойств некоторого объекта, как это показано в следующем примере.
Пример
Этот пример получен при помощи макрорекордера записью действий при форматировании выделенного участка абзаца в Word.
Sub Масгоб()
1 Масгоб Macro
' Macro recorded 01.12.01 by Владимир
With Selection.Font
.Name = "Times New Roman" .Size = 10 .Bold = False .Italic = False .Underline = wdUnderllneNone .Underlinecolor = wdColorAutomatic .StrikeThrough = False .DoubleStrikeThrough = False .Outline = False .Emboss = False .Shadow = False Hidden = False SmallCaps = False .AllCaps = False .Color = wdColorAutomatic Engrave = False  Superscript = False	•’	•	*
Subscript = True .Spacing = 0
Scaling = 100 .Position = 0 Kerning = 0	'
.Animation = wdAnimationNone End With End Sub
Write #	z
Записывает данные в файл с последовательным доступом.
Синтаксис
Write # filenumber, [outputlist]
Синтаксис оператора Write # состоит из следующих элементов:
jilenumber	Обязательный. Любой допустимый файловый номер.
outputlist	Необязательный. Одно или более (разделенных запятыми) числовых или строковых выражений для записи в файл.
766
Приложение В
Данные, которые записываются в файл оператором Write #, обычно считываются оператором Input #. Если аргумент outputlist не используется, а после filenumber помещается запятая, в файл записывается пустая строка.
Чтобы при использовании оператора Write # для записи в файл данные корректно считывались оператором Input #, выполняются следующие правила:
	Числовые данные всегда записываются с использованием точки в качестве десятичного разделителя.
*	Для данных типа Boolean печатается либо #TRUE#, либо #FALSE#.
	Данные типа Date записываются в файл с использованием универсального формата даты. Если компонента даты или времени отсутствует или нулевая, в файл записывается только предоставленная часть.
	В файл ничего не записывается, если значение outputlist имеет значение Empty. Однако для Null-данных записывается #NULL#.
	Для Error-данных в файле появляется #ERROR errorcode#.
В отличие от оператора Print # оператор Write # вставляет запятые между элементами и кавычки вокруг строк. Вам не нужно использовать явно разделители в списке. Оператор Write# вставляет символ новой строки, т.е. Chr(13) + Chr(10), после того, как в файл будет записан последний символ из outputlist.
Пример
Sub TestPrint()
' запись данных в файл TESTFILE
Dim TextLine
Open "TESTFILE" For Output As #1
Write #1, "По синим волнам океана,"
Write #1, "Лишь звезды блеснут в небесах,"
Write #1, "Корабль одинокий несется,"
Write #1, "Несется на всех парусах"
Write #1,
Write #1, Iab(10); "М.Ю. Лермонтов"
Close #1
End Sub
Sub Testinput ()
Dim StrMy
Open "TESTFILE" For Input As #1 ' открыть файл
Do While Not EOF(l)	' цикл до конца файла
Input #1, StrMy	' считать данные
Debug.Print StrMy	1 результат -> на экран
Loop
Close #1	' закрыть файл
End Sub
Приложение Г
Функции в VBA
В этом приложении приведены функции, которые вы можете использовать в своих программах. Данная информация предназначена для разработчиков VBA-приложений.
Abs
Возвращает абсолютное значение своего аргумента. (Абсолютное значенце числа — это его значение без знака.)
Синтаксис
Abs(number)
Обязательный аргумент number может быть любым допустимым арифметическим выражением. Если number содержит Null, возвращается также Null; если — неинициализированная переменная, то возвращается нулевое значение.
Array
Возвращает Variant-массив, значениями которого являются элементы аргумента-списка.
Синтаксис
Array(argl1st)
Обязательный аргумент arglist—это разделенный запятыми список значений, которые назначаются элементам массива. Значение нижней границы (индекса) массива определяется опцией оператора Option Base.
Примеры
Dim A As Variant ' объявление А как типа Variant
А = Array(10,20,30)	' теперь А — массив
В = А(2)	' в В записывается значение А (2)
Asc
J.
Возвращает числовой (тип Integer) код первого символа строки-аргумента.
Синтаксис
Asc(string)	,
Обязательный аргумент string —любое допустимое строковое выражение. Если аргумент не содержит ни одного символа, вызывается ошибка времени исполнения.
Диапазон возвращаемых значений: 0-255 для не DBCS-систем и -32768 -32767 для DBCS-систем.
Примеры
Dim MyNumber		
MyNumber = Asc("В")	‘ возвращает	66
MyNumber = Asc("a")	' возвращает	97
MyNumber - AscCABCD")	’ возвращает	65
768
Приложение Г
Atn
Возвращает арктангенс (тип Double) заданного аргумента.
Синтаксис
Atn(number)
Обязательный аргумент number —переменная типа Double или любое допустимое арифметическое выражение. Функция Atn (обратная функции Tan) принимает отношение двух сторон прямоугольного треугольника и возвращает значение соответствующего угла в радианах (в диапазоне от — pi/2 до pi/2).
Пример
pi = 4 * Atn(l) ' pi
CallByName
Выполняет метод некоторого объекта или устанавливает или возвращает свойство объекта.
Синтаксис
CallByName(object, procname, calltype,[args()1)
Функция CallByName принимает следующие именованные аргументы:
Аргумент	Назначение
object	Обязательный; тип — Variant (Object). Имя объекта, для которого вызывается функция.
ргоспате	Обязательный; тип — Variant (String). Строка с именем свойства или метода объекта.
calltype	Обязательный; Константа типа vbCallType, представляющая тип вызываемой процедуры.
args( )	Необязательный: тип — Variant (Array).
Для проверки работы этой функции поместите на форме три кнопки с именами, которые Редактор VB задаст им по умолчанию, и напишите простые программы обработки событий:
Private Sub CommandButtonl_Click()
MsgBox "Свойство Enabled кнопки: " & _
CallByName(CommandButton2, "Enabled", VbGet)	\
End Sub
Private Sub CommandButton3_Click()
If CallByName(CommandButton2, "Enabled", VbGet) Then CallByName CommandButton2, "Enabled", VbLet, False Else
CallByName CommandButton2, "Enabled", VbLet, True End If
End Sub
Когда вы запустите это приложение (командой Run | Run Sub/UserForm), кнопка с именем CommandButtonl позволит вывести на экран свойство Enabled кнопки CommandButton2. А кнопка с именем CommandButton3 будет последовательно изменять свойство Enabled кнопки CommandButton2. Обратите внимание на различие в синтаксисе функции при установке и считывании свойства.
Функции в VBA
769
Функции преобразования типов
Синтаксис
CBool(expression)
CByte(expression) CCur(expression) CDate(expression)
CDbl(expression)
CDec(expression)
CInt(expression)
CLng(expression) CSng(expre s s i on) CStr(expression)
CVar(expression)
Функции преобразуют данные из одних типов в другие. Обязательный аргумент expression —любое строковое или численное (арифметическое) выражение.
Возвращаемые типы
Тип возвращаемых данных определяется именем функции:
Функция	Тип возвращаемых данных
CBool	Boolean
CByte	Byte
CCur	Currency
CDate	Date
CDbl	Double
CDec	Decimal
CInt	Integer
CLng	Long
CSng	Single
CStr	String
CVar	Variant
Обычно функции преобразования типов данных используются разработчиком VBA-приложения для документирования преобразований в коде, поскольку преобразования, выполняемые по умолчанию, могут быть не понятны при чтении кода.
Choose
Выбирает и возвращает значение из списка аргументов.
Синтаксис
Choose(index, choice-1 [, choice-2, ... [, choice-n]])
Функция Choose принимает следующие аргументы:
Аргументы	Назначение
index	Обязательный. Численное выражение, результатом которого является значение от 1 до числа возможных вариантов для выбора.
25 Программирование на VBA 2002
770
Приложение Г
j Аргументы	Назначение
choice	Обязательный. Variant-выражение, содержащее один из возможных выборов.
Пример
Dim Ind As Integer	•
Ind = 2
' функция MsgBox выдаст диалоговое окно с "United"
MsgBox Choose(Ind, "Speedy", "United", "Federal")
Chr
Возвращает String-значение (строку), содержащее символ, код которого указан в качестве аргумента.
Синтаксис	(
Chr(charcode)
Обязательный аргумент charcode — это Long-значение кода символа. Диапазон значений аргумента: 0-255. Однако в DBCS-системах1 этот диапазон: от -32768 до 65535.
Cos
Возвращает значение (тип Double) косинуса угла-аргумента.
Синтаксис
Cos (number)	*'
Обязательный аргумент number —допустимое численное выражение, представляющее угол в радианах.
CreateObject
Создает и возвращает ссылку на ActiveX-объект.
Синтаксис
CreateObject{class,[servername])
Функция CreateObject имеет следующие аргументы:
Аргумент	Назначение
class	Обязательный; тип Variant (String). Имя приложения и класс объекта для создания.
servername	Необязательный; тип Variant (String). Имя сервера сети, где должен быть создан объект. Если servername — пустая строка («»)> используется локальная машина.
Аргумент class использует синтаксис appname.objecttype, где:
Здесь набор символов использует 1 или 2 байта для представления символа.
Функции в VBA
771
Элемент	Назначение	|i
аррпате	Обязательный; тип Variant (String). Имя приложения, предоставляющего объект.	||
objecttype	Обязательный; тип Variant (String). Тип или класс объекта для создания.	|
Любое приложение, поддерживающее Automation, предоставляет, по крайней мере, один тип объекта. Например, приложение текстового процессора может предоставить объект Application, Document и Toolbar.
Чтобы создать ActiveX-объект, присвойте объект, возвращаемый функцией CreateObject, объектной переменной:
Dim Excel_Sheet As Object
Set Excel_Sheet - CreateObject("Excel.Sheet")
Объявление объектной переменной при помощи As Object создает переменную, содержащую ссылку на объект любого типа. Связывание этой ссылки с конкретным объектом происходит при выполнении программы (позднее связывание). Чтобы создать объектную переменную при помощи раннего связывания, объявляйте объектную переменную как определенный ID-класс. Например:
Dim xlApplication As Excel.Application
Dim xlBook. As Excel. Workbook
Dim xlSheet As Excel.Worksheet
Set xlApplication = CreateObject("Excel.Application")
Set xlBook = xlApplication.Workbooks.Add
Set xlSheet = xlBook.Worksheets(1)
CurDir
Возвращает значение типа Variant (String), содержащее текущий путь (current path).
Синтаксис
CurDir[(drive)]
Необязательный аргумент drive — строковое выражение, определяющее драйвер. Если этот аргумент не задан или является пустой строкой ('"'), функция CurDir возвращает путь для текущего драйвера.
Пример
Dim My_Path
My_Path =	CurDir	'	Returns	"C:\WIN2000\SYSTEM".
My_Path =	CurDir("C")	'	Returns	"C:\WIN2000\SYSTEM".
My.Path =	CurDir("D")	'	Returns	"D:\WORD".
CVErr
Возвращает значение (тип Variant) подтипа Error, содержащее номер ошибки, определенный пользователем.
Синтаксис
CVErr(errornumber)
Обязательный аргумент errornumber — любое допустимое error-число.
Функцию CVErr следует использовать для описания ошибок в пользовательских процедурах. Например, если вы создали функцию с несколькими аргумента-
25*
772
Приложение Г
ми, то можно при этом написать вспомогательную функцию, которая проверяет количество передаваемых аргументов и нахождение значений аргументов в допустимых диапазонах. В случае нарушения правил передачи параметров вы можете использовать функцию CVEr, для возвращения номера возникшей ошибки, который вы сами и зададите.
*
Date
Возвращает значение [тип Variant (Date)], содержащее текущую системную дату.
Синтаксис
Date
Можно также использовать эту функцию как процедуру для установки системных часов компьютера.
DateAdd
Возвращает значение [тип Variant (Date)], содержащее дату, к которой добавлен заданный интервал времени.
Синтаксис
DateAdd(interval, number, date)
Функция DateAdd принимает следующие именованные аргументы:
Аргумент	Назначение
interval	Обязательный. Строковое выражение, определяющее вид интервала, который необходимо использовать.
number	Обязательный. Числовое выражение, определяющее количество добавляемых интервалов. Может быть как положительным, так и отрицательным.
date	Обязательный. Значение [Variant (Date)], определяющее дату, к которой добавляется временной интервал.
Аргумент interval может принимать следующие значения:
Значение	Описание	Значение	Описание
УУУУ	Year (год)	W	Weekday (день недели)
q	Quarter (квартал)	WW	Week (неделя)
m	Month (месяц)	h	Hour (час)
У	Day of year (день года)	n	Minute (минута)
d	Day (день)	s	Second (секунда)
Функция DateAdd может использоваться для добавления (или вычитания) определенного временного интервала к указанной дате (из указанной даты). Например, с использованием функции DateAdd можно узнать значение даты через 40 дней после текущей даты или время через 50 секунд от текущего времени.
Функции в VBA
773
DateDiff
Возвращает значение [тип Variant (Long)] числа временных интервалов между двумя определенными датами.
Синтаксис
DateDiff(interval, datel, date2[, firstdayofweek[, firstweekofyear]])
Функция DateDiff принимает следующие именованные аргументы:
Аргумент	Назначение
interval	Обязательный. Строковое выражение, которое является временным интервалом (единицей измерения).
datel, date2	Обязательный; Variant (Date). Две даты для вычисления.
firstdayofweek	Необязательный. Константа, которая определяет первый день недели (день по умолчанию зависит от национальных настроек).
firstweekofyear	Необязательный. Константа, которая определяет первую неделю года. Если не указана, первой неделей считается неделя, в которой имеется дата 1 января.
Значения аргумента interval приведены в таблице для функции DateAdd. Значения аргумента firstdayofweek могут быть следующими:
Константа	Значение	Описание
vbUseSystem	0	Использовать национальные языковые [National Language Support (NLS)] API-настройки
vbSunday	1	Sunday (Воскресенье)
vbMonday	2	Monday (Понедельник)
vbTuesday	3	Tuesday (Вторник)
vb Wednesday	4	Wednesday (Среда)
vbThursday	5	Thursday (Четверг)
vbFriday	6	Friday (Пятница)
vbSaturday	7	Saturday (Суббота)
Значения аргумента firstweekofyear могут быть следующими:
Константа	Значение	Описание
vbUseSystem	0	Использовать NLS API-настройки.
vbFirstJanl	1	Начинать с недели, в которой имеется дата 1 января. (по умолчанию).
vbFirstFourDays	2	Начинать с первой недели, которая имеет, по крайней мере, четыре дня в новом году.
vbFirstFullWeek	3	Начинать с первой полной недели года.
Функция DateDiff используется для определения количества указанного вида (дней, недель и т.д.) временных интервалов между двумя датами. При этом следует учитывать значение последнего аргумента.
774
Приложение Г
Date Part
Возвращает определенную часть [тип Variant (Integer)] заданной даты. Синтаксис
DatePart(interval, date[,firstdayofweek[, firstweekofyear]])
Функция DatePart принимает следующие именованные аргументы:
Part	Description
interval	Обязательный. Строковое выражение с обозначением необходимого интервала.
date	Обязательный. Тип Variant (Date). Значение даты.
firstdayofweek	Необязательный. Константа, задающая первый день недели. Значение по умолчанию определяется национальными настройками системы.
firstweekofyear	Необязательный. Константа, задающая первую неделю года. Если не задается, первая неделя считается той, в которой имеется дата 1 января.
Значения аргумента interval приведены в таблице для функции DateAdd.
Значения аргумента firstdayofweek приведены в таблице для функции DateDiff.
Аргумент firstweekofyear может принимать следующие значения:
Константа	Значение	Описание
vbUseSystem	0	Использовать настройку NLS API.
vbFirstJanl	1	Начинать с той недели, в которой будет первое января (по умолчанию).	'
vbFirstFourDays	2	Начинать с первой недели, которая имеет, по меньшей мере, четыре дня в новом году.
vbFirstFull W eek	3	Начинать с первой полной недели года.
Функция DatePart может быть использована для вычисления некоторой даты и интервала времени. Например, вы можете вычислить день недели или текущий час.
Пример
Dim DateVar As Date	'
DateVar = InputBox("Введите дату:")
MsgBox "Квартал: " & DatePart("q", DateVar)
Если в диалоговом окне функции InputBox ввести, например, 22/09/2001, то в диалоговом окне MsgBox будет выведена строка "Квартал: 3".
DateSerial
Возвращает значение даты [тип Variant (Date)] для заданных года, месяца и дня.
Синтаксис
DateSerial(year, month, day)
Функция DateSerial принимает следующие именованные аргументы:
Функции в VBA
775
Part	Description
year	Обязательный; тип Integer. Число (арифметическое выражение) в интервале от 100 до 9999.
month	Обязательный; тип Integer. Любое арифметическое выражение.
day	Обязательный? тип Integer. Любое арифметическое выражение.
Пример
Следующая строка имеет результатом диалоговое окно с текстом "12.02.01".
MsgBox DateSerial(2001, 2, 12)
DateValue
Возвращает значение типа Date, эквивалентное дате, заданной аргументом, который должен быть строкой, числом или константой, представляющей дату.
Синтаксис
DateValue(date)
Обязательный аргумент date — обычно строковое выражение, представляющее дату от 1 января 100 года до 31 декабря 9999 года. Этот аргумент может быть также любым выражением, которое вычисляется до значения даты.
Если date является строкой, включающей только числа, разделенные так называемыми разделителями даты (date separators), DateValue распознает месяц, день и год в соответствии с форматом Short Date, который определен для вашей системы. DateValue также распознает строку, которая содержит дату с полным или коротким именем месяца (например, "февраль 12, 1969").
Day
Возвращает значение [тип Variant (Integer)] (между 1 и 31 включительно), представляющее день месяца.
Синтаксис
Day (da te)
Обязательный аргумент date — любое значение TnnaVariant, численное выражение, строковое выражение или их комбинация, которая представляет дату. Если аргумент содержит значение Null, функция возвращает Null.
Возвращаемое значение зависит от значения свойства Calendar в вашей системе.
DDB
Возвращает значение (Double) амортизации (depreciation) активов за определенный период времени с использованием балансового метода «двойного списания» (double-declining) или другого (вами указанного) метода.
Синтаксис
DDB(cost, salvage, life, periodl, factor])
Именованные аргументы функции DDB:
776
Приложение Г
Аргумент	Назначение
cost	Обязательный. Тип Double. Определяет начальную стоимость активов.	‘
salvage	Обязательный. Тип Double. Определяет стоимость активов в конце периода амортизации (остаточная стоимость).
life	Обязательный. Тип Double. Определяет длительность периода амортизации собственности.
period	Обязательный. Тип Double. Определяет период, для которого вычисляется амортизация активов.
factor	Необязательный. Тип Variant. Определяет норму снижения стоимости (амортизации). Если аргумент отсутствует, используется значение 2 (метод «двойного списания»).
Аргументы life и period должны выражаться в одних и тех же единицах, например, если life задается в месяцах, то и period также должен быть задан в месяцах. Все аргументы должны быть положительными числами.
Функция DDB использует следующую формулу для вычисления амортизации за заданный период:
Амортизация / period = ((cost - salvage) * factor) / life
Dir
Возвращает значение типа String, представляющее имя файла (каталога или папки), которое совпадает с шаблоном, файловым атрибутом или меткой тома драйвера.
Синтаксис
Dir[(pathname[, attributes])]
Функция Dir имеет следующие аргументы:
Аргумент	Назначение
Pathname	Необязательный. Строковое выражение, которое определяет имя файла. Может включать каталог (папку) и имя драйвера диска Если функция не находит pathname, возвращается строка нулевой длины ("").
Attributes	Необязательный. Константа или числовое выражение, являющееся суммой атрибутов файла.
Аргумент attributes принимает следующие значения:
Константа	Значение	Описание
vbNormal	0	Обычный (Normal) (по умолчанию) — файлы без атрибутов.
vbReadOnly	1	Только на чтение (Read-only).
vbHidden	2	Скрытый (Hidden).
VbSystem	4	Системный файл (System file).
vb Volume	8	Метка тома (Volume label); если указаны любые другие атрибуты, vbVolume игнорируется.
Функции в VBA
777
Константа	Значение	Описание
vbDirectory	16	Каталог или папка.
vbAlias	64	Алиасное имя (на Macintosh).
В Microsoft Windows Dir поддерживает использование символов (*) и (?) для поиска множества файлов.
В первом вызове функции Dir следует обязательно задавать аргумент pathname, иначе будет сгенерирована ошибка. Аргумент pathname также должен использоваться, если указываются атрибуты файлов.
Dir возвращает первое имя файла, которое совпадает с pathname. Для получения следующих файлов, совпадающих с pathname, следует вызвать функцию Dir снова, но без аргументов. После того как функция в последних вызовах возвратит все совпавшие файлы, функция возвратит пустую строку (""). В связи с этим удобно записывать имена файлов, возвращаемых функцией Dir, в массив и в дальнейшем, например, сортировать его.
Environ
Возвращает значение типа String, связанное с переменной среды операционной системы. На Macintosh не работает.
Синтаксис
Environ({envstring | number})
Функция Environ принимает следующие именованные аргументы:
Аргумент	Назначение	|
envstring	Необязательный. Строковое выражение, содержащее имя переменной среды.	1
number	Необязательный. Числовое выражение, соответствующее номеру строки в таблице переменных среды.
Если значение аргумента envstring не может быть найдено в таблице переменных среды, функция возвращает строку нулевой длины («»). Иначе функция возвращает текст, присвоенный определенному параметру envstring, текст, который следует за знаком равенства (=) в таблице переменных среды для определенной переменной.
EOF
• Z
Возвращает значение True при достижении конца файла, открытого для прямого или последовательного доступа.
Синтаксис
EOF(f21епumber)
Обязательный аргумент filenumber является Integer-значением, содержащим допустимый номер файла. Эту функцию следует использовать перед попыткой доступа к концу файла.
Пока конец файла (открытого для Random- или Binary-доступа) не достигнут, функция возвращает значение False. При этом из файла можно получать данные.
Если файл был открыт для Binary-доступа, попытка чтения записей из него функцией Input при условии, что EOF возвращает значение True, приведет к гене
778
Приложение Г
рации ошибки. Используйте функции LOF и Loe вместо EOF при чтении бинарных файлов функцией Input или используйте GET с функцией EOF. С файлами, открытыми для Output, функция EOF всегда возвращает True.
Error
Возвращает еггог-сообщение, соответствующее заданному номеру ошибки.
Синтаксис
Error[(errornumber)]
Необязательный аргумент errornumber может быть любым допустимым еггог-номером. Если errornumber — допустимый error-номер, но не определен, функция возвращает сообщение "Application-defined or object-defined error." Если аргумент отсутствует, возвращается сообщение, относящееся к последней run-time-ошибке. Если же errornumber равен 0, функция возвращает строку нулевой длины ("").
Ехр
Возвращает значение (тип Double), определяющее число е (основание натурального логарифма), возведенное в степень.
Синтаксис
Exp(number)
Обязательный аргумент number — Double- или любое допустимое численное выражение. Если значение аргумента превышает число 709.782712893, возникнет ошибка. Константа е равна приблизительно 2.718282.
FileAttr
Возвращает значение (тип Long), представляющее файловый режим для файла, открытого с использованием оператора Open.
Синтаксис
FileAttr(filenumber, returntype)
Функция FileAttr имеет следующие именованные аргументы:
Аргумент	Назначение
filenumber	Обязательный; тип Integer. Любой допустимый файловый номер.
returntype	Обязательный; тип Integer. Число, указывающее на тип возвращаемой информации. Для определения файлового режима следует задать значение 1. Для получения дескриптора файла операционной системы укажите значение 2 (только для 16-битной системы!).
При значении аргумента returntype равном 1, можно получить следующие результаты:
Режим	Значение
Input	1
Output	2
Функции в VBA
779
Режим	Значение
Random	4
Append	8
Binary	32
FileDateTime
Возвращает значение [тип Variant (Date)], которое указывает дату и время создания или последней модификации файла.
Синтаксис
FileDateTime(pathname)
Обязательный аргумент pathname является строковым выражением, определяющим имя файла, которое может включать каталог (папку) и драйвер.
Пример
Следующая строка приводит к выдаче в окне MsgBox информации о времени создания файла "TESTFILE".
MsgBox FileDateTime("TESTFILE")
FileLen
Возвращает значение (тип Long) длины (размера) файла в байтах.
Синтаксис
FileLen(pathname)
Обязательный аргумент pathname является строковым выражением, определяющим имя файла, которое может включать каталог (папку) и драйвер. Если указанный в аргументе файл открыт при вызове функции FileLen, возвращаемое значение имеет отношение к длине файла непосредственно перед открытием.
Чтобы получить длину открытого файла, используйте функцию LOF.
Пример
Следующая строка приводит к выдаче в окне MsgBox информации о длине файла "TESTFILE".
MsgBox FileLen ("TESTFILE")
Filter
Возвращает массив (начинающийся с нулевого индекса), содержащий поднабор строчного массива на основе заданного критерия.
Синтаксис
Filter(sourcesrray, match[, include!, compare]])
Функция Filter имеет следующие именованные аргументы:
Аргумент	Назначение
sourcearray	Обязательный. Одномерный массив, в котором производится поиск.
match	Обязательный. Строка для поиска.
780
Приложение Г
Аргумент	Назначение
include	Необязательный. Значение типа Boolean, определяющее, какое значение возвращать: включающее или не включающее шаблон match. Если include — True, функция Filter возвращает поднабор массива, который содержит match как подстроку. Если include — False, Filter возвращает поднабор массива, который не содержит match как подстроку.
compare	Необязательный. Численной значение, указывающее тип сравнения.
Аргумент compare может иметь следующие значения:
Константа	Значение	Назначение
vbUseCompareOption	-1	Выполнять сравнение с использованием настроек оператора Option Compare.
vbBinaryCompare	0	Выполнять бинарное сравнение.
vbTextCompare	1	Выполнять текстовое сравнение.
vbDatabaseCompare	2	Только для Microsoft Access. Выполнять сравнение, основанное на информации в базе данных.
Если ни одного совпадения с шаблоном match в sourcearray не обнаруживается, функция Filter возвращает пустой массив. Если sourcearray — Null или — неодномерный массив, возникает ошибка.
Fix
Возвращает целую часть числа.
Синтаксис
Fix(number)
Обязательный аргумент number имеет тип Double или является допустимым численным выражением. Если number — Null, возвращается Null.
И функция Int, и функция Fix удаляют дробную часть аргумента number и возвращают целое значение. Отличаются эти функции при работе с отрицательным аргументом: Int возвращает ближайшее меньшее отрицательное число, a Fix — ближайшее большее отрицательное число.
Примеры Dim My_Number as Integer My_Number = Int(19.8) My_Number = Fix(19.2)	' результат ’ результат	19 19
My_Number = Int(-19.8)	’ результат	-20
My_Number = Fix(-19.8)	’ результат	-19
My_Number = Int(-19.2)	' результат	-20
My_Number = Fix(-19.2)	’ результат	-19
Функции в VBA
781
Format
Возвращает строку [тип Variant (String)], содержащую значение, отформатированное согласно инструкциям, находящимся в format-выражении.
Синтаксис
Format(expression[, fornfat], firstdayofweek], firstweekofyear]]])
Функция Format принимает следующие аргументы:
Аргумент	Назначение
expression	Обязательный. Любое допустимое выражение.
format	Необязательный. Допустимое выражение именованного или определенного пользователем формата.	|
firstdayofweek	Необязательный. Константа, которая определяет первый день | недели.
firstweekofyear	Необязательный. Константа, которая определяет первую неделю года.
Аргумент firstdayofweek может принимать следующие значения:
Константа	Значение	Описание
vbUseSystem	0	Использовать настройку NLS API.
Vb Sunday	1	Sunday
vbMonday	2	Monday
vbTuesday	3	Tuesday	।
vb Wednesday	4	Wednesday
vbThursday	5	Thursday
vbFriday	6	Friday
vbSaturday	7	Saturday
Аргумент firstweekofyear может принимать следующие значения:
Константа	Значение	Описание
vbUseSystem	0	Использовать настройку NLS API.
vbFirstJanl	1	Начинать с недели, в которой имеется дата первое января.
vbFirstFourDays	2	Начинать с первой недели, в которой имеется, по крайней мере, четыре дня года.
vbFirstFuIl Week	3	Начинать с первой полной недели года.
Если вы пытаетесь форматировать число, не определяя format, функция Format обеспечивает функциональность, подобную функциональности Str. Однако положительные числа, форматируемые как строки с использованием функции Format, не включают лидирующего пробела, резервируемого для знака значения.
782
Приложение Г
Символ	Диапазон	|
D	1-30
Dd	1-30
WW	1-51
ттт	Отображать полное наименование месяца (Юлианские наименования месяцев не имеют сокращений).
У	1-355
УУУУ	100-9666
Formatcurrency
Возвращает выражение, отформатированное как денежное (валютное) выражение с использованием значения, заданного на вкладке Денежная единица окна Свойства: Язык и стандарты, доступного из Панели управления.
Синтаксис
Formatcurrency(Expression[, NumDigitsAfterDecimal [, IncludeLeadingDigit [, UseParensForNegativeNumbers [, GroupDigits]]]])
Функция Formatcurrency принимает следующие аргументы:
Аргумент	Назначение
Expression	Обязательный. Выражение для форматирования.
NumDigitsAfterDecimal	Необязательный. Численное значение, определяющее количество отображаемых знаков справа от десятичной точки. Значение по умолчанию для этого аргумента равно -1, что означает использование региональных настроек.
IncludeLeadingDigit	Необязательный. Константа трех состояний, определяющая, следует ли отображать ведущий ноль для дробных чисел.
UseParensForNegative- Numbers	Необязательный. Константа трех состояний, определяющая, следует ли помещать отрицательные значения внутри круглых скобок.
GroupDigits	Необязательный. Константа трех состояний, определяющая, группировать ли цифры с помощью ограничителей, заданных региональными настройками.
Аргументы IncludeLeadingDigit, UseParensForNegativeNumbers и GroupDigits могут принимать следующие значения:
Константа	Значение	Описание
vbTrue	-1	True
vbFalse	0	False
vbUseDefauIt	-2	Использовать региональные настройки компьютера.
Когда один или более необязательных аргументов пропускается, значения для пропущенных аргументов используются из региональных настроек компьютера.
Функции в VBA
783
FormatDateTime
Возвращает выражение, отформатированное, как дата или время.
Синтаксис
FormatDateTime(Date[,NamedFormat])
Функция FormatDateTime принимает следующие аргументы:
Аргумент	Назначение
Date	Обязательный. Дата для форматирования.
NamedFormat	Необязательный. Численное значение, указывающее, необходимый формат. Если опущен, используется vbGeneralDate.
Аргумент NamedFormat может принимать следующие значения:
Константа	Значение	Описание
vbGeneralDate	0	Отображать дату и/или время. Если в аргументе Date имеется часть даты, дата отображается в коротком формате. Если в аргументе Date имеется часть времени, она отображается в длинном формате.
vbLongDate	1	Отображать дату с использованием длинного формата, установленного на компьютере в региональных настройках.
vbShortDate	2	Отображать дату с использованием короткого формата, установленного на компьютере в региональных настройках.
vbLongTime	3	Отображать время с использованием временного формата, установленного на компьютере в региональных настройках.
vbShortTime	4	Отображать время с использованием формата 24-hour (hh:mm).
FormatNumber
Возвращает выражение, отформатированное, как число.
Синтаксис
FormatNumber{Expression[,NumDigitsAfterDecimal [,IncludeLeadingDigit [, UseParensForNegativeNumbers [,GroupDigits]]]])
Функция FormatNumber принимает следующие аргументы:
Аргумент	Назначение
Expression	Обязательный. Выражение для форматирования.
NumDigitsAf terDecimal	Необязательный. Численное значение, определяющее количество отображаемых знаков справа от десятичной точки. Значение по умолчанию для этого аргумента равно -1, что означает использование региональных настроек.
784
Приложение Г
Аргумент	Назначение
IncludeLeadingDigit	Необязательный. Константа трех состояний, определяющая, следует ли отображать ведущий ноль для дробных чисел.
UseParensForNegativeNumbers	Необязательный. Константа трех состояний, определяющая, следует ли помещать отрицательные значения внутри круглых скобок.
GroupDigits	Необязательный. Константа трех состояний, определяющая, группировать ли цифры с помощью ограничителей, заданных региональными настройками.
Аргументы IncludeLeadingDigit, UseParensForNegativeNumbers и GroupDigits могут принимать следующие значения:
Константа	Значение	Описание
vbTrue	-1	True
vbFalse	0	False
vbUseDefault	-2	Использовать региональные настройки компьютера.
Когда один или более необязательных аргументов пропускается, значения для пропущенных аргументов используются из региональных настроек компьютера.
FormatPercent
Возвращает выражение, отформатированное, как процентное отношение (умноженное на 100) с конечным знаком процента (%).
Синтаксис
FormatPercent(Expression[,NumDigitsAft erDecimal [,IncludeLeadingDigit [,UseParensForNegativeNumbers [,GroupDigits]]]])
Функция FormatPercent имеет следующие аргументы:
Аргумент	Назначение
Expression	Обязательный. Выражение для форматирования.
NumDigitsAf terDecimal у	Необязательный. Численное значение, определяющее количество отображаемых знаков справа от десятичной точки. Значение по умолчанию для этого аргумента равно -1, что означает использование региональных настроек.
IncludeLeadingDigit	Необязательный. Константа трех состояний, определяющая, следует ли отображать ведущий ноль для дробных чисел.
UseParensForNegative- Numbers	Необязательный. Константа трех состояний, определяющая, следует ли помещать отрицательные значения внутри круглых скобок.
GroupDigits	Необязательный. Константа трех состояний, определяющая, группировать ли цифры с помощью ограничителей, заданных региональными настройками.
Функции в VBA
785
Когда один или более необязательных аргументов пропускается, значения для пропущенных аргументов используются из региональных настроек компьютера:
Константа	Значение	Описание
vbTrue	-1	True
vbFalse	0	False
vbUseDefault	-2	Использовать региональные настройки компьютера.
Когда один или более необязательных аргументов пропускается, значения для пропущенных аргументов используются из региональных настроек компьютера.
FreeFile
Возвращает значение (тип Integer), представляющее следующий файловый номер1, доступный для использования оператором Open.
Синтаксис
FreeFile [ (rangenumber) ]	•
Необязательный аргумент rangenumber (тип Variant) определяет диапазон для возвращаемых файловых номеров. Если этот аргумент задается нулевым (по умолчанию), то возвращается файловый номер в диапазоне 1-255, включительно. Для диапазона 256-511 используется значение 1.
* ' А
FV
Возвращает будущее значение (тип Double) ежегодных поступлений (annuity) на базе периодических, фиксированных платежей (fixed payments) и фиксированной процентной ставки (fixed interest rate).
Синтаксис	'
FV(rate, nper, pmt[, pv[, type]]) Функция FV имеет следующие именованные аргументы:
Аргумент	Назначение
rate	Обязательный. Тип Double. Процентная ставка за период. Например, если вы получаете ссуду на покупку машины из расчета 10 процентов годовых [annual percentage rate (APR)] и вносите ежемесячные платежи, то ставка за период должна составлять 0.1/12 или 0.0083.
прег	Обязательный. Тип Integer. Общее число периодов платежей в ежегодных поступлениях (annuity). Например, если вы вносите ежемесячные платежи в счет погашения четырехлетней ссуды на покупку автомашины, в вашей ссуде будет всего 4 * 12 (или 48) периодов платежей.
pmt	Обязательный. Тип Double. Платеж, который должен быть внесен за каждый период. Платежи обычно состоят из основного платежа (principal) и платежа по процентам (interest), которые не изменяются на протяжении выплаты взноса.
1 Файловый номер (file number) — число, используемое в операторе Open для открытия файла.
786
Приложение Г
Аргумент	Назначение
pv	Необязательный. Тип Variant. Настоящая величина [или твердая (lump sum)] ряда будущих платежей. Например, когда вы берете в долг деньги, чтобы купить автомобиль, сумма займа (loan amount) — это настоящая величина для кредитора ежемесячных платежей за автомобиль, которые вы будете вносить. Если аргумент отсутствует, то он подразумевается равным 0.
type	Необязательный. Тип Variant. Определяет, когда должен производиться платеж. Используется 0, если платеж должен производиться в конце периода платежа или 1, если срок платежа наступает в начале периода платежа. Если отсутствует, подразумевается 0.
Ежегодные поступления, аннуитет (annuity) — это ряд фиксированных наличных платежей, вносимых в течение некоторого периода времени. Поступления могут быть ссудой, такой как ипотека (home mortgage) или инвестицией, такой как план ежемесячных накоплений (monthly savings plan).
Аргументы rate и прег должны вычисляться с использованием периодов платежей, выраженных в одних и тех же единицах. Например, если rate вычисляется с использованием месяцев, прег должен также вычисляться в месяцах.
Для всех аргументов наличные платежи, такие как депозиты (deposits to savings) представляются отрицательными числами; наличные поступления, такие как дивиденды, представляются положительными числами.
GetAllSettings
Возвращает список ключевых настроек и их значения в Windows реестре (или файле инициализации приложения на Macintosh).
Синтаксис
GetAllSettings(appname, section)
Функция GetAllSettings принимает следующие именованные аргументы:
Аргумент	Назначение
аррпате	Обязательный. Строковое выражение, содержащее имя приложения или проекта, ключевые установки которого требуются.
section	Обязательный. Строковое выражение, содержащее имя секции, ключевые настройки которой необходимо получить. Функция возвращает двумерный массив строк, содержащий все ключевые настройки в указанной секции и соответствующие им значения.
Функция GetAllSettings возвращает неинициализированное Variant-значение, если не задан либо аргумент appname, либо section.
GetAttr
Возвращает значение (тип Integer), представляющее атрибуты файла, каталога или папки.
Синтаксис
GetAttr(pathname)
Функции в VBA
787
Обязательный аргумент pathname является строковым выражением, которое определяет имя файла, которое может включать каталог (или папку) и драйвер.
Значения, возвращаемые функцией GetAttr, представляют собой сумму следующих значений атрибутов:
Константа	Значение	Описание
vbNormal	0	Обычный (Normal).
vbKeadOnly	1	Только на чтение (Read-only).
vbHidden	2	Скрытый (Hidden).
vbSystem	4	Системный файл (System file)
vbDirectory	16	Каталог или папка (Directory or folder).
vbArchive	32	Файл изменился с момента архивации (недоступен на Macintosh).
vbAlias	64	Определяет имя файла как алиасное (Specified file name is an alias). Только для Macintosh.
Чтобы определить установленные атрибуты, необходимо использовать оператор And для побитового сравнения возвращаемого функцией значения и некоторого шаблона с указанием конкретного атрибута. Если результатом сравнения будет нулевое значение, это означает, что атрибут не установлен.
GetObject
Возвращает ссылку на объект, поддерживаемый ActiveX-компонентом. Синтаксис GetObject([pathname] [, class])
Функция GetObject принимает следующие именованные аргументы:
Аргумент	Назначение	।
pathname	Необязательный; тип Variant (String). Полный путь и имя фай- 1 ла, содержащего объект. Если pathname опускается, необходимо указывать аргумент class.
class	Необязательный; тип Variant (String). Строка — класс объекта.
Аргумент class использует следующий синтаксис appname.objecttype и имеет две составляющие:
Аргумент	Назначение
аррпате	Обязательный; тип Variant (String). Имя приложения, обеспечивающего объектом.
objecttype	Обязательный; тип Variant (String). Тип или класс объекта.
Используйте функцию GetObject для доступа к ActiveX-объекту из файла и назначайте объект объектной переменной. Оператор Set применяйте для присваивания объектной переменной возвращаемого функцией GetObject значения. Например:
Dim CObject As Object
Set CObject = GetObject("C:\CAD\SCHEMA.CAD")
788
Приложение Г
Если pathname является строкой нулевой длины функция GetObject возвращает экземпляр нового объекта указанного типа. Если аргумент pathname опускается, GetObject возвращает текущий активный объект указанного типа. Если ни одного указанного объекта не существует, возникает ошибка.
Пример
В следующей процедуре функция GetObject используется для того, чтобы определить наличие в системе экземпляра приложения Excel.
Sub Test GetObject()
Dim xlApp As Object
Dim xlSheet As Object
On Error Resume Next Set xlApp - Nothing ' Set xlApp = GetObject(, "Excel.Application") If Err.Number <> 0 Then
Set xlApp = CreateObject("Excel.Application") End If
Err.Clear
Set xlBook = xlApp.Workbooks-Add
Set xlSheet - xlBook.Worksheets(1) xlSheet.Application.Visible = True End Sub
GetSetting
Возвращает значение ключевой настройки определенного приложения в Windows-реестре.
Синтаксис
GetSetting(аррпате, section, keyf, default])
Функция GetSetting принимает следующие именованные аргументы:
1 Аргумент	Назначение
appname	Обязательный. Строковое выражение, содержащее имя приложения или проекта, настройки которого необходимы.
I section	Обязательный. Строковое выражение, содержащее наименование секции, в которой следует искать ключевую настройку.
key	Обязательный. Строковое выражение, содержащее имя настройки.
i default	Необязательный. Выражение, содержащее возвращаемое значение, если в настройке не установлено никакого значения. Если этот параметр опускается, используется строка нулевой длины
Если какой-либо из элементов, указанных в аргумента функции GetSetting, не существует, функция возвращает default.
Hex
Возвращает строку, представляющую шестнадцатиричное значение числа.
Синтаксис
Hex (number)
Функции в VBA
789
Обязательный аргумент number является любым допустимым числовым (или строковым) выражением.
Если number не является целым числом, сначала выполняется округление до целого.
если number	функция возвращает
Null	Null
Empty	Ноль (0)
Примеры
Му_Нех = Hex(5)	' Returns	5
Му_Нех = Hex(10)	1 Returns	A
Му_Нех = Hex (459)	' Returns	1CB
Му__Нех = Hex (4 59.4)	' Returns	1CB
Му_Нех = Hex (459.7)	' Returns	ICC
Hour
Возвращает значение [TnnVariant (Integer)], определяющее целое число в диапазоне от 0 до 23, включительно, представляющее час дня.
Синтаксис
Hour(time)
Обязательный аргумент time — любое значение типа Variant, численное выражение, строковое выражение или любая их комбинация, представляющая время. Для аргумента time, содержащего Null, функция возвращает Null.
Ilf
Возвращает значение одного из двух своих аргументов в зависимости от оцениваемого выражения.
Синтаксис
Ilf(ехрг, truepart, falsepart)
Функция Ilf имеет следующие (все обязательные) именованные аргументы:
аргумент	назначение
expr	Оцениваемое выражение.
truepart	Значение или выражение, которое возвращается, если ехрг имеет значение True.
falsepart	Значение или выражение, которое возвращается, если ехрг имеет значение False.
Пример х = 200 MsgBox Ilf(х > 1000, "Много", "Мало") ' выдача слова "Мало"
790
Приложение Г
Input
Функция String возвращает строку символов из файла, открытого в режиме Input или Binary.
Синтаксис
Input(number, [#]filenumber)	*
Функция Input имеет следующие (обязательные) аргументы:
аргумент	назначение
Number	Любое допустимое выражение (возвращающее число), определяющее число возвращаемых символов.
Filenumber	Допустимый номер файла.
Данные, считываемые функцией Input, предварительно должны быть записаны в файл посредством функции Print # или Put.
В отличие от оператора Input # функция Input возвращает все прочитанные символы, включая запятые, символы возврата каретки, перехода на другую строку, кавычки и ведущие пробелы.
Пример
В этом примере открывается текстовый файл и в цикле происходит посимвольное считывание и вывод в окно Immediate .
Open "F:\ZZ\WWW.TXT" For Input As #1	' открыть файл
Do While Not EOF(l)	' цикл до конца файла
CharOne = Input (1, #1)	' считать символ	1
Debug.Print CharOne ' отобразить в Immediate-окне
Loop
Close #1	' закрыть файл
InputBox
Отображает запрос в диалоговом окне, ожидает ввода пользователем строки (или щелчка на кнопке окна), а затем возвращает строку из поля ввода окна.
Синтаксис
InputBox (prompt [, title] [, default] [, iqaos] [, ypos] [, helpfile, context])
Функция InputBox принимает следующие именованные аргументы:
аргумент	назначение
prompt	Обязательный. Любое строковое выражение, отображаемое в качестве подсказки. Максимальная длина этой строки примерно 1024 символа (в зависимости от используемой ширины символов). Если необходимо, чтобы prompt-аргумент содержал более одной строки, следует использовать символы разделения строк: символ возврата каретки (Chr(13)) и символ перехода на другую строку (Chr(10)) или комбинацию этих символов (Chr(13) & Chr(10)).
title	Необязательный. Строка, используемая в качестве заголовка для окна ввода. Если этот аргумент опускается, в качестве заголовка выводится наименование приложения, в котором вызывается функция.
Функции в VBA
791
аргумент	назначение
default	Необязательный. Является любым строковым выражением и используется как значение по умолчанию для пользовательского ввода. Если опускается, строка ввода в окне отображается пустой.
xpos	Необязательный. Численное значение, определяющее (в твипах) горизонтальное расстояние от левого края окна до верхнего левого угла диалогового окна. Если этот аргумент не указан, диалоговое окно центрируется горизонтально.
ypos	Необязательный. Численное значение, определяющее (в твипах) вертикальное расстояние от верхнего края окна до верхней границы диалогового окна. Если этот аргумент не указывается, диалоговое окно позиционируется по вертикали примерно на одну треть от нижней части экрана.
helpfile	Необязательный. Строковое выражение, которое содержит имя справочного Windows-файла для обеспечения контекстной справки. Если этот аргумент используется, необходимо включать и аргумент context.
context	Необязательный. Численное выражение, которое указывает раздел в справочном файле, относящийся к отображаемому окну.
InStr
Возвращает значение [тип Variant (Long)], определяющее позицию первого вхождения одной строки внутри другой.
Синтаксис
InStr([start, ]stringl, string2[, compare])
Функция InStr принимает следующие аргументы:
Аргумент	назначение
start	Необязательный. Числовое выражение, задающее начальную позицию для поиска. Если аргумент не указывается, то поиск начинается с первого символа. Если аргумент start содержит значение Null, возникает ошибка. Аргумент start является обязательным, если указывается аргумент compare.
stringl	Обязательный. Строковое выражение, в котором выполняется поиск.
string2	Обязательный. Строковое выражение, поиск положения которого выполняет функция.
compare	Необязательный. Определяет тип сравнения строк. Если не опускается, то используется сравнение согласно оператору Option Compare.
Аргумент compare может принимать следующие значения:
константа	значение	описание
vbUseCompareOption	-1	Выполняется сравнение согласно установкам посредством оператора Option Compare.
vbBinaryComp are	0	Выполняется двоичное сравнение.
792
Приложение Г
константа	значение	описание
vbTextCompare	1	Выполняется двоичное сравнение.
vbDatabaseCompare	2	Только для Microsoft Access. Выполняется сравнение, основанное на информации в вашей базе данных.
Возвращаемые значения
если	InStr возвращает
stringl имеет нулевую длину	0
string 1 — Null	Null
string2 имеет нулевую длину	start	1
string2 — Null	Null
string2 не найдена	0
string2 найдена в stringl	Позиция, в которой произошло совпадение.
start > string2	0
InStrRev
Возвращает позицию появления одной строки внутри другой, начиная с конца строки.
Синтаксис
InstrRev(stringcheck, stringmatch[, start], compare]])
Функция InstrRev принимает следующие именованные аргументы:
аргумент	Назначение
stringcheck	Обязательный. Строка, в которой выполняется поиск.
stringmatch	Обязательный. Строковое выражение, поиск которого выполняется.	i
start	Необязательный. Численное выражение, устанавливающее начальную позицию для поиска. Если не указывается, используется значение -1, что означает начало поиска с последнего символа строки. Значение Null вызывает появление ошибки.
compare	Необязательный. Численное значение, задающее тип сравнения. Если не указывается, выполняется двоичное сравнение.
Аргумент compare может принимать следующие значения:
константа	значение	описание
vbUseCompareOption	-1	Выполняется сравнение согласно установкам посредством оператора Option Compare.
vbBinaryCompare	0	Выполняется двоичное сравнение.
vbTextCompare	1		Выполняется двоичное сравнение.
Функции в VBA
793
константа	значение	описание
vbDatabaseCompare	2	Только для Microsoft Access. Выполняется сравнение, основанное на информации в вашей базе данных.
Функция InStrRev возвращает следующие значения:
если	InStrRev возвращает
stringcheck имеет нулевую длину	0
stringcheck — Null	Null
stringmatch имеет нулевую длину	start
stringmatch — Null	Null
stringmatch не найдена	0
stringmatch найдена в stringcheck	Позиция, в которой произошло совпадение.
start > Lenfstringmatch)	0
Int
Возвращает целую часть числа.
Синтаксис
Fix(number)
Обязательный аргумент number — число (тип Double) или допустимое числовое выражение. Если number содержит Null, функция возвращает Null.
IPmt
Возвращает значение (тип Double) платежей по процентам для данного периода ежегодных поступлений на базе периодических, фиксированных платежей и фиксированной процентной ставки.
Синтаксис
IPmt(rate, per, nper, pv[, fv[, type]])
Именованные аргументы функции IPmt:
аргумент	назначение
rate	Обязательный. Тип Double. Процентная ставка за период. Например, если вы берете заем для покупки автомобиля из расчета 10 процентов годовых (annual percentage rate, APR) и делаете ежемесячные платежи, ставка за период составляет 0.1/12, или 0.0083.
per	Обязательный. Значение типа Double. Период платежа в диапазоне 1 - nper.
nper	Обязательный. Значение типа Double. Общее число периодов платежей в ежегодных поступлениях (annuity). Например, если вы вносите ежемесячные платежи в счет погашения четырехлетней ссуды, ваша ссуда имеет всего 4 * 12 (или 48) периодов платежа.
794
Приложение Г
аргумент	назначение
ри	Обязательный. Значение Double. Текущая стоимость или общая сумма всех будущих платежей с настоящего момента. Например, когда вы получаете заем, чтобы купить автомобиль, сумма займа — это текущее значение (present value) для кредитора.
fv	Необязательный. Значение Variant. Будущее значение (future value) или баланс наличности (cash balance), которого необходимо достичь после того, как вы внесете окончательный платеж. Например, будущая величина ссуды равна $0, потому что это ее величина после окончательного платежа. Однако если вы хотите накопить $50,000 за 18 лет, то $50,000 — это будущее значение. Если аргумент отсутствует, то он предполагается равным 0.
type	Необязательный. Значение Variant. Определяет, когда должен производиться платеж. Используется 0, если срок платежа наступает в конце периода платежа или используется 1, если срок платежа наступает в начале периода. Если аргумент отсутствует, он предполагается равным 0.
Ежегодные поступления (annuity) — это ряд фиксированных наличных платежей (fixed cash payments), внесенных в течение некоторого периода времени. Поступления могут быть ссудой, такой как ипотека (home mortgage) или инвестиции (investment), такие как план ежемесячных накоплений (monthly savings plan).
Аргументы rate и прег должны вычисляться с использованием периодов платежей, выраженных в одних и тех же единицах. Например, если rate вычисляется с использованием месяцев, прег также должен вычисляться в месяцах.
Для всех аргументов выплаченные наличные платежи, такие как депозиты (deposits to savings) представляются отрицательными числами; прибыли, такие как дивиденды (dividend checks), представляются положительными числами.
IRR
Возвращает (значение типа Double) внутреннюю скорость оборота для серии периодических операций с наличными.
Синтаксис
IRR(values О [, guess])
Именованные аргументы функции IRR:
аргумент	назначение
valuesQ	Обязательный. Массив (тип Double) со значениями, для которых определяется внутренняя скорость оборота средств. Массив должен содержать, по меньшей мере, одно отрицательное значение (выплата) и одно — положительное (поступление).
guess	'	Необязательный. Ваша оценка (тип Variant) возвращаемого функцией результата. Если отсутствует, то полагается равным значению 0.1 (10%).
Функция IRR использует порядок значений массива для интерпретации порядка денежных выплат или поступлений, поэтому следует внимательно указывать этот порядок.
Функции в VBA
795
IsArray
Возвращает значение (тип Boolean), указывающее, является ли переменная массивом.
Синтаксис	t
IsArray (varname)
Обязательный аргумент varname — идентификатор, определяющий переменную.
Функция IsArray возвращает значение True, если переменная-аргумент является массивом. В противном случае возвращается значение False.
Примеры
Dim Arrayl(1 То 5) As Integer, Array2, Rez
Array2 = Array (1, 2, 3)
Rez = IsArray(Arrayl)	1 True
Rez = IsArray(Array2)	1 True
IsDate
Возвращает значение (тип Boolean), указывающее, может ли выражение-аргумент быть конвертировано в дату.
Синтаксис
IsDate(expression)
Обязательный аргумент expression — значение (тип Variant), содержащее выражение даты или любое строковое выражение, распознаваемое как дата или время.
Функция IsDate возвращает значение True, если выражение-аргумент является датой или может быть представлен как дата; иначе возвращается значение False.
Примеры
Dim DateExpl, DateExp2, NoDate, Rez
DateExpl= "February 12, 1969"
DateExp2= #2/12/69#
NoDate = " "
Rez = IsDate(NoDate) 1 False
Rez = IsDate(DateExpl) ' True
Rez = IsDate(DateExp2)	1 True
IsEmpty
Возвращает значение (тип Boolean ), указывающее, была ли переменная-аргумент инициализирована.
Синтаксис
IsEmpty(expression)
Обязательный аргумент expression — значение (тип Variant), содержащее численное или строковое выражение. Но поскольку функция IsEmpty используется для определения того, инициализирована ли отдельная переменная, аргумент expression — чаще всего имя единственной переменной.
Функция IsEmpty возвращает значение True, если переменная инициализирована или ей явно было присвоено значение Empty; иначе — функция возвращает
796
Приложение Г
значение False. Значение False также возвращается всегда, когда expression содержит более одной переменной.
Примеры	,
Dim My_Var, Rez
MyCheck = IsEmpty(My_Var) ' True
*
My_Var = Null
MyCheck = IsEmpty(My_Var)	' False
My_Var = Empty
MyCheck = IsEmpty(My_Var)	' True
z
IsError
Функция возвращает значение (тип Boolean), указывающее, является ли выражение значением ошибки (еггог-значением).
Синтаксис
IsError(expressi on)
Обязательный аргумент expression может быть любым допустимым выражением.
Error-значения создаются преобразованием действительных чисел в error-значения с использованием функции CVErr. Функция IsError используется для определения того, представляет ли числовое выражение ошибку. IsError возвращает значение True, если аргумент expression указывает на ошибку, и — False в противном случае.
IsMissing
Возвращает значение (тип Boolean), указывающее, был ли необязательный аргумент (типа Variant) передан в процедуру (указан ли при вызове).
Синтаксис
IsMissing(argname)
Обязательный аргумент argname содержит имя необязательного аргумента процедуры.
Используйте функцию IsMissing для определения того, были ли определены при вызове процедуры необязательные аргументы. Функция IsMissing возвращает значение True, если для указанного аргумента не было при вызове процедуры указано никакого значения; иначе — возвращается значение False. Если функция IsMissing возвращает значение True для некоторого аргумента, использование отсутствующего аргумента в коде может вызвать определенную пользователем ошибку.
IsNull
Возвращает значение (тип Boolean), которое указывает, содержит ли выражение недопустимые данные (Null).
Синтаксис
IsNull(expression)
Обязательный аргумент expression — (тип Variant) численное или строковое выражение.
функции в VBA
797
Функция IsNull возвращает значение True, если expression — Null; иначе — IsNull возвращает False. Если expression содержит более одной переменной, Null в любой переменной приводит к тому, что для всего выражения функция возвращает значение True.
Значение Null указывает, что Variant содержит недопустимые данные. Null — это не то же самое, что Empty, которое указывает на то, что переменная еще не была инициализирована. Это — также не то же самое, что строка нулевой длины (”").
Обычно следует использовать функцию IsNull для определения того, содержит ли выражение значение Null.
Примеры
Dim MyVar, Rez
Rez = IsNull(My_Var) 'False
My_Var = Null
Rez = IsNull(My_Var)	'True
My__Var = ""
Rez = IsNull(My_Var)	'False
IsNumeric
Возвращает значение (тип Boolean), указывающее, является ли результатом вычисления выражения численное значение.
Синтаксис
IsNumeric(expression)
Обязательный аргумент expression — значение (тип Variant), содержащее численное или строковое выражение.
Функция IsNumeric возвращает значение True, если все expression распознается как число, иначе —возвращается значение False. Если expression является датой, функция возвращает значение False.
Примеры
В этом примере используется функция IsNumeric для определения, может ли переменная быть оценена как число.
StrVar =,"763"
BooleanVar = IsNumeric(StrVar) 'возвращает True
IsObject
Возвращает значение (тип Boolean), указывающее, представляет ли идентификатор объектную переменную.
Синтаксис
IsObject(identifier)
Обязательный аргумент identifier — имя переменной.
Функция IsObject возвращает значение True, если аргумент identifier является переменной, объявленной как Object-тип или как тип любого допустимого класса, или если identifier — Variant-переменная VarType vbObject, или объект типа, определенного пользователем; иначе — возвращается значение False. Функция IsObject возвращает значение True, даже если переменной было присвоено значение Nothing.
798
Приложение Г
Join
Возвращает строку, объединяя несколько подстрок, находящихся в массиве.
Синтаксис
Join(sourcearray[, delimiter])	'
Функция Join принимает следующие именованные аргументы:
аргумент	назначение
sourcearray	Обязательный. Одномерный массив, содержащий подстроки, которые следует объединить.
delimiter	Необязательный. Символ, используемый для разделения подстрок в возвращаемой строке. Если параметр опускается, используется символ пробела (" "). Если этот аргумент является строкой нулевой длины (""), подстроки объединяются без разделителя.
Примеры
Dim array_str(3) array_str(l) = "Первый" array_str(2) = "Второй" array—str(3) = "Третий" MsgBox Join(array_str,
'вывод: "Первый:Второй:Третий "
LBound
Функция возвращает значение (тип Long), содержащее наименьшее значение индекса массива.
Синтаксис
LBound(arrayname[, dimension])
Функция LBound принимает следующие аргументы:
аргумент	назначение
аггаупатпе	Обязательный. Имя переменной-массива.
dimension	Необязательный; тип Variant (Long). Целое число, определяющее, границу какой из размерностей следует возвратить. Для первой размерности указывайте значение 1, для второй — 2, и так далее. Если аргумент dimension опускается, он предполагается равным 1.
Функцию LBound можно использовать совместно с функцией UBound для определения размера массива, поскольку последняя возвращает наибольшее значение индекса массива.
Пример
Dim	Rez		
Dim	A (4 To 100,	0 To	3, -5 To 4)
Rez	= LBound(A,	1)	'возвращает 4
Rez	= LBound(A,	2)	'возвращает 0
Rez	= LBound(A,	3)	'возвращает -5
Функции в VBA
799
LCase
Возвращает значение (тип String), которое преобразовано к нижнему регистру.
Синтаксис
LCase(string)
Обязательный аргумент string — любое допустимое строковое выражение. Если string содержит Null, возвращается Null.
К нижнему регистру преобразуются только символы верхнего регистра. Остальные символы остаются без изменений.
Пример
Dim Ustring, Lstring
Ustring = "Hello Nike-2"
Lstring = LCase (Ustring) ' возвращает "hello nike-2".
Left
Возвращает значение [тип Variant (String)], содержащее указанное количество символов с левой стороны строки.
Синтаксис
Left(string, length)
Функция Left принимает следующие именованные аргументы:
аргумент	назначение
string	Обязательный. Строковое выражение, из которого возвращается указанное количество символов. Если аргумент string содержит Null, возвращается также Null.
length	Обязательный; тип Variant (Long). Численное выражение, определяющее количество возвращаемых символов строки. Если это значение равно 0, возвращается строка нулевой длины (””). Если аргумент больше или равен длине строки, возвращается вся строка.
Примеры
Dim StrMY
StrMY = Left("Hello World", 2)
StrMY = Left("Hello World", 6)
StrMY = Left("Hello World", 20)
'возвращает "He"
'возвращает "Hello "
'возвращает "Hello World"
Len
Возвращает значение (тип Long), содержащее количество символов (длину) строки или число байт, необходимых для сохранения переменной.
Синтаксис
Len(string | varname)
Функция Len принимает следующие аргументы:
800
Приложение Г
аргумент	назначение
string	Любое допустимое строковое выражение. Если аргумент содержит Null, функция возвращает Null.
varname	Любое допустимое имя переменной. Если varname содержит Null, функция возвращает Null. Если varname — Variant, функция Len «рассматривает» его как строку и возвращает число символов в аргументе.
Loc
Возвращает значение (тип Long), определяющее текущую позицию чтения/за-писи в открытом файле.
Синтаксис
Loc(filenumber)
Обязательный аргумент filenumber — любой допустимый файловый номер (тип Integer).
В следующей таблице приведены режимы файлового доступа и соответствующие им возвращаемые значения функции Loc.
режим	возвращаемое значение
Random	Номер последней записи, которая считывалась из файла или записывалась в файл.
Sequential	Текущая байтовая позиция в файле, деленная на число 128.
Binary	Позиция последнего считанного или записанного байта.
Примеры
В этом примере открывается текстовый файл и в цикле происходит посимвольное считывание и вывод в окно Immediate считанного символа и номера текущей байтовой позиции в файле.
Open "F:\ZZ\WWW.TXT" For Input As #1 Do While Not EOF(l)
CharOne = Input(1, #1)
MyLocation = Loc(l)
Debug.Print CharOne; MyLocation
Loop
Close #1
'открыть файл
'цикл до конца файла 'считать символ 'текущая позиция
'отобразить в Immediate-окне
'закрыть файл t
LOF
Возвращает значение (тип Long), представляющее размер (в байтах) файла, открытого с использованием оператора Open.
Синтаксис
LOF(filenumber)
Обязательный аргумент filenumber — число (тип Integer), содержащее допустимый номер файла.
В качестве примера см. код для функции Loc.
функции в VBA
801
Log
Возвращает значение (тип Double), определяющее натуральный логарифм числа.
Синтаксис	*
hog(number)
Обязательный аргумент number — число (тип Double) или допустимое численное выражение, большее нуля.
Натуральный логарифм — это логарифм с основанием е , где константа е равна примерно 2.718282.
LTrim
Функция возвращает значение [тип Variant (String)], содержащее копию указанной строки без ведущих (leading) пробелов.
Синтаксис
LTrim(string)
Обязательный аргумент string — любое допустимое строковое выражение. Если аргумент содержит Null, функция возвращает Null.
Mid
Возвращает значение [тип Variant (String)], содержащее указанное число символов из строки.
Синтаксис
Mid(string, start], length])
Функция Mid принимает следующие именованные аргументы:
аргумент	назначение
string	Обязательный. Строковое выражение (тип String), из которого возвращается определенное число символов. Если аргумент string содержит Null, функция возвращает Null.
start	Обязательный; тип Long. Символьная позиция в строке string, с которой следует начинать выделение строки. Если значение аргумента start больше длины заданной строки, функция возвращает строку нулевой длины.
length	Необязательный; тип Variant (Long). Число возвращаемых из строки символов. Если опускается или если символов в строке меньше, чем length, включая символ в позиции start, функция возвращает все символы с позиции start до конца строки.
Примеры
SFirstWord = Mid("Mid Function Example", 1, 3) ' "Mid" SLastWord = Mid("Mid Function Example", 14 )	' "Example"
SMidWords = Mid("Mid Function Example", 5, 8) ' "Function"
26 Программирование на VBA 2002
802
Приложение Г
Minute
Функция возвращает [тип Variant (Integer)] целое число от 0 до 59, включительно, которое представляет минуты часа.
Синтаксис	.
Minute(time)
Обязательный аргумент time — численное (тип Variant) выражение, строковое выражение или любая комбинация, представляющая время. Если аргумент time содержит Null, функция возвращает Null.
Примеры
DTime = #4:35:17 PM#
DMinute = Minute(DTime) ' возвращаемое значение - 35	, 1
MIRR
Возвращает (тип Double) модифицируемую внутреннюю скорость оборота для ряда периодических операций с наличными.
Синтаксис
MIRR(values(), finance_rate, reinvest_rate)
Именованные аргументы функции MIRR:
аргумент	назначение
ualues()	Обязательный. Массив (тип Double) со значениями, для которых определяется внутренняя скорость оборота средств. Массив должен содержать, по меньшей мере, одно отрицательное значение (выплата) и одно — положительное (поступление).
finance_rate	Обязательный. Норма прибыли (тип Double), выплачиваемой за денежные средства, находящиеся в наличном обороте.
reinvest_rate	Обязательный. Норма прибыли (тип Double), получаемой за денежные средства, находящиеся в наличном обороте при инвестировании.
Функция MIRR учитывает как стоимость инвестиций, так и доход от реинвестирования, и использует порядок значений массива для интерпретации порядка денежных выплат или поступлений. Следует внимательно указывать этот порядок.
Month
Возвращает целое значение [тип Variant (Integer)] в диапазоне от 1 до 12, включительно, представляющее месяц года.
Синтаксис
Month(date)
Обязательный аргумент date — (тип Variant) численное выражение, строковое выражение или любая комбинация, которая представляет дату. Если аргумент date содержит Null, функция возвращает Null.
Возвращаемое значение функции зависит от значения свойства Calendar.
Функции в VBA
803
Примеры
DDateMy = #February 12, 1969#
DMonthMy = Month(MyDate) ' возвращает 2
MonthName
Возвращает строку, указывающую определенный месяц.
Синтаксис
MonthName(month[, abbreviate])
Функция MonthName имеет следующие аргументы:
аргумент	назначение
month	Обязательный. Числовое представление месяца. Например, Январь (January) — это 1, Февраль (February) — 2 и т.д.
abbreviate	Необязательный. Тип Boolean. Значение, которое указывает, следует ли использовать сокращение для отображения имени месяца. Если аргумент опущен, то по умолчанию принимается значение False, которое означает, сокращение не используется.
MsgBox
Отображает сообщение в диалоговом окне, ожидает нажатия на кнопку пользователем и возвращает значение (тип Integer), указывающее, какую кнопку выбрал пользователь.
Синтаксис
MsgBox(prompt[, buttons] [, title] [, helpfile, context])
Функция MsgBox имеет следующие именованные аргументы:
аргумент	назначение
prompt	Обязательный. Строковое выражение, отображаемое в диалоговом окне. Строка может содержать примерно 1024 символа (в зависимости от используемой ширины символов). Если необходимо, чтобы выражение prompt состояло из нескольких строк, можно для разделения строк использовать символы возврата каретки (Chr(13)), перехода на другую строку (Chr(10)) или комбинацию этих символов (Chr(13) & Chr(10)).
buttons	Необязательный. Числовое выражение, являющееся суммой значений, которые определяют количество и тип кнопок для отображения, используемый значок, кнопку по умолчанию и модальность диалогового окна Если не используется, принимается равным значению 0.
title	Необязательный. Строковое выражение для заголовка диалогового окна. Если не используется, в заголовке отображается наименование приложения.
helpfile	Необязательный. Строковое выражение, которое идентифицирует Help-файл для обеспечения контекстно-зависимой помощи. Если этот аргумент используется, context также должен использоваться.
context	Необязательный. Числовое выражение, указывающее раздел (в справочном файле), относящийся к отображаемому диалоговому окну.
804
Приложение Г
Аргумент buttons может принимать следующие значения (константы):
константа	значение	описание
vbOKOnly	0	Отображать только кнопку ОК.
vbOKCancel	1	Отображать кнопки ОК и Cancel.
vbAbortRetrylgnore	2	Отображать кнопки Abort, Retry и Ignore.
vbYesNoCancel	3	Отображать кнопки Yes, No и Cancel.
vbYesNo	4	Отображать кнопки Yes и No.
vbRetryCancel	5	Отображать кнопки Retry и Cancel.
vbCritical	16	Отображать значок Critical Message.
vbQuestion	32	Отображать значок Warning Query.
vbExclamation	48	Отображать значок Warning Message.
vblnformation	64	Отображать значок Information Message.
vbDefaultButtonl	0	Первая кнопка — кнопка по умолчанию.
vbDefaultButton2	256	Вторая кнопка — кнопка по умолчанию.
vbDefaultButton3	512	Третья кнопка — кнопка по умолчанию.
vbDefaultButton4	768	Четвертая кнопка — кнопка по умолчанию.
vbApplicationModal	0	Приложение — модальное; пользователь должен сначала «ответить» на диалоговое окно, прежде чем сможет продолжить работу с текущим приложением.
vbSystemModal	4096	Система — модальная; все приложения ожидают «ответа» на диалоговое окно.
vbMsgBoxHelpButton	16384	Добавляет кнопку Help к диалоговому окну.
VbMsgBoxSet-Foreground	65536	Определяет диалоговое окно как окно переднего плана.
vbMsgBoxRight	524288	Текст выравнивается по правой границе.
В этой таблице первая группа констант (0-5) описывает типы кнопок, отображаемых в диалоговом окне; следующая группа (16, 32, 48, 64) — стили значков; третья группа (0, 256, 512) определяет кнопку умолчания (кнопка, которая будет «срабатывать» при нажатии на клавишу Enter); четвертая группа (0, 4096) задает модальность диалогового окна.
Возвращаемые значения функции MsgBox:
константа	значение	выбранная кнопка
vbOK	1	OK
vbCancel	2	Cancel
vbAbort	3	Abort
vbRetry	4	Retry
vblgnore	5	Ignore
vbYes	6	Yes
vbNo	7	No
функции в VBA
805
Если используются оба аргумента helpfile и context, для вызова справочного файла, связанного с диалоговым окном MsgBox, достаточно нажать на клавиатуре клавишу F1. Если диалоговое окно содержит кнопку Cancel, то вместо щелчка на этой кнопке можно нажимать на клавишу Esc на клавиатуре.
Now
Возвращает текущую дату и время [тип Variant (Date)], используя системные дату и время компьютера.
Синтаксис
Now
NPer
Возвращает количество (тип Double) периодов выплаты для данного вклада на основе периодических фиксированных выплат и фиксированной процентной ставки.
Синтаксис
NPer (rate, pint, pv[, fv[, type]])
Функция NPer имеет следующие именованные аргументы:
аргумент	назначение
rate	Обязательный. Ставка (тип Double) — процентная ставка за период. Например, если вы получаете заем для покупки автомашины из расчета 10 процентов годовых (APR) и вносите ежемесячные платежи, то ставка за период составит 0.1/12 или 0.0083.
pmt	Обязательный. Выплата (тип Double), производимая в каждый период. Выплаты обычно состоят из основного платежа и платежа по процентам и не изменяются в течение срока займа.
pv	Обязательный. Тип Double. Текущее значение или величина сегодня всех будущих платежей или поступлений. Например если вы получаете заем для покупки автомашины, сумма займа является текущим значением для кредитора ежемесячных платежей, которые вы будете вносить.
f»	Необязательный. Значение типа Variant. Будущее значение или баланс наличности, который необходимо достичь после последнего платежа. Например, будущее значение займа равно $0 поскольку это — его значение после внесения последнего платежа. Однако если вы хотите накопить $50,000 в течение 18 лет на образование вашего ребенка, то $50,000 будет будущим значением. Если аргумент опущен, предполагается равным 0.
type	Необязательный. Значение типа Variant, обозначающее, когда должна производиться выплата. Используется 0, если срок платежа наступает в конце периода платежа, или 1, если выплата должна производиться в начале периода платежа. Если аргумент опущен, предполагается равным 0.
Ежегодные поступления (по займу и т.д., аннуитет) — это ряд фиксированных наличных платежей в течение периода времени. Аннуитет может быть ссудой, та
806
Приложение Г
кой как ипотека (home mortgage) или вкладами, такими как план ежемесячной экономии (monthly savings plan).
Для всех аргументов наличные выплаты, такие как вклады (deposits to savings) представляются отрицательными числами, наличные поступления, такие как дивиденды (dividend checks) представляются положительными числами.
Функция NPV
Возвращает значение типа Double, определяющее чистый текущий объем вклада на базе ряда периодических операций с наличностью (платежей и поступлений) и учетной ставки (discount rate).
Синтаксис
NPV(rate, valuesO)
Именованные аргументы функции NPV:
аргумент	назначение
rate	Обязательный. Тип Double, определяет учетную ставку за период.
valuesO	Обязательный. Массив типа Double. Определяет значения операций с наличностью. Массив должен содержать, по меньшей мере, одно отрицательное значение (платеж) и одно положительное значение (поступление).
Чистый текущий объем вклада — это текущее значение ряда будущих платежей и поступлений.
Функция NPV использует порядок значений в массиве для определения порядка платежей и поступлений. Убедитесь, что значения ваших платежей и поступлений введены в правильной последовательности.
Инвестиция, значение которой вычисляет функция NPV, начинается за один период до даты первой наличной операции (денежного взноса) и заканчивается последним значением наличной операции (денежного взноса) в массиве.
Вычисление чистого текущего значения вклада основывается на будущих наличных операциях (денежных взносах). Если ваш первый денежный взнос производится в начале первого периода, то первое значение следует добавить к значению, возвращаемому функций NPV, но не включать в список аргументов values().
Функция NPV аналогична функции PV (текущее значение), за исключением того, что функция PV допускает, чтобы денежные взносы производились либо в конце, либо в начале периода. В отличие от переменных значений денежных взносов в функции NPV, значения денежных взносов функции PV должны быть фиксированными в течение всего периода инвестиции.
Oct
Возвращает значение [тип Variant (String)], являющееся восьмеричным представлением числа..
Синтаксис
Oct(number)
Обязательный аргумент number — любое допустимое численное или строковое выражение.
Если аргумент number не является целым числом, его значение округляется до целого, а затем производится преобразование к восьмеричному представлению.
Функции в VBA
807
если number	функция Oct возвращает
Null	Null
Empty	Нуль (0)
Любое другое число	Восьмеричные цифры
Примеры
OctRep = Oct(4)	'	4
OctRep = Oct(9)	'	11
OctRep = Oct(459)	'	713
Partition
Возвращает значение [тип Variant (String)], показывающее диапазон (из серии диапазонов), внутри которого находится заданное число.
Синтаксис
Partition(number, start, stop, interval}
Функция Partition принимает следующие именованные аргументы:
аргумент	назначение
number	Обязательный. Целое число, которое необходимо оценить относительно диапазонов.
start	Обязательный. Целое число — начало всего диапазона чисел. Это число не может быть меньше нуля.
stop	Обязательный. Целое число — конец всего диапазона чисел. Это число не может быть равным или меньшим, чем start.
Каждый диапазон создается с использованием аргументов start, stop и interval.
Функцию Partition удобно использовать в запросах (queries). Вы можете создать select-запрос, который покажет, как много заказов попадает в различные диапазоны, например, значения заказов от 1 до 1000, от 1001 до 2000 и т.д.
Если любой из аргументов функции — Null, функция Partition возвращает Null.
Примеры
Var = Partition(3, 1, 20, 5)
Var = Partition(14, 1, 20, 5)
Var = Partition(14, 1, 20, 10)
'возвращает 1:5 'возвращает 11:15
'возвращает 11:20
Pmt
Возвращает значение типа Double. Вычисляет величину выплаты по ссуде на основе периодических, фиксированных платежей и фиксированной процентной ставки.
Синтаксис
₽mt(rate, nper, pv[, fv[, type]])
Именованные аргументы функции Pmt:
808
Приложение Г
аргумент	назначение
rate	Обязательный. Тип Double. Процентная ставка за период. Например, если вы получаете заем на покупку автомашины из расчета 10 процентов годовых (APR) и вносите ежемесячные платежи, ставка за период составляет 0.1/12, или 0.0083.
прег	Обязательный. Значение типа Integer. Общее число периодов выплат ежегодных поступлений (аннуитет). Например, если вы делаете ежемесячные выплаты по четырехлетнему займу, ваш заем имеет в сумме 4 * 12 (or 48) периодов выплат.
pv	Обязательный. Тип Double. Текущее значение (или общая сумма), которое составит ряд будущих платежей. Например, если вы берете в долг деньги для покупки автомашины, сумма займа является текущим значением для кредитора выплат, которые вы будете вносить.
fv	Необязательный. Тип Variant. Будущая сумма или баланс наличности, которого необходимо достичь, после того как вы внесете последний платеж. Например, будущее значение займа равно $0, потому что это его значение после последней выплаты. Однако если вы хотите накопить $50,000 в течение 18 лет на образование вашего ребенка, то будущей суммой является $50,000. Если опущен, то предполагается равным 0.
type	Необязательный. Тип Variant. Определяет, когда должна производиться выплата. Используется 0, если платеж должен производиться в конце периода, или 1, если платеж должен производиться в начале периода. Если опущен, предполагается равным 0.
Ежегодные поступления (annuity) — это ряд фиксированных наличных платежей, производимых в течение периода времени. Аннуитет может быть ссудой, такой как ипотека (home mortgage), или инвестицией, такой как план ежемесячных накоплений (monthly savings plan).
Аргументы rate и прег должны вычисляться с использованием периодов выплат, выраженных в одних и тех же единицах. Например, если, rate вычисляется с использованием месяцев, прег также должен вычисляться с использованием месяцев.
Для всех аргументов наличные выплаты, такие как депозиты и накопления, представляются отрицательными числами; наличные поступления, такие как дивиденды-чеки (dividend checks), представляются положительными числами.
PPmt	’
Возвращает значение типа Double. Величина основного платежа на данный период займа на основе периодических, фиксированных платежей и фиксированной процентной ставки.
Синтаксис
PPmt(rate, per, прег, pv[, fv[, type]])
Именованные аргументы функции PPmt:
Функции в VBA
809
аргумент	назначение
rate	Обязательный. Тип Double. Процентная ставка за период. Например, если вы получаете заем на покупку автомашины из расчета 10 процентов годовых (APR) и вносите ежемесячные платежи, ставка за период равна 0.1/12, или 0.0083.
per	Обязательный. Тип Integer. Задает период в интервале 1 - прег.
прег	Обязательный. Тип Integer. Это — общее число периодов выплат годовой ссуды. Например, если вы вносите ежемесячные платежи в счет погашения четырехлетней ссуды на автомашину, ваш заем имеет всего 4 * 12 (или 48) периодов платежей.
pv	Обязательный. Тип Double. Это — текущее значение или значение сегодня ряда будущих платежей или поступлений. Например, если вы берете заем для покупки автомашины, сумма займа является текущим значением для кредитора.
fv	Необязательный. Тип Variant. Это — будущая сумма или баланс наличности, которого необходимо достичь после того, как вы внесете последний платеж. Например, будущая сумма ссуды равна $0, таково ее значение после последнего платежа. Однако если вы хотите накопить $50,000 в течение 18 лет на образование вашего ребенка, то будущим значением является $50,000. Если опущен, предполагается равным 0.
type	Необязательный. Тип Variant, определяет, когда должен производиться платеж. Используется 0, если платеж должен производиться в конце периода, или используется 1, если делать выплату необходимо в начале периода. Если опущен, предполагается равным 0.
Ежегодные поступления (annuity) — это ряд фиксированных наличных платежей, производимых в течение периода времени. Аннуитет может быть ссудой, такой как ипотека (home mortgage), или инвестицией, такой как план ежемесячных накоплений (monthly savings plan).
Аргументы rate и прег должны вычисляться с использованием периодов выплат, выраженных в одних и тех же единицах. Например, если, rate вычисляется с использованием месяцев, прег также должен вычисляться с использованием месяцев.
Для всех аргументов наличные выплаты, такие как депозиты и накопления, представляются отрицательными числами; наличные поступления, такие как дивиденды-чеки (dividend checks), представляются положительными числами.
PV
Возвращает значение типа Double, определяющее текущий объем вклада (займа) на основе будущих периодических, фиксированных платежей и фиксированной процентной ставки.
Синтаксис
PV(rate, прег, pmt[, fv[, type]])
Именованные аргументы функции PV:
810
Приложение Г
аргумент	назначение
rate	Обязательный. Тип Double. Процентная ставка за период. Например, если вы получаете ссуду на покупку автомашины из расчета 10 процентов годовых (APR) и вносите ежемесячные платежи, то процентная ставка за период равна 0.1/12, или 0.0083.
nper	Обязательный. Тип Integer. Это — общее число периодов платежей годовой ссуды. Например, если вы вносите ежемесячные платежи в счет погашения четырехлетней ссуды, ваша ссуда имеет всего 4 * 12 (или 48) периодов.
pmt	Обязательный. Тип Double. Это — платеж, производимый в каждый период. Платежи обычно включают основные платежи и платежи по процентам, которые не изменяются за все время годовых поступлений.	।
fv	Необязательный. Тип Variant, обозначает будущее значение или наличный баланс, которого необходимо достичь после того, как будет внесен последний платеж. Например, будущая стоимость займа равна $0, потому что таково его значение после последней выплаты. Однако если вы хотите накопить $50,000 за 18 лет на образование вашего ребенка, то будущее значение равняется $50,000. Если опущен, предполагается равным 0.
type	Необязательный. Тип Variant, обозначает, когда должен производиться платеж. Используется 0, если платеж должен производиться в конце периода, или 1, если платеж должен производиться в начале периода. Если опущен, предполагается равным 0.
Ежегодные поступления (annuity) — это ряд фиксированных наличных платежей, производимых в течение периода времени. Аннуитет может быть ссудой, такой как ипотека (home mortgage), или инвестицией, такой как план ежемесячных накоплений (monthly savings plan).
Аргументы rate и nper должны вычисляться с использованием периодов выплат, выраженных в одних и тех же единицах. Например, если, rate вычисляется с использованием месяцев, nper также должен вычисляться с использованием месяцев.
Для всех аргументов наличные выплаты, такие как депозиты и накопления, представляются отрицательными числами; наличные поступления, такие как дивиденды-чеки (dividend checks), представляются положительными числами.
QBColor
Возвращает значение (тип Long) кода RGB-цвета.
Синтаксис
QBColor(color)
Обязательный аргумент color — целое число в диапазоне 0-15:
ЧИСЛО	цвет	число	цвет	।
0	Black (черный)	8	Gray (серый)
1	Blue(Голубой)	9	Light Blue (светло голубой)
2	Green (зеленый)	10	Light Green
Функции в VBA
811
ЧИСЛО	цвет	ЧИСЛО	цвет
3	Cyan (бирюзовый)	11	Light .Cyan
4	Red (красный)	12	Light Red
5	Magenta (малиновый)	13	Light Magenta
6	Yellow (желтый)	14	Light Yellow
7	White (белый)	15	Bright White
Аргумент color представляет значение цвета, используемого ранними версиями системы Basic (такими как Microsoft Visual Basic for MS-DOS и Basic Compiler). Начиная с младшего значащего байта, возвращаемое значение определяет red-, green- и blue-значения, используемые для установки соответствующего цвета в RGB-системе для Visual Basic for Applications.
Примеры
Sub ChangeBackColor (IntColorCode As Integer, FormMy As Form) FormMy.BackColor = QBColor (IntColorCode)
End Sub
Процедура в этом примере позволяет менять свойство формы BackColor. Имя формы (как и код цвета) передается как параметр.
Rate
Возвращает значение типа Double, определяющее процентную ставку за период при выплате годовых поступлений (annuity).
Синтаксис
Rate(прег, pmt, pv[, fv[, type], guess]]])
Полное описание аргументов прег, pmt, pv, fv и type см. в справке по функции PV.
Именованные аргументы функции Rate :
аргумент	назначение
прег	Обязательный. Значение типа Double, обозначает общее число периодов выплат годовых поступлений. Например, если вы вносите ежемесячные платежи по четырехлетнему займу на покупку автомашины, то ваш заем имеет всего 4 * 12 (или 48) периодов платежей.
pmt	Обязательный. Тип Double. Это — платеж, вносимый в каждый период. Платежи обычно состоят из основного платежа и платежа по процентам и не меняются в течение всего периода выплат.
pv	Обязательный. Тип Double. Это — текущее значение или сумма сегодня ряда будущих платежей или поступлений. Например, когда вы берете заем для покупки автомашины, сумма займа является настоящим значением для кредитора.
fv	Необязательный. Тип Variant. Это — будущее значение или баланс наличности, которого необходимо достичь после последнего платежа. Например, будущее значение для займа равняется $0. Если аргумент fv опущен, то он предполагается равным 0.
812
Приложение Г
аргумент	назначение
type	Необязательный. Тип Variant. Число 0, если платеж должен производиться в конце периода, или 1, если платеж должен производиться в начале периода. Если аргумент опущен, он предполагается равным 0.
guess	Необязательный. Тип Variant. Это — предполагаемая величина нормы, возвращаемая функцией Rate. Если аргумент guess опущен, то он предполагается равным 0.1 (10 процентам).
Ежегодные поступления (annuity) — это ряд фиксированных наличных платежей, производимых в течение периода времени. Аннуитет может быть ссудой, такой как ипотека (home mortgage), или инвестицией, такой как план ежемесячных накоплений (monthly savings plan).
Для всех аргументов наличные выплаты, такие как депозиты и накопления, представляются отрицательными числами; наличные поступления, такие как дивиденды-чеки (dividend checks), представляются положительными числами.
Rate вычисляется методом последовательного приближения и может не иметь решения или иметь несколько решений. Начиная со значения guess, функция Rate выполняет циклически вычисления до тех пор, пока результат не будет в пределах 0.00001 процента. Если после 20 итераций Rate не может найти результат, функция заканчивается неуспешно. Если ваше значение guess равно 10 процентам и функция Rate заканчивается неуспешно, попробуйте использовать другие значения для guess.
Replace
Возвращает строку, в которой определенная подстрока заменена на другую подстроку указанное число раз.
Синтаксис
Replace(expression, find, replace[, start[, count[, compare]]])
Функция Replace принимает следующие именованные аргументы:
аргумент	назначение
expression	Обязательный. Строковое выражение, содержащее подстроку для замены.
find	Обязательный. Подстрока, которую необходимо найти.
replace	Обязательный. Строка для замены.
start	Необязательный. Позиция внутри expression, с которой начинается поиск подстроки. Если опускается, используется значение 1.
count	Необязательный. Необходимое число подстановок подстроки. Если опускается, по умолчанию используется число -1, означающее выполнение всех возможных подстановок.
compare	Необязательный. Числовое значение, определяющее тип сравнения. См. следующую таблицу.
Функции в VBA
813
Аргумент compare может принимать следующие значения:
константа	значение	описание
vbUseCompareOption	-1	Выполнять сравнение с использованием установки оператора Option Compare.
vbBinaryCompare	0	Выполнять двоичное сравнение.
vbTextCompare	1	Выполнять текстовое сравнение.
vbDatabaseCompare	2	Только для Microsoft Access. Выполнять сравнение, основываясь на информации в некоторой базе данных.
Функция Replace возвращает следующие значения:
если	функция Replace возвращает
expression — нулевой длины	Строку нулевой длины ("").
expression — Null	Ошибку.
find — нулевой длины	Копию строки expression.
replace — нулевой длины	Копию строки expression со всеми удалениями строки find.
start > Len(expression)	Строку нулевой длины.
count — 0	Копию строки expression.
Возвращаемое значение функции Replace — строка с выполненными подстановками.
Пример
vexpression = "Привет всем, кто добрый, и ничего всем, кто не добрый" vFind = "добрый" vReplace = "хороший" 'замена всех слов "добрый" на слово "хороший": MsgBox Replace(vexpression, vFind, vReplace) vReplace = "" 'удаление всех слов "добрый" MsgBox Replace(vexpression, vFind, vReplace)
RGB
Возвращает целое число (тип Long), представляющее значение RGB-цвета. Синтаксис RGB(red, green, blue)
Функция RGB принимает следующие именованные аргументы:
аргумент	назначение
red	Обязательный; тип Variant (Integer). Число в диапазоне 0-255, включительно, которое представляет красную (red) компоненту цвета.
green	Обязательный; тип Variant (Integer). Число в диапазоне 0-255, включительно, которое представляет зеленую (green) компоненту цвета.
814
Приложение Г
аргумент	назначение
blue	Обязательный; Variant (Integer). Число в диапазоне 0-255, включительно, которое представляет голубую (blue) компоненту цвета.
Значение RGB-цвета определяет относительную интенсивность красного, зеленого и голубого для получения необходимого цвета, который будет отображаться на экране.
Если значение некоторого аргумента функции RGB превышает 255, оно заменяется на значение 255.
В следующей таблице приведены стандартные цвета и соответствующие им значения красного, зеленого и голубого цветов.
цвет	Red-значение	Green-значение	Blue-значение
Black	0	0	0
Blue	0	0	255
Green	0	255	0
Cyan	0	255	255
Red	255	0	0
I Magenta	255	0	255
Yellow	255	255	0
White	255	255	255
Значения RGB-цветов, возвращаемых функцией, совместимы с используемыми в операционной системе Macintosh. Они могут использоваться в контексте Microsoft-приложения для Macintosh, но не могут применяться, когда взаимодействующие цвета меняются непосредственно для операционной системы Macintosh.
Right
Возвращает строку [тип Variant (String)], содержащую определенное количество символов правой части указанной строки.
Синтаксис
Right(string, length}
Функция Right принимает следующие именованные аргументы:
аргумент	назначение
string	Обязательный. Строковое выражение, из правой части которого возвращаются символы. Если string содержит Null, функция возвращает Null.
length	Обязательный; тип Variant (Long). Численное выражение, указывающее число возвращаемых символов. Если этот аргумент равен значению 0, функция возвращает строку нулевой длины (""). Если length содержит значение, равное или большее, чем длина строки, возвращается вся строка.
Для определения длины строки (аргумента string) следует использовать функцию Len.
Функции в VBA
815
Примеры
В этом примере используется функция Right для возвращения указанного числа символов от правого конца строки.
Dim StringAny, StrRez
StringAny = "Hello World"
StrRez = Right(StringAny, 1)	' возвращает "d"
StrRez = Right(StringAny, 6)	'возвращает " World”
StrRez = Right(StringAny, 20)	'возвращает "Hello World"
Rnd
Возвращает значение (тип Single), содержащее случайное число.
Синтаксис
Rnd[(number) ]
Необязательный аргумент (тип Single) number — любое допустимое числовое выражение.
Возвращаемые значения функции:
если number	функция Rnd возвращает
меньше нуля	Одно и то же число каждый раз, используя number для инициализации генератора случайных чисел.
больше нуля	Следующее случайное число в последовательности случайных чисел.
равно нулю	Самое последнее сгенерированное число.	।
) не используется	Следующее случайное число в последовательности случай- | ных чисел.	1
Функция Rnd возвращает значение, меньшее 1, большее или равное 0. Значение аргумента number определяет способ генерации функцией случайного числа: для любого заданного числа-инициализатора последовательности случайных чисел (seed) генерируется одна и та же последовательность, поскольку каждый последующий вызов функции Rnd использует предыдущее число как инициализатор для генерации следующего случайного числа. Перед вызовом функции Rnd следует использовать оператор Randomize (см. Приложение Д) без аргументов для инициализации генератора случайных чисел, использующего системное время в качестве числа-инициализатора.
Иногда бывает необходимо получать последовательность случайных чисел в некотором числовом диапазоне. Для этого можно использовать следующую формулу:
Int((upperbound - lowerbound +1) * Rnd + lowerbound)
Здесь upperbound — наибольшее число диапазона, lowerbound — наименьшее число диапазона.
Примеры
Dim MyValue, MyString As String
Randomize
MyString = "" For I = 0 To 9 MyValue = Int ((6 * Rnd) + 1) MyString = MyString & " " & MyValue Next
816
Приложение Г
Приведенный код генерирует строку из случайных чисел в диапазоне от 1 до 6. Результатом работы этого кода могут быть, например, следующие строки:
"1526555554 1";	"5613546143"
Round
Возвращает число, округленное до определенного количества десятичных знаков.
Синтаксис
Round(expression [,numdecimalplaces])
Функция Round принимает следующие аргументы:
аргумент	назначение
expression	Обязательный. Численное выражение, которое округляется.
numdecimalplaces	Необязательный. Число, указывающее, до скольки десятичных знаков (справа от десятичной точки) следует выполнять округление. Если этот аргумент опускается, функция Round возвращает целое число.
Rtrim
Функция возвращает значение [тип Variant (String)], содержащее копию указанной строки без конечных (trailing) пробелов.
Синтаксис
RTrim(string)
Обязательный аргумент string — любое допустимое строковое выражение. Если аргумент содержит Null, функция возвращает Null.
Second
Возвращает значение [тип Variant (Integer)], определяющее целое число между 0 и 59, включительно, представляющее секунды в минуте.
Синтаксис	'
Second(time)
Обязательный аргумент time — любое Variant-, численное, строковое выражение или любая их комбинация, которое представляет время. Если аргумент time содержит Null, функция также возвращает Null.
Пример
Timel = #3:45:20 PM#
MySecond = Second (Timel)	1 переменная получает значение 20
Seek
Возращает значение (тип Long), определяющее текущую позицию чтения/за-писи в файле, открытом с использованием оператора Open.
Функции в VBA
817
Синтаксис
Seek(flienumber)
Обязательный аргумент filenumber — допустимый файловый номер (тип Integer).
Функция Seek возвращает значения между 1 и 2147483647 (что эквивалентно 231 - 1), включительно.
В следующей таблице описаны возвращаемые значения для каждого режима файлового доступа.
режим	возвращаемое значение
Random	Номер следующей записи (record) для чтения или записи.
Binary, Output, Append, Input	Позиция байта, для которой имеет место следующая операция. Первый байт в файле имеет позицию 1, второй байт — позицию 2 и т.д. ___________		
Sgn
Возвращает значение [тип Variant (Integer)], указывающее знак числа.
Синтаксис
Sgn(number)
Обязательный аргумент number может быть любым допустимым численным выражением.
Возвращаемые значения
если number	функция возвращает
больше нуля	1
равно нулю	0
меньше нуля	-1
Обратите внимание: знак аргумента определяет знак возвращаемого значения функции.
Shell
Запускает исполняемую программу и возвращает значение [тип Variant (Double)], представляющее ID-задачи, если запуск выполнен успешно, или нуль — в противном случае.
Синтаксис
Shell(pathname[,windowstyle])
Функция Shell принимает следующие именованные аргументы:
27 Программирование на VBA 2002
818
Приложение Г
аргумент	назначение
pathname	Обязательный; тип Variant (String). Наименование (имя) программы, которую следует запустить, и необходимые аргументы и ключи; можно включать каталог или папку и драйвер диска. На Macintosh можно использовать функцию MacID для определения сигнатуры приложения вместо его имени. Например, так на Macintosh можно с помощью сигнатуры запустить Microsoft Word: Shell MacID(«MSWD»)
windowstyle	Необязательный; тип Variant (Integer); соответствует стилю окна, в котором запускается приложение. Если аргумент windowstyle опускается, программа «стартует» минимизированной (если такое состояние в ней предусмотрено) с фокусом. На Macintosh (System 7.0 и более поздняя) аргумент windowstyle определяет, получает ли запускаемое приложение фокус.
Аргумент windowstyle может иметь следующие значения:
константа	значение	описание
vbHide	0	Окно скрыто, фокус передается на скрытое окно. На платформе Macintosh эта константа не используется.	|
vbNormalFocus	1	Окно имеет фокус и восстановлено до оригинальных размеров и положения на экране.
vbMinimizedFocus	2	Окно отображается как значок с фокусом.
vbMaximizedFocus	3	Окно максимизировано и с фокусом.
vbNormalNoFocus	4	Окно восстановлено к его предыдущим размерам и положению на экране. Текущее активное окно остается быть активным.
vbMinimizedN oFocus	6	Окно отображается как значок. Текущее активное окно остается быть активным.
Если функция Shell успешно запускает исполняемый файл, она возвращает ID запущенной программы — уникальный номер, который идентифицирует выполняемую программу. Если функция Shell не может запустить программу, возникает ошибка.
По умолчанию функция Shell запускает другие программы асинхронно. Это означает, что программа, запущенная этой функцией, не должна завершаться перед той, из которой была выполнена функция Shell.
Пример
Так, например, можно запустить Windows-программу «Лазерный проигрыватель» (переменная ReVai может получить при этом значение, например, -532327):
ReVai = Shell("С:\WINDOWS\cdplayer.EXE", vbNormalFocus)
Sin
Возвращает значение (тип Double) синуса угла (в диапазоне от -1 до 1).
Синтаксис
Sin(number)	:
Функции в VBA
819
Обязательный аргумент number — Double- или любое численное выражение, которое представляет значение угла в радианах.
SLN
Возвращает значение типа Double, обозначающее величину непосредственной амортизации имущества за один период.
Синтаксис SLN(cost, salvage, life) Именованные аргументы функции SLN:
аргумент	назначение
cost	Обязательный. Тип Double, обозначает начальную стоимость имущества.
salvage	Обязательный. Тип Double. Это — стоимость имущества в конце периода амортизации.
life	Обязательный. Тип Double. Это — продолжительность периода использования (амортизации).
Замечания
Период снижения стоимости (depreciation period ) должен выражаться в одних и тех же единицах, что и аргумент life. Все аргументы должны быть положительными числами.
Space
Возвращает строку [тип Variant (String)], содержащую указанное количество пробелов.
Синтаксис
Space(number)
Обязательный аргумент number — это необходимое количество пробелов в возвращаемой строке.
Функция Space полезна при форматировании выходных данных и очистке строк фиксированной длины.
Пример	1
MsgBox = "ПрЮвет"4 Space(5) & "зайцу1"
Spc
Используется с оператором Print # или методом Print (в окне Immediate) для позиционирования выходных данных.
Синтаксис	'
Spc(n)
Обязательный аргумент п — это количество пробелов для вставки перед следующим отображаемым на экране или печатаемым выражением в списке.
820
Приложение Г
Если п меньше, чем ширина выходной строки, информация выводится сразу за указанным количеством пробелов. Если п больше, чем ширина выходной строки, функция Spc вычисляет следующую позицию для печати, используя формулу:
текущая_позиция + (п Mod ширина)
Например, если текущая позиция для печати — 25, ширина выходной строки длина — 75, и вы определяете Spc(90), выдача данных начнется с позиции (текущая позиция + остаток от 90/75). Если разность между текущей позицией и шириной выходной строки меньше, чем п (или п Mod ширина), функция Spc выполняет переход к началу следующей строки и генерирует число пробелов, равное п - (ширина - текущая_позиция).
При использовании метода с пропорциональным шрифтом ширина символов пробела с использованием функции Spc — это всегда среднее значение ширины всех символов для выбранного шрифта. Однако нет никакой связи между числом печатаемых символов и количеством колонок фиксированной ширины, которые эти символы занимают. Например, символ W занимает больше места, чем колонка фиксированной ширины, а символ 1 — меньше.
Split
Возвращает одномерный массив (индексируемый с нуля), содержащий определенное число подстрок.
Синтаксис
Split(expression[, delimiter!, limit!, compare]]))
Функция Split принимает следующие именованные аргументы:
аргумент	назначение
expression	Обязательный. Строковое выражение, содержащее подстроки и ограничители. Если expression — строка нулевой длины (""), функция Split возвращает пустой массив, не содержащий ни элементов, ни данных.
delimiter	Необязательный. Строковый символ, используемый в качестве разделителя подстрок. Если этот аргумент не указан, в качестве разделителя используется символ пробела. Если delimiter — строка нулевой длины, функция возвращает массив из одного элемента, содержащего всю строку, заданную аргументом expression.
limit	Необязательный. Число возвращаемых подстрок.; -1 указывает на необходимость вернуть все подстроки.
compare	Необязательный. Числовое значение, определяющее тип сравнения при оценке подстрок. (См. следующую таблицу.)
Аргумент compare может иметь следующие значения:
константа	значение	описание
vbUseCompareOption	-1	Выполнять сравнение с использованием настройки оператора Option Compare.
vbBinaryCompare	0	Выполнять бинарное сравнение.	I
vbTextCompare	1	Выполнять текстовое сравнение.
vbDatabaseCompare	2	Только для Microsoft Access. Выполнять сравнение, основанное на информации базы данных.
Функции в VBA
821
Возвращает значение (тип Double), определяющее корень квадратный из числа-аргумента.
Синтаксис
Sqr(number)
Обязательный аргумент number — Double- или любое допустимое числовое выражение, большее или равное нулю.
Пример
Sqr3 =	Sqr(O)	'возвращает	О
Sqrl =	Sqr(9)	'возвращает	3
Sqr2 =	Sqr(23)	'возвращает	4.79583152331272
Sqr4 =	Sqr(-9)	'генерируется	ошибка	времени исполнения
Str
Возвращает строку [тип Variant (String)], представляющую число.
Синтаксис
Str(number)
Обязательный аргумент number — значение (тип Long ), содержащее любое допустимое числовое выражение. При преобразовании числа в строку всегда резервируется ведущий пробел для знака числа. Если number — положительное число, возвращается строка с ведущим пробелом.
Для преобразования числовых значений в форматированные строки (в даты, время, валюты и т.д.) следует использовать функцию Format, которая в отличие от Str не включает в строку ведущий пробел для знака числа.
Примеры MyString = Str(975) MyString = Str(-449.63) MyString = Str(479.011)	'возвращает строку " 975" 'возвращает строку "-449.63" 'возвращает строку " 479.011"
StrComp
Возвращает значение [тип Variant (Integer)] с результатом строкового сравнения.
Синтаксис	,
StrComp(stringl, string2[, compare]) Функция StrComp принимает следующие именованные аргументы:
аргумент	назначение
stringl	Обязательный. Любое допустимое строковое выражение.
string2	Обязательный. Любое допустимое строковое выражение.
compare	Необязательный. Определяет тип строкового сравнения. Если compare — Null, генерируется ошибка. Если compare не указывается, тип сравнения определяется настройкой оператора Option Compare.
822
Приложение Г
Аргумент compare может принимать следующие значения:
константа	значение	описание
vbUseCompareOption	-1	Выполнять сравнение с использованием настройки оператора Option Compare.
vbBinaryCompare	0	Выполнять бинарное сравнение.
vbTextCompare	1	Выполнять текстовое сравнение.
vbDatabaseCompare	2	Только для Microsoft Access. Выполнять сравнение, основанное на информации базы данных.
Возвращаемые значения
Функция StrComp возвращает следующие значения:
если	StrComp возвращает
stringl меньше, чем string2	-1
stringl эквивалентна string2	0
stringl больше, чем string2	1
stringl или string2 — Null	Null
Примеры
Dim Strl, Str2, RezComp
Strl = "BCDF"
Str2 = "bcdf"
RezComp =	StrComp(Str2,	Strl)	'	1
RezComp =	StrComp(Strl,	Str2,	1)	'	0
RezComp =	StrComp(Strl,	Str2,	0)	'	-1
StrConv
Возвращает значение [тип Variant (String)], конвертированное указанным способом.
Синтаксис
StrConv(string, conversion, LCID)
Функция StrConv принимает следующие именованные аргументы:
аргумент	назначение
String	Обязательный. Конвертируемое строковое выражение.
Conversion	Обязательный. Тип Integer. Суммарное значение, определяющее тип преобразования.
LCID	Необязательный. LocalelD, если отличается от системного LocalelD (по умолчанию).
Аргумент conversion может принимать следующие значения:
константа	значение	описание
vbUpperCase	1	Конвертировать строку в символы верхнего регистра.
Функции в VBA
823
константа	значение	описание
vbLowerCase	2	Конвертировать строку в символы нижнего регистра.
vbProperCase	3	Конвертирует первый символ каждого слова строки в символ верхнего регистра.
vbUnicode	64	Конвертирует строку в Unicode, используя кодовую страницу системы по умолчанию (Не для Macintosh).
vbFrom-Unicode	128	Конвертирует строку из Unicode в кодовую страницу системы по умолчанию (Не для Macintosh).
StrReverse
Возвращает строку с обратным порядком символов по сравнению с оригинальной строкой.
Синтаксис
StrReverse(expression)
Аргумент expression. — строка, символы которой должны изменить порядок следования. Если expression является строкой нулевой длины («»), функция также возвращает строку нулевой длины. Если expression — Null, возникает ошибка.
String
Возвращает строку [тип Variant (String)], содержащую определенной длины строку повторяющихся символов.
Синтаксис
String(number, character)
Функция String принимает следующие именованные аргументы:
аргумент	назначение
number	Обязательный; тип Long. Длина возвращаемой строки. Если number содержит Null, функция также возвращает Null.
character	Обязательный; тип Variant. Код символа или строковое выражение, первый символ которого используется для построения возвращаемой строки. Если character содержит Null, функция возвращает Null.
Если character содержит код, больший чем 255, функция String предварительно преобразует это значение в следующей формуле:
character Mod 256
Примеры
Stringl =	String (5,	"*")	' String2 =	String(5,	42)	' String3 =	String(10, "BCd")' String4 =	String (5,	299)	'	возвращает "*****" возвращает возвращает "AAAAAAAAAA" возвращает "+++++"
824
Приложение Г
Switch	*
Оценивает список выражений и возвращает значение (тип Variant) или выражение, связанное с первым выражением в списке, равным значению True.
Синтаксис
Switch(expr-1, value-l[, expr-2, value-2 [, expr-n,value-n]])
Функция Switch принимает следующие аргументы
аргумент	назначение
ехрг	Обязательный. Variant-выражение, которое необходимо оценить.
value	Обязательный. Значение или выражение, которое возвращается, если соответствующее выражение равно значению True.
Список аргументов функции Switch содержит пары выражений и значений. Выражения оцениваются слева направо, и значение, соответствующее первому выражению, которое оценивается как True, возвращается.
Функция Switch возвращает Null, если ни одно из выражений не равно значению True или если первое из выражений, равное значению True, имеет соответствующее ему значение Null.
SYD
Возвращает значение годовой амортизации активов за определенный период.
Синтаксис
SYD(cost, salvage, life, period}
Функция SYD имеет следующие (все обязательные, тип Double) именованные аргументы:
аргумент	назначение
cost	Начальная стоимость имущества.
salvage	Остаточная стоимость имущества в конце периода амортизации (useful life).
life	Время эксплуатации (период амортизации).
period	Период, за который вычисляется амортизация.
Аргументы life и period должны выражаться в одних и тех же единицах, например, если life задается в месяцах, то и period также должен быть задан в месяцах. Все аргументы должны быть положительными числами.
Tab
Используется с оператором (statement) Print # или методом Print для позиционирования выходных данных.
Синтаксис	’	,
ТаЬ[(п)]
Функции в VBA
825
Необязательный аргумент п — число колонок, на которые необходимо сместить начало вывода информации на экране или принтере. Если аргумент отсутствует, функция Tab перемещает курсор вставки в начало следующей зоны печати. Это позволяет использовать функцию Tab вместо запятой там, где запятая применяется как десятичный разделитель.
Если текущая позиция печати на текущей строке больше, чем п, функция Tab пропускает n-ую колонку на* следующей строке вывода. Если п меньше, чем 1, функция Tab продвигает позицию печати к первой колонке. Если значение аргумента п больше, чем ширина выходной строки, следующая позиция печати вычисляется по формуле:
п Mod width
Tan
Возвращает значение (тип Double) тангенса угла.
Синтаксис
Tan(number)
Обязательный аргумент number — Double- или любое допустимое числовое выражение, которое представляет значение угла в радианах.
Примеры
Angle = 1.-3	' значение угла в радианах
Cotangent = 1 / Tan(Angle) ' значение котангенса	,
Time
Возвращает значение [тип Variant (Date)] системного времени.
Синтаксис
Time	1
Пример
TimeSystem = Time ' возвращает системное время
Timer
Возвращает значение (тип Single), представляющее число секунд, прошедших с начала суток.
Синтаксис
Timer
В Microsoft Windows функция Timer возвращает дробные части секунд.
TimeSerial
Возвращает значение [тип Variant (Date)], содержащее время для указанных часа, минут и секунд.
Синтаксис
TimeSerial(hour, minute, second)
Функция TimeSerial принимает следующие именованные аргументы:
826
Приложение Г
аргумент	назначение
hour	Обязательный; тип Variant (Integer). Число между 0 (12:00 А.М.) и 23 (11:00 Р.М.), включительно, или числовое выражение.
minute	Обязательный; тип Variant (Integer). Любое числовое выражение в диапазоне от 0 до 59, включительно.
second	Обязательный; тип Variant (Integer). Любое числовое выражение в диапазоне от 0 до 59, включительно.
Примеры
Timel = TimeSerial(1, 30, 17) 'значение для Timel 10:30:17
TimeValue
Возвращает значение [тип Variant (Date)], содержащее время.
Синтаксис
TimeValue(time)
Обязательный аргумент time — это обычно строковое выражение, представляющее время от 0:00:00 (12:00:00 А.М.) до 23:59:59 (11:59:59 Р.М.), включительно. Если time содержит Null, функция возвращает Null.
Примеры
Msg = "Московское время: " S TimeValue("5:30:17 РМ")
В этом примере переменная Msg получает значение ‘Московское время: 17:30:17’.
Trim
Функция возвращает значение [тип Variant (String)], содержащее копию указанной строки без ведущих и конечных пробелов.
Синтаксис
Trim(string)
Обязательный аргумент string — любое допустимое строковое выражение. Если аргумент содержит Null, функция возвращает Null.
TypeName
Возвращает Строку (тип String), которая содержит информацию о типе переменной.
Синтаксис
TypeName(varname)
Обязательный аргумент varname — имя переменной.
Строка, содержащая возвращаемое функцией TypeName, может иметь следующее значение:
возвращаемая строка	переменная
object type	Объект с типом objecttype
Byte	Байтовое значение
Функции в VBA
827
возвращаемая строка	переменная
Integer	Целое
Long	Длинное целое
Single	Число с плавающей запятой одинарной точности
Double	Число с плавающей запятой двойной точности
Currency	Значение валюты
Decimal	Десятичное значение
Date	Значение даты
String	Строка
Boolean	Логическое значение
Error	Значение ошибки
Empty	Неинициализированная переменная
Null	Нет допустимых данных
Object	Объект
Unknown	Объект с неизвестным типом
Nothing	Объектная переменная, которая не ссылается на объект
Если varname — массив, функция возвращает строку с типом элементов массива и двумя круглыми скобками.
Примеры
Dim NullVar, VarType
Dim StrVar As String
Dim IntVar As Integer
Dim CurVar As Currency
Dim IntArray (1 To 25) As Integer
NullVar =	Null
VarType =	TypeName(StrVar)	'	возвращает
VarType =	TypeName(IntVar)	'	возвращает
VarType =	TypeName(CurVar)	'	возвращает
VarType =	TypeName(IntArray)	'	возвращает
VarType =	TypeName(NullVar)	1	возвращает
"String"
"Integer" "Currency” "Integer()" "Null"
UBound
Возвращает значение (тип Long), содержащее наибольшее значение индекса для указанной размерности массива.
Синтаксис
UBound(arrayname[, dimension])
Функция UBound имеет следующие аргументы:
аргумент	назначение
аггаупате	Обязательный. Имя переменной-масива.
dimension	Необязательный; Тип Variant (Long). Целое число, указывающее размерность, для которой определяется верхняя граница индекса. Для первой размерности используется число 1, для второй — 2 и т.д. Если аргумент не указывается, по умолчанию используется значение 1.	|
828
Приложение Г
Функция UBound обычно используется с функцией LBound для определения размера массива, поскольку LBound позволяет найти наименьшее значение индекса указанной размерности.
Примеры
Dim IntArray(1 То 12, 5 То	17,	10 To 20)	' Declare array variables
Dim DouArray(13) IntUpper = UBound(DouArray)		* возвращает	13
IntUpper = UBound(IntArray,	1)	’возвращает	12
IntUpper = UBound(IntArray,	2)	’возвращает	17
UCase
Возвращает значение [тип Variant (String)], содержащее заданную строку, символы которой преобразованы к верхнему регистру.
Синтаксис
UCase(string)
Обязательный аргумент string — любое допустимое строковое выражение. Если string содержит Null, функция возвращает Null.
Примеры
Dim LowerCase, Uppercase
StringLowerCase = "Hello World!"
'Следующий оператор возвращает строку 'HELLO WORLD!'
StringUpperCase = UCase(StringowerCase)
Vai
Возвращает число, содержащееся в строке.
Синтаксис
Vai(string)
Обязательный аргумент string — любое допустимое строковое выражение.
Функция Vai прекращает чтение строки на первом символе, который не распознается как часть символа. Такие символы, как символ доллара, запятая, не распознаются. Однако функция распознает символы основания системы счисления &0 (для восьмеричной) и &Н (для шестнадцатиричной). Пробелы, знаки табуляции отсекаются.
Примеры
IntValue =	Vai("9459")	'	возвращается	9459
IntValue -	Val(" 9 45 9")	'	возвращается	9459
IntValue =	Vai("124 and 537")	'	возвращается	24
VarType
Возвращает целое, указывающее подтип переменной.
Синтаксис
VarType (varname)
Обязательный аргумент varname — значение (тип Variant), содержащее любую переменную, исключая переменные типов, определенных пользователем.
Функции в VBA
829
Возвращаемые значения
константа	значение	описание
vbEmpty	0	Empty (не инициализирована)
vbNull	1	Null (недопустимые данные)
vblnteger	2	Целое
vbLong	3	Длинное целое
vbSingle	4	С плавающей точкой одинарной точности
vbDouble	5	С плавающей точкой двойной точности
vbCurrency	6	Значение валюты
vbDate	7	Значение даты
vbString	8	Строка
vbObject	9	Объект
vbError	10	Значение ошибки
vbBoolean	11	Логическое значение
vbVariant	12	Variant (используется только с variant-массивами)
vbDataObject	13	Объект для доступа к данным
vbDecimal	14	Десятичное значение
vbByte	17	Байтовое значение
vbUserDefinedType	36	Variant-данные пользовательского типа
vbArray	8192	Массив
Функция VarType никогда не возвращает значение для vbArray «само по себе». Оно всегда добавляется к некоторому другому значению для указания на массив определенного типа. Константа vbVariant возвращается только в конъюнкции с vbArray для индикации того, что аргумент функции VarType является массивом типа Variant.
Примеры
IntVar = 159
DateVar = #2/11/73#
StrVar = "Random number generator"
MyRez =	VarType(IntVar)	'	возвращает	2	(vblnteger)
MyRez =	VarType(DateVar)	'	возвращает	7	(vbDate)
MyRez =	VarType(StrVar)	'	возвращает	8	(vbString)
Weekday
Возвращает значение типа Variant (Integer), являющееся частью аргумента (типа Date) и содержащее день недели.
Синтаксис
Weekday(date, !firstdayofweek])
Функция Weekday принимает следующие именованные аргументы:
830
Приложение Г
аргумент	назначение
date	Обязательный. Тип Variant. Численное, строковое выражение или их комбинация, представляющая дату. Если date содержит Null, функция возвращает Null.
firstdayofweek	Необязательный. Константа, которая задает первый день недели; если не указан, по умолчанию используется vbSunday или vbMonday (в зависимости от национальных настроек).
В качестве аргумента firstdayofweek следует использовать следующие константы:
константа	значение	назначение
vbUseSystem	0	Использовать настройки NLS API.
vbSunday	1	Sunday
vbMonday	2	Monday
vbTuesday	3	Tuesday
vb Wednesday	4	Wednesday
vbThursday	5	Thursday
vbFriday	6	Friday
vbSaturday	7	Saturday
Функция Weekday возвращает следующие значения:
константа	значение	назначение
vbSunday	1	Sunday
vbMonday	2	Monday
vbTuesday	3	Tuesday
vbWednesday	4	Wednesday
vbThursday	5	Thursday
vbFriday	6	Friday
vbSaturday	7	Saturday
Результат функции зависит от значения свойства Calendar.
Пример
My_Date = #February 13, 1969#
My_Week_Day = Weekday(My_Date) ' My_Week_Day содержит 5
WeekdayName
Возвращает строку с наименованием дня недели, используя номер дня недели. Синтаксис WeekdayName(weekday, abbreviate, firstdayofweek)
Функция WeekdayName-принимает следующие аргументы:
Функции в VBA
831
аргумент	назначение
weekday	Обязательный. Числовое обозначение дня недели. Численное значение каждого дня недели зависит от значения firstdayofweek.
abbreviate	Необязательный. Тип Boolean. Указывает на необходимость использовать сокращенное название дня недели. По умолчанию — False, что означает использовать полное название.
firstdayofweek	Необязательный. Численное значение, определяющее первый день недели.
Аргумент firstdayofweek может принимать следующие значения:
константа	значение	назначение
vbUseSystem	0	Использовать национальные языковые [National Language Support (NLS)] API-настройки.
vbSunday	1	Sunday (Воскресенье)
vbMonday	2	Monday (Понедельник)
vbTuesday	3	Tuesday (Вторник)
vbWednesday	4	Wednesday (Среда)
vbThursday	5	Thursday (Четверг)
vbFriday	6	Friday (Пятница)
vbSaturday	7	Saturday (Суббота)
Пример
MsgBox	WeekdayName(2)	' в	диалоговом	окне —	"Вторник
MsgBox	WeekdayName(2, True)	' в	диалоговом	окне —	"Вт"
MsgBox	WeekdayName(2, True, vbSunday)	' в	диалоговом	окне —	"Пн"
Year
Возвращает значение типа Variant (Integer), являющееся частью аргумента (типа Date) и содержащее год.
Синтаксис
Year(date)	.
Обязательный аргумент date — любое выражение (Variant, численное, строковое или любая комбинация), представляющее дату. Если аргумент If date содержит Null, функция возвратит Null. Результат функции зависит от значения свойства Calendar.
Пример
Dim My_Date, My_Year
My_Date = #February 11, 1960#
My_Year = Year(My_Date)	' My_Year содержит 1960
Приложение Д
Константы в VBA
В этом приложении приведены все константы, которые можете использовать в своих программах. Данная информация предназначена для разработчиков VBA-приложений.
Календарные (Calendar) константы
Константа	Значение	Описание
vbCalGreg	0	Указывает на использование Григорианского календаря.
vbCalHijri	1	Указывает на использование Юлианского календаря.
Константы типов вызова (CallType)
Константа	Значение	Описание
vbMethod	1	Указывает на используемый метод.
vbGet	2	Указывает на процедуру Property Get.
vbLet	4	Указывает на процедуру Property Let.
vbSet	8	Указывает на процедуру Property Set.
Константы цветовые (Color)
Константа	Значение	Описание
vbBlack	0x0	Черный (Black)
vbRed	OxFF	Красный (Red)
vb Green	OxFFOO	Зеленый (Green)
vbYellow	OxFFFF	Желтый (Yellow)
vbBlue	OxFFOOOO	Голубой (Blue)
vbMagenta	OxFFOOFF	Малиновый (Magenta)
vbCyan	OxFFFFOO	Бирюзовый (Cyan)
vb White	OxFFFFFF	Белый (White)
Константы в VBA
833
Константы типов сравнений (Comparison)
Константа	Значение	Описание
vbU seCompareOption	-1	Выполняется сравнение, использующее установки оператора Option Compare.
vbBinaryCompare	0	Выполняется бинарное сравнение.
vbTextCompare	1	Выполняется текстовое сравнение.
vbDatabaseCompare	2	Для Microsoft Access: выполняется сравнение, базирующееся на информации из вашей базы данных.
Константы компиляции (Compiler)
Константа	Значение	Описание
Для 16-битных платформ:		
winie	True	Указывает на 16-битную среду разработки.
Win32	False	Указывает, что среда разработки — не 32-битная.
Для 32-битных платформ:		
Vba6	True	Указывает, что среда разработки — Visual Basic for Applications, версия 6.0.
Vba6	False	Указывает, что среда разработки — не Visual Basic for Applications, версия 6.0.
Winl6	False	Указывает, что среда разработки — не 16-битная.
Win32	True	Указывает на 32-битную среду разработки.
Mac	False	Указывает, что среда разработки — не Macintosh.
WinlG	False	Указывает, что среда разработки — не 16-битная.
Константы дат (Date)
Константа	Значение	Описание
Аргумент firstdayofweek может принимать следующие значения		
vbUseSystem	0	Использовать настройку NLS API.
vbSunday	1	Sunday
vbMonday	2	Monday
vbTuesday	3	Tuesday
vb W ednesday	4	Wednesday
vbThursday	5	Thursday
vbFriday	6	Friday
vbSaturday	7	Saturday
834
Приложение Д
Константа	Значение	Описание
Аргумент firstdayofyear может принимать следующие значения		
vbUseSystem	0	Использовать настройку NLS API.
VbUseSystem DayOfWeek	0	Использовать день недели, заданный установками вашей системы для первого дня недели.
VbFirstJanl	1	Начинать с той недели, в которой будет первое января (по умолчанию).
vbFirstFourDays	2	Начинать с первой недели, которая имеет, по меньшей мере, четыре дня в новом году.	1
vbFirstFull W eek	3	Начинать с первой полной недели года.
Возвращаемые значения		
vbSunday	1	Sunday
vbMonday	2	Monday
vbTuesday	3	Tuesday
vb Wednesday	4	Wednesday
vbThursday	5	Thursday
vbFriday	6	Friday
vbSaturday	7	Saturday
Константы формата дат (Date Format)
Эти константы доступны только в том случае, когда ваш проект имеет явную ссылку на соответствующую библиотеку, в которой константы определены.
Константа	Значение	Описание
vbGeneralDate •	0	Отображать дату и/или время. Для действительных чисел отображать дату и время. Если дробная часть отсутствует, отображать только дату. Если отсутствует целая часть, отображать только время. Вид отображения даты и времени определяется настройками компьютерной системы.
vbLongDate	1	Отображать дату с использованием «длинного» (long) формата, определенного региональными установками компьютерной системы.
vbShortDate	2	Отображать дату с использованием «короткого» (short) формата, определенного региональными установками компьютерной системы.
vbLongTime	3	Отображать время с использованием «длинного» (long) формата, определенного региональными установками компьютерной системы.
vbShortTime	4	Отображать время с использованием «короткого» (short) формата, определенного региональными установками компьютерной системы.
Константы в VBA
835
Константы функций Dir, GetAttr и SetAttr
Константа	Значение	Описание
vbNormal	0	Обычный (Normal) (по умолчанию для Dir и SetAttr],
vbReadOnly	1	Только на чтение (Read-only).
vbHidden	2	Скрытый (Hidden).
vbSystem	4	Системный файл (System file).
vb Volume	8	Метка тома (Volume label).
vbDirectory	16	Каталог или папка.
vbArchive	32	Файл изменен после последнего резервирования.
vbAlias	64	Алиасное имя (на Macintosh).
Для Macintosh доступны только VbNormal, vbReadOnly, vbHidden и vbAlias.
Константы типов драйверов (DriveType)
Эти константы доступны только в том случае, когда ваш проект имеет явную ссылку на соответствующую библиотеку, в которой константы определены.
Константа	Значение	Описание
Unknown	0	Тип драйвера не может быть определен.
Removable	1	Устройство со съемным носителем. Включает все флоппи-драйверы и много других разновидностей устройств хранения данных.
Fixed	2	Устройство с несъемным носителем. Включает все «жесткие» диски.
Remote	3	Сетевые драйверы.
CDROM	4	CD-ROM. Не различаются read-only и read/write.
RAMDisk	5	Драйвер — блок Random Access Memory (RAM) на локальном компьютере. По своему «поведению» подобен дисковому драйверу.
Константы атрибутов файлов (File Attribute)
Эти константы доступны только в том случае, когда ваш проект имеет явную ссылку на соответствующую библиотеку, в которой константы определены.
Константа	Значение	Описание
Normal	0	Обычный файл
Readonly	1	Файл только для чтения
Hidden	2	Скрытый файл
System	4	Системный файл
Volume	8	Метка тома дискового драйвера
836
Приложение Д
Константа	Значение	Описание
Directory	16	Папка или каталог
Archive	32	Файл изменился, после последней архивации
Alias	64	Ссылка или ярлык
Compressed	128	Упакованный файл
Константы файлового ввода/вывода
(File Input/Output)
Эти константы доступны только в том случае, когда ваш проект имеет явную ссылку на соответствующую библиотеку, в которой константы определены.
Константа	Значение	Описание
ForReading	1	Файл открывается только для чтения. Запись в этот файл невозможна.
For Writing	2	Файл открывается для записи. Если файл с таким именем уже существует, предыдущее его содержимое теряется.
ForAppending	8	Файл открывается для дозаписи (в конец файла).
Константы форм (Form)
Константа	Значение	Описание
vbModeless	0	UserForm — немодальная
vbModal	1	UserForm — модальная (modal)
Константы Dir, GetAttr и SetAttr
Константа	Значение	Описание
vbNormal	0	Обычный (Normal)
vbReadOnly	1	Только на чтение (Read-only)
vbHidden	2	Скрытый (Hidden)
vbSystem	4	Системный файл (System file)
vbVolume	8	Метка тома (Volume label)
vbDirectory	16	Каталог или папка (Directory or folder)
vb Archive	32	Файл изменился, после последней архивации (File has changed since last backup)
vbAlias	64	Ha Macintosh (идентифицирует алиас)
Константы VbNormal, vbReadOnly, vbHidden и vbAlias доступны только при работе в системе Macintosh.
Константы в VBA
837
Константы ключевых кодов (Keycode)
Константа	Значение	Описание
vbKeyLButton	0x1	Левая кнопка мыши (Left mouse button)
vbKeyRButton	0x2	Правая кнопка мыши (Right mouse button)
vbKeyCancel	0x3	Клавиша CANCEL (CANCEL key)
vbKeyMButton	0x4	Средняя кнопка мыши (Middle mouse button)
vbKeyBack	0x8	Клавиша BACKSPACE (BACKSPACE key)
vbKeyTab	0x9	Клавиша TAB (TAB key)
vbKeyClear	OxC	Клавиша CLEAR (CLEAR key)
vbKeyReturn	OxD	Клавиша ENTER (ENTER key)
vbKeyShift	0x10	Клавиша SHIFT (key)
vbKeyControl	0x11	Клавиша CTRL (CTRL key)
vbKeyMenu	0x12	Клавиша MENU (MENU key)
vbKeyPause	0x13	Клавиша PAUSE (PAUSE key)
1 vbKeyCapital	0x14	Клавиша CAPS LOCK (CAPS LOCK key)
1 vbKeyEscape	OxlB	Клавиша ESC (ESC key)
vbKeySpace	0x20	Клавиша SPACEBAR (SPACEBAR key)
vbKeyPageUp	0x21	Клавиша PAGE UP (PAGE UP key)
vb KeyPageDown	0x22	Клавиша PAGE DOWN (PAGE DOWN key)
j vbKeyEnd	0x23	Клавиша END (END key)
| vbKeyHome	0x24	Клавиша HOME (HOME key)
vbKeyLeft	0x25	Клавиша LEFT ARROW (LEFT ARROW key)
vbKeyUp	0x26	Клавиша UP ARROW (UP ARROW key)
vbKeyRight	0x27	Клавиша RIGHT ARROW (RIGHT ARROW key)
vbKeyDown	0x28	Клавиша DOWN ARROW (DOWN ARROW key)
vbKeySelect	0x29	Клавиша SELECT (SELECT key)
vbKeyPrint	0x2A	Клавиша PRINT SCREEN (PRINT SCREEN key)
vbKeyExecute	0x2B	Клавиша EXECUTE (EXECUTE key)
vbKeySnapshot	0x2C	Клавиша SNAPSHOT (SNAPSHOT key)
vbKeylnsert	0x2D	Клавиша INSERT (INSERT key)
vbKeyDelete	0x2E	Клавиша DELETE (DELETE key)
| vbKeyHelp	0x2F	Клавиша HELP (HELP key)
| vbKeyNumlock	0x90	Клавиша NUM LOCK (NUM LOCK key)
838
Приложение Д
Клавиши от А до Z имеют следующие константы и ASCII-значения:
Константа	Значение	Клавиша	Константа	Значение	Клавиша
vbKeyA	65	A	vbKeyM	77	M
vbKeyB	66	В	vbKeyN	78	N
vbKeyC	67	С	vbKeyO	79	О
vbKeyD	68	D	vbKeyP	80	P
vbKeyE	69	E	vbKeyQ	81	Q
vbKeyF	70	F	vbKeyR	82	R
vbKeyG	71	G	vbKeyS	83	S
vbKeyH	72	H	vbKeyT	84	T
vbKeyl	73	I	vbKeyU	85	и
vbKeyJ	74	J	vbKeyV	86	V
vbKeyK	75	К	vbKeyW	87	w
vbKeyL	76	L	vbKeyX	88	X
Клавиши от 0 до 9 имеют следующие константы и ASCII-значения:
Константа	Значение	Клавиша
vbKeyO	48	0
vbKeyl	49	1
vbKey2	50	2
vbKey3	51	3
vbKey4	52	4
vbKey5	53	5
vbKey6	54	6
vbKey7	55	7
vbKey8	56	8
vbKey9	57		9	
Константы, соответствующие клавишам на числовом поле клавиатуры:
Константа	Значение	Клавиша
vbKeyNumpadO	0x60	0
vbKeyN umpadl	0x61	1
vbKeyNumpad2	0x62	2
vbKeyN umpad3	0x63	3
vbKeyNumpad4	0x64	4
vbKeyN umpad5	0x65	5
vbKeyN umpad6	0x66	6
Константы в VBA
839
Константа	Значение	Клавиша
vbKeyNumpad7	0x67	7
vbKeyNumpad8	0x68	8
vbKeyNumpad9	0x69	9
vbKeyMultiply	0x6A	MULTIPLICATION SIGN (*)
vbKeyAdd	0x6B	PLUS SIGN (+)
vbKeySeparator	0x6C	ENTER
vbKeySubtract	0x6D	MINUS SIGN (-)
vbKeyDecimal	0x6E	DECIMAL POINT (.)
vbKeyDivide	0x6F	DIVISION SIGN (/)
Константы для представления функциональных клавиш:
Константа	Значение	Клавиша	Константа	Значение	Клавиша
vbKeyFl	0x70	Fl	vbKeyF9	0x78	F9
vbKeyF2	0x71	F2	vbKeyFlO	0x79	F10
vbKeyF3	0x72	F3	vbKeyFll	0x7A	Fll
vbKeyF4	0x73	F4	vbKeyF12	0x7B	F12
vbKeyF5	0x74	F5	vbKeyF13	0x7C	F13
vbKeyF6	0x75	F6	vbKeyF14	0x7D	F14
vbKeyF7	0x76	F7	vbKeyF15	0x7E	F15
vbKeyF8	0x77	F8	vbKeyF16	0x7F	F16
Смешанные константы (Miscellaneous Constants)
Константа	Значение	Описание
vbCrLf	Chr(13) + Chr(10)	Комбинация символов «возврат карет -ки-перевод строки» (Carriage return-linefeed combination).
vbCr	Chr(13)	Символ «возврата каретки» (Carriage return character).
vbLf	Chr(10)	Символ «перевода строки» (Linefeed character).
vbNewLine	Chr(13) + Chr(10) или Chr(13) на Macintosh	Зависящий от «платформы» символ «новой строки».
vbNullChar	Chr(0)	Символ нулевого значения (Character having value 0).
vbNullString	Строка, имеющая нулевое значение (String having value 0)	Не то же самое, что строка нулевой длины (""); используется при вызове внешних процедур.
840
Приложение Д
Константа	Значение	Описание
vbObjectError	-2147221504	Определяемые пользователем error-числа должны быть больше этого значения. Например: Err.Raise Number = vbObjectError + 1000
vbTab	Chr(9)	Символ табуляции (Tab character).
vbBack	Chr(8)	Backspace-символ (Backspace character).
Константы функции MsgBox
Аргументы-константы функции MsgBox
Константа	Значение	Описание
vbOKOnly	0	Вывод только кнопки ОК (по умолчанию).
vbOKCancel	1	Вывод кнопок ОК и Cancel.
vbAbortRetrylgnore	2	Вывод кнопок Abort, Retry и Ignore.
vbYesNoCancel	3	Вывод кнопок Yes, No и Cancel.
vbYesNo	4	Вывод кнопок Yes и No.
vbRetryCancel	5	Вывод кнопок Retry и Cancel.
vbCritical	16	Critical-сообщение.
vbQuestion	32	Warning-запрос.
vbExclamation	48	W arning-сообщение.
vblnformation	64	Information-сообщение.
vbDefaultButtonl	0	Кнопка по умолчанию — первая (по умолчанию).
vbDefaultButton2	256	Кнопка по умолчанию — вторая.
vbDefaultButton3	512	Кнопка по умолчанию — третья.
vbDefaultButton4	768	Кнопка по умолчанию — четвертая.
vbApplicationModal	0	Модальное окно сообщения приложения (по умолчанию) (Application modal message box).
vbSystemModal	4096	Модальное окно сообщения системы (System modal message box).
vbMsgBoxHelpButton	16384	Добавляет кнопку Help к окну сообщения.
VbMsgBoxSet-Foreground	65536	Определяет окно сообщения как фоновое (Specifies the message box window as the foreground window).
vbMsgBoxRight	524288	Текст выравнивать по правой границе.
vbMsgBoxRtlReading	1048576	Определяет, что должен появляться справа-налево, как в Hebrew- и Arabic-системе.
Константы в VBA
841
Возвращаемые значения функции MsgBox
Константа	Значение	Выбрана кнопка
vbOK	1	OK
vbCancel	2 .	Cancel
vbAbort	3	Abort
vbRetry	4	Retry
vblgnore	5	Ignore
vbYes	6	Yes
vbNo	7	No
QueryClose-константы
Константа	Значение	Описание
vbFormControlMenu	0	Пользователь выбирает команду Close из меню Control на форме.
vbFormCode	1	Оператор Unload вызывается из кода.
vbApp Windows	2	Текущий сеанс Microsoft Windows заканчивается.
vbAppTaskManager	3	Windows Task Manager закрывает приложение.
Константы Shell
Константа	Значение	Описание
vbHide	0	Окно становится скрытым, фокус устанавливается на скрытое окно.
vbN ormalFocus	1	Окно принимает фокус и восстанавливается до оригинальных размеров и положения на экране.
vbMinimizedFocus	2	Окно отображается как значок с фокусом.
vbMaximizedFocus	3	Окно «максимизируется» с фокусом.
vbNormalNoFocus	4	Окно восстанавливается до его последних размеров и положения на экране. Текущее активное окно остается активным.
vbMinimizedN oFocus	6	Окно отображается как значок. Текущее активное окно остается активным.
Константы специальных папок (SpecialFolder)
Эти константы доступны только в том случае, когда ваш проект имеет явную ссылку на соответствующую библиотеку, в которой константы определены.
842
Приложение Д
Константа	Значение	Описание
WindowsFolder	0	Папка Windows содержит файлы, установленные операционной системой Windows.
SystemFolder	1	Папка System содержит библиотеки, шрифты и драйверы устройств.
TemporaryFolder	2	Папка Тетр используется для хранения временных файлов. Путь (path) к ней находится в переменной среды ТМР.
Константы преобразования строк (StrConv)
Константа	Значение	Описание
vbUpperCase	1	Конвертирует строку в символы верхнего регистра.
vbLowerCase	2	Конвертирует строку в символы нижнего регистра.
vbProperCase	3	Конветрирует первый символ каждого слова в строке в верхний регистр.
vbUnicode	64	Конвертирует строку в Unicode, используя кодовую страницу системы по умолчанию (Не для Macintosh).
vbFromUnicode	128	Конвертирует строку из Unicode в кодовую страницу системы по умолчанию (Не для Macintosh).
Константы системных цветов (System Color)
Константа	Значение	Описание
vbScrollBars	0x80000000	Цвет линейки прокрутки
vbDesktop	0x80000001	Цвет элемента Desktop
vbActiveTitleBar	0x80000002	Цвет строки заголовка активного окна
! vblnactiveTitleBar	0x80000003	Цвет строки заголовка неактивного окна
vbMenuBar	0x80000004	Цвет фона меню
vbWindow- Background	0x80000005	Цвет фона окна (Window)
vbWindowFrame	0x80000006	Цвет рамки окна (Window frame color)
1 vbMenuText	0x80000007	Цвет текста меню (Color of text on menus)
vbWindowText	0x80000008	Цвет текста в окнах (Color of text in windows)
vbTitleBarText	0x80000009	Цвет текста в заголовке (caption)
vbActiveBorder	0x8000000A	Цвет границы активного окна (Border color of active window)
Константы в VBA
843
Константа	Значение	Описание
vblnactiveBorder	0x8000000В	Цвет границы неактивного окна (Border color of inactive window)
vbApplication-Workspace	0x8000000C	Цвет фона приложений с многодокументным интерфейсом [Background color of multiple-document interface (MDI) applications]
vbHighlight	0x8000000D	Цвет фона выделенных частей элемента управления (Background color of items selected in a control)
vbHighlightText	0x8000000E	Цвет текста выделенных частей элемента управления (Text color of items selected in a control)
vbButtonFace	0x8000000F	Цвет затенения командной кнопки (Color of shading on the face of command buttons)
vbButton Shadow	0x80000010	Цвет затенения на контуре командной кнопки (Color of shading on the edge of command buttons)
vbGrayText	0x80000011	Текст на элементе, недоступном для выбора
vbButtonText	0x80000012	Цвет текста на «нажатой»кнопке (Text color on push buttons)
vblnactiveCaption-Text	0x80000013	Цвет текста неактивного заголовка (Color of text in an inactive caption)
vb3DHighlight	0x80000014	Цвет выделения для трехмерных элементов (Highlight color for 3-D display elements)
vb3DDKShadow	0x80000015	Самый темный цвет тени для трехмерных элементов (Darkest shadow color for 3-D display elements)
vb3DLight	0x80000016	Второй по яркости после vb3DHighlight цвет для трехмерных элементов (Second lightest 3-D color after vb3Dhighlight)
vblnfoText	0x80000017	Цвет текста для элемента ToolTip
vblnfoBackground	0x80000018	Цвет фона для элемента ToolTip
Tristate-константы
Эти константы доступны только в том случае, когда ваш проект имеет явную ссылку на соответствующую библиотеку, в которой константы определены.
Константа	Значение	Описание
vbTrue	-1	True
vbFalse	0	False
vbUseDefault	-2	Использовать установку по умолчанию
844
Приложение Д
VarType-константы
Константа	Значение	Описание
vbEmpty	0	He инициализирована (по умолчанию)
vbNull	1	Содержит недопустимые данные
vblnteger	2	Целое (Integer)
vbLong	3	Длинное целое (Long integer)
vbSingle	4	Число с плавающей запятой одинарной точности (Single-precision floating-point number)
vbDouble	5	Число с плавающей запятой двойной точности (Double-precision floating-point number)
vbCurrency	6	Currency
vbDate	7	Date
vbString	8	String
vbObject	9	Object
vbError	10	Error
vbBoolean	11	Boolean
vbVariant	12	Variant (используется только для Variant-массивов)
vbDataObject	13	Объект для доступа к данным (Data access object)
vbDecimal	14	Decimal
vbByte	17	Byte
vbUserDefinedType	36	Данные пользовательских типов
vbArray	8192	Array
Приложение I
События объектов UserForm
Для всех синтаксических выражений object - допустимый объект, объектное выражение, которое вычисляется до объекта (ссылки на объект).
Activate
Инициируется всякий раз, когда окно формы становится активным.
Синтаксис
Private Sub object Activate()
Пример
Следующий код использует две формы UserForm: UserForml и UserForm2. Скопируйте эти две процедуры в модуль UserForml, затем добавьте UserForm2. Заголовок UserForml создается в процедуре события Activate. Когда пользователь щелкает мышью на клиентской области UserForml, UserForm2 загружается и отображается, запуская событие Deactivate формы UserForml, изменяющее заголовки форм.
' Событие Activate для UserForml
Private Sub UserForm_Activate()
UserForml.Caption = "Щелкните на мне"
End Sub
' Событие Click для UserForml
Private Sub UserForm_Click()
Load UserForm2
UserForm2.Startupposition = 3
UserForm2.Show
End Sub
' Событие Deactivate для UserForml	>	. ( J
Private Sub UserForm_Deactivate()
UserForml.Caption = "Я потеряла фокус1"
UserForm2.Caption = "Фокус перешел от UserForml ко мне "
End Sub
Для всех примеров достаточно создать форму(ы), поместить на нее указанные эле менты управления и скопировать приведенный код в модуль формы
Initialize
Инициируется всякий раз, когда форма впервые загружается в память оператором Load или методом Show.
Синтаксис
Private Sub object lnitialize()
Пример
Следующий пример предполагает наличие двух UserForm в программе. В событии Initialize формы UserForml загружается и отображается форма UserForm2. Когда пользователь щелкает мышью на UserForm2, она скрывается и отображается UserForml. При щелчке на UserForml форма UserForm2 отображается снова.
846
Приложение Е
' Это процедура события Initialize для UserForml Private Sub UserForm_Initialize()
Load UserForm2
UserForm2.Show
End Sub
' Это событие Click формы UserForm2
Private Sub UserForm_Click()
UserForm2.Hide
End Sub
' Это событие click для UserForml Private Sub UserForm_Click()
UserForm2.Show
' End Sub
QueryClose
Инициируется перед тем, как UserForm закрывается.
Синтаксис
Private Sub UserForm_QueryClose(cancel As Integer, closemode As Integer) Параметры
cancel	Целое. Задание этому аргументу любого значения, отличного от 0, устанавливает событие QueryClose во всех загружаемых пользовательских формах и предотвращает закрытие UserForm и приложения.
closemode	Значение или константа, обозначающая причину события QueryClose.
Возвращаемые значения
Аргумент closemode возвращает следующие значения:
Константа	Значение	Описание
vbFormControlMenu	0	Пользователь выбрал команду Close из меню Control в UserForm.
VbFormCode	1	Оператор Unload вызывается из кода.
vbApp Windows	2	Текущая сессия рабочей среды Windows заканчивается.
vbAppTaskManager	3	Windows Task Manager закрывает приложение.
Пример
Следующий код вынуждает пользователя щелнуть мышью на клиентской области UserForm для ее закрытия. Если пользователь пытается использовать кнопку закрытия окна в строке заголовка, параметр Cancel устанавливается в ненулевое значение, предотвращая завершение программы. Однако если пользователь щелкнул мышью на форме, closemode имеет значение 1 и оператор Unload Me завершает работу приложения.
Private Sub UserForm__Activate ()
UserForml.Caption - "Вы должны щелкнуть на мне, чтобы закрыть меня!" End Sub
События объектов UserForm
847
Private Sub UserForm_Click() Unload Me
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) ' Предотвратить закрытие с помощью Close box в строке заголовка.
If CloseMode 1 Then_Cancel = 1
UserForml.Caption = " Close box не работает! Щелкните на мне!"
End Sub
Resize
Инициируется при изменении размеров формы.
Синтаксис
Private Sub UserForm_Resize()
Пример
Следующий пример использует события Activate и Click для иллюстрации запуска события Resize формы (UserForm). Когда пользователь щелкает мышью на клиентской области формы, она расширяется или сжимается и в строке заголовка сообщается о новой высоте. Заметьте, что переменная Tag используется для сохранения первоначальной высоты UserForm.
' Событие Activate для UserForml Private Sub UserForm_Activate()
UserForml.Caption = "Щелкните на мне для увеличения моей высоты!" Tag = Height ' Сохранить первоначальную высоту.
End Sub
' Событие Click для UserForml Private Sub UserForm_Click() Dim NewHeight As Single NewHeight = Height ' Если форма маленькая, увеличить высоту. If NewHeight = Vai(Tag) Then	,
Height = Vai(Tag) * 2 Else ' Если форма большая, уменьшить ее. Height = Vai(Tag)
End If End Sub ' Событие Resize для UserForml Private Sub UserFormResize()
UserForml.Caption - "Новая высота: " & Высота & "	" & _
"Щелкните, чтобы изменить мой размер!" End Sub
Terminate
Инициируется всякий раз, когда форма выгружается из памяти.
Синтаксис
Private Sub object_Terminate( )
Пример
Следующие событийные процедуры приводят к тому, что код модуля формы издает звуковой сигнал в течение нескольких секунд после того, как пользователь щелкает на клиентской области, чтобы отменить форму.
848
Приложение Е
Private Sub UserForm_Activate()
UserForml.Caption = "Щелкните на мне для окончания работы!" End Sub
Private Sub UserForm_Click()
Unload Me
End Sub	•	,
Private Sub UserForm_Terminate()
Dim Count As Integer
For Count = 1 To 100
Beep
Next
End Sub
События объектов управления
AddControl
Инициируется всякий раз, когда к форме или элементам Frame, MultiPage (Page) добавляется какой-либо элемент управления.
Синтаксис
Для элемента Frame:
Private Sub obgect_AddControl()
Для элемента MultiPage:
Private Sub objectAddControl(index As Lpng, Ctrl As Control)
Параметры (обязательные):
index	Индекс страницы (Page), которая будет содержать новый элемент управления.
Ctrl	Элемент управления, который необходимо добавить.	]
Пример
Следующий пример использует метод Add для добавления элемента управления в форму во время выполнения приложения и использует событие AddControl в качестве подтверждения того, что элемент управления был добавлен.
Для того чтобы использовать этот пример кода, скопируйте код в часть Declarations (объявлений) формы. Поместите на форму CommandButton с именем CommandButtonl.
Dim Mycmd as Control
Private Sub CommandButtonl Click ()
'	Set Mycmd = Controls.Av ("MSForms.CommandButton.1", _
CommandButcon2, Visible)
Mycmd.Left = 18
Mycmd.Top =150
Mycmd.Width - 175
Mycmd Height = 20
Mycmd.Caption = "Это забавно. " & Mycmd.Name
End Sub
Private Sub UserForm_AddControl(ByVai Control As MSForms.Control) UserForml.Caption = "Элемент управления был добавлен."
End Sub
События объектов UserForm
849
AfterUpdate
Инициируется после обновления значения элемента управления.
Синтаксис
Private Sub object_AfterUpdate()
Пример
В этом примере форма пользователя должна содержать элемент Checkbox с именем CheckBoxl. Тогда следующая событийная процедура после каждого изменения установки флажка будет выдавать звуковое и текстовое сообщение об этом.
Private Sub CheckBoxlAfterUpdate() Beep MsgBox ("Установка флажка изменилась")
End Sub
BeforeDragOver
Инициируется при выполнении операции drag-and-drop.
Синтаксис
Для элементов Frame:
Private Sub оЪject_BeforeDragOver( ByVai Cancel As
MSForms.ReturnBoolean, Ctrl As Control, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai DragState As fmDragState, ByVai Effect As MSForms.ReturnEffect, ByVai Shift As fmShiftState)
Для элементов MultiPage:
Private Sub object_BeforeDragOver( index As Long, ByVai Cancel As MSForms.ReturnBoolean, Ctrl As Control, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai DragState As fmDragState, ByVai Effect As MSForms.ReturnEffect, ByVai Shift As fmShiftState)
Для элементов TabStrip:
Private Sub object_BeforeDragOver( index As Long, ByVai Cancel As MSForms.ReturnBoolean, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai DragState As fmDragState, ByVai Effect As MSForms.ReturnEffect, ByVai Shift As fmShiftState)
Для других элементов управления:
Private Sub object_BeforeDragOver( ByVai Cancel As
MSForms.ReturnBoolean, ByVai Data As DataObject, ByVai X As Single, ByVai У As Single, ByVai DragState As fmDragState, ByVai Effect As MSForms.ReturnEffect, ByVai Shift As fmShiftState)
Параметры (все обязательные):
index	Индекс страницы (Page) (в MultiPage), для которой имеет место операция drag-and-drop.
Cancel	Статус (status) события. False указывает, что элемент управления должен обрабатывать событие (по умолчанию). True указывает, что событие обрабатывается приложением.
Ctrl	Элемент-приемник.
Data	Данные, перетаскиваемые в операции drag-and-drop. Данные упаковываются в DataObject.
X, Y	Горизонтальная и вертикальная координаты (в пойнтах) положения левого (координата X) верхнего (координата Y) угла элемента управления.
2ft Ппогоаммиоование на VBA 2002
850
Приложение Е
DragState	Состояние перемещения данных.
Effect	Операции, поддерживаемые перемещаемым объектом.
Shift	Определяет состояние клавиш SHIFT, CTRL и ALT.
Установки для DragState'.
Константа	Значение	Описание
fmDragStateEnter	0	Указатель мыши находится внутри области приемника.
fmD rag St at eLeave	1	Указатель мыши находится вне области приемника.
fmDragStateOver	2	Указатель мыши находится в новой позиции, но остается внутри области того же приемника.
Установки для Effect'.
Константа	Значение	Описание
fmDropEffectNone	0	He копирует или передвигает перемещаемый объект на объект-приемник.
fmDropE ffec tCopy	1	Копирует перемещаемый объект на объект-приемник.
fmDropEffectMove	2	Перемещает объект на объект-приемник.
fmDropEffectCopyOrMove	3	Копирует или перемещает объект на объект-приемник.
Установки для Shift'.
Константа	Значение	Описание
fmShiftMask	1	SHIFT была нажата.
fmCtrlMask	2	CTRL была нажата.
fmAltMask	4	ALT была нажата.
Используйте это событие для контроля за тем, когда указатель (курсор) мыши входит, покидает или остается на доступном элементе-приемнике. При выполнении операции drag-and-drop система инициализирует это событие, кода пользователь перемещает мышь, нажимает или отпускает кнопку(и) мыши. Положение указателя мыши определяет объект-приемник, который принимает это событие. Состояние указателя мыши можно определить посредством аргумента DragState.
Если элемент управления обрабатывает это событие, вы можете использовать аргумент Effect, чтобы указать drag-and-drop-действие для выполнения. Если Effect установлен в fmDropEffectCopyOrMove, перемещаемый объект (drop source) поддерживает операцию копирования (fmDropEffectCopy), перемещения (fmDrop-EffectMove) или отмены (fmDropEffectNone). Если Effect установлен в fmDropEffectCopy, перемещаемый объект поддерживает операцию копирования или отмены (fmDropEffectNone). Если Effect установлен в fmDropEffectMove, перемещаемый объект поддерживает операцию перемещения или отмены (fmDropEffectNone). Если Effect установлен в fmDropEffectNone, перемещаемый объект поддерживает операцию отмены.
События объектов UserForm
851
BeforeDropOrPaste
Инициируется, когда пользователь «бросает» или вставляет данные в объект.
Синтаксис
Для элементов Frame:
Private Sub object_BeforeDropOrPaste( ByVai Cancel As
MSForms.ReturnBoolean, Ctrl As Control, ByVai Action As fmAction, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai Effect As MSForms.ReturnEffeet, ByVai Shift As fmShiftState)
Для элементов MultiPage:
Private Sub object_BeforeDropOrPaste( index As Long, ByVai Cancel As MSForms.ReturnBoolean, Ctrl As Control, ByVai Action As fmAction, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai Effect As MSForms.ReturnEffeet, ByVai Shift As fmShiftState)
Для элементов TabStrip:
Private Sub object_BeforeDropOrPaste( index As Long, ByVai Cancel As MSForms.ReturnBoolean, ByVai Action As fmAction, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai Effect As MSForms.ReturnEffeet, ByVai Shift As fmShiftState)
Для других элементов управления:
Private Sub object_BeforeDropOrPaste( ByVai Cancel As
MSForms.ReturnBoolean, ByVai Action As fmAction, ByVai Data As DataObject, ByVai X As Single, ByVai Y As Single, ByVai Effect As MSForms.ReturnEffeet, ByVai Shift As fmShiftState)
Параметры (все обязательные):
index	Индекс страницы (Page) (в MultiPage), для которой имеет место операция drag-and-drop.
Cancel	Статус (status) события. False указывает, что элемент управления должен обрабатывать событие (по умолчанию). True указывает, что событие обрабатывается приложением.
Ctrl	Элемент-приемник
Action	Указывает результат, основанный на текущих настройках клавиатуры во время операции drag-and-drop.
Data	Данные, перетаскиваемые в операции drag-and-drop. Данные упаковываются в DataObject.
X, Y	Горизонтальная и вертикальная координаты (в пойнтах) положения левого (координата X) верхнего (координата Y) угла указателя мыши при «бросании».
Effect	Воздействие операции drag-and-drop на элемент-приемник.
Shift	Определяет состояние клавиш SHIFT, CTRL и ALT.
Установки для Action:
Константа	Значение	Описание
fmActionPaste	2	Вставляет выделенный элемент в элемент-приемник.	I
fmActionDrag-Drop	3	Указывает, что пользователь перетащил объект из источника и «бросил» его на объект-приемник.
852
Приложение Е
Установки для Effect-.
Константа	Значение	Описание
fmDropEffectNone	0	He копирует или передвигает перемещаемый объект на объект-приемник
fmD ropE ff ectCopy	1	Копирует перемещаемый объект на объект-приемник.
fmDropEffectMove	2	Перемещает объект на объект-приемник.
fmDropEffectCopy- OrMove	3	Копирует или перемещает объект на объект-приемник.
Установки для Shift:
Константа	Значение	Описание
fmShiftMask	1	SHIFT была нажата.
fmCtrlMask	2	CTRL была нажата.
fmAltMask	4	ALT была нажата.
Для элементов MultiPage или TabStrip Visual Basic for Applications инициирует это событие при переносе объекта на элемент управления. Для других элементов управления система инициирует это событие непосредственно перед операцией «бросания» или вставки.
Если элемент обрабатывает это событие, вы можете изменить аргумент Action, чтобы указать drag-and-drop-действие для выполнения. Если Effect установлен в fmDropEffectCopyOrMove, аргументу Action можно присвоить fmDropEffectNone, fmDropEffectCopy или fmDropEffectMove. Если Effect установлен в fmDropEffectCopy или fmDropEffectMove, аргументу Action можно присвоить fmDropEffectNone. Нельзя переприсваивать аргумент Action, если Effect установлен в fmDropEffectNone.
BeforeUpdate
Private Sub object_BeforeUpdate(ByVai Cancel As MSForms.ReturnBoolean)
Параметр:
। Cancel	Обязательный. Статус события. False обозначает, что этот элемент управления должен обрабатывать событие (по умолчанию). True отменяет обновление и обозначает, что приложение должно обрабатывать событие.
Change
Событие Change возникает, когда изменяется настройка свойства Value, независимо от того, вызвано ли это изменение из выполняемого кода или действиями пользователя (посредством интерфейса).
Синтаксис
Private Sub object_Change()
Вот некоторые примеры действий, которые изменяют свойство Value:
События объектов UserForm
853
	Щелчок на CheckBox, OptionButton или ToggleButton.
	Ввод или выбор нового текстового значения для ComboBox, ListBox или TextBox.
	Выбор другой вкладки в TabStrip.
	Перемещение ползунка линейки прокрутки в ScrollBar.
	Щелчок на стрелке вверх или на стрелке вниз на SpinButton.
	Выбор другой страницы в MultiPage.
В качестве примера можно использовать код примера для события AfterUpdate, немного его модифицировав.
Click
Инициируется всякий раз, когда по элементу управления щелкают мышью. Чаще всего используется для элементов управления типа CommandButton.
Для элемента MultiPage и TabStrip
Синтаксис
Private Sub oi>ject_Click ( index As Long)
Для других элементов управления:
Private Sub object_Click( )
Параметр:
index т====я=====с	Обязательный. Индекс страницы или вкладки в MultiPage TabStrip, ассоциированной с этим событием.
Пример 
Этот пример изменяет Caption-свойство элемента CommandButton каждый раз, когда пользователь щелкает на кнопке, используя мышь. Событие Click содержит код для изменения свойства Caption.
Чтобы выполнить этот пример, скопируйте код в область Declarations формы, содержащей CommandButton с именем Кнопка.
Private Sub Кнопка _Click ()
If Кнопка.Caption = "OK" Then
' Изменить заголовок
Кнопка.Caption = "Щекните еще"
Else
Кнопка.Caption = "OK"
End If
End Sub	’
DbICIick
Инициируется, когда по элементу управления дважды щелкают мышью.
Синтаксис
Для элементов MultiPage и TabStrip:
Private Sub object_DblClick( index As Long, ByVai Cancel As MSForms.ReturnBoolean)
Для других элементов управления:
Private Sub object_DblClick( ByVai Cancel As MSForms.ReturnBoolean)
Параметры (обязательные):
index	Позиция объекта Page или Tab в коллекции Pages или Tabs.
854
Приложение Е
Cancel	Статус события. False обозначает, что элемент управления должен обрабатывать это событие (по умолчанию). True обозначает, что приложение обрабатывает событие.
Следующий пример использует форму и код предыдущего примера, но здесь добавлена событийная процедура, которая предупреждает пользователя о том, что нет нужды щелкать по кнопке дважды. (В справочной системе для этого события приведен более интересный, но и более сложный пример.)
Private Sub Кнопка _Click()
If Кнопка.Caption = "OK" Then
' Изменить заголовок
.	Кнопка.Caption = "Щекните еще"
Else
Кнопка.Caption = "OK" End If
End Sub
Private Sub Кнопка_РЫС11ск(ByVai Cansel As MSForms.ReturnBoolean) Beep
MsgBox ("He нужно щелкать дважды, одного щелчка достаточно!")
End Sub
Enter
Инициируется при выделении элемента управления.
Синтаксис
Private Sub obgect_Enter( )
Параметр:	
Cancel	Обязательный. Статус события. False обозначает, что элемент управления должен обрабатывать событие (по умолчанию). True обозначает, что приложение обрабатывает событие и фокус должен оставаться у текущего элемента управления.
Пример	।
Следующий пример использует свойство ActiveControl в подпрограмме, которая отслеживает элементы управления, выбираемые пользователем. Событие Enter для каждого элемента управления вызывает подпрограмму TraceFocus для идентификации элемента управления, который имеет фокус.
Для того чтобы использовать этот пример, скопируйте код в область Declarations формы. Поместите на форму следующие элементы управления:
	ScrollBar с именем ScrollBarl.
	ListBox с именем ListBoxl.
	Два элемента управления OptionButton с именами OptionButton 1 и Option-Button2.
	Frame с именем Framel. (Элементы OptionButton не помещайте внутрь Frame.)
Dim MyControl As Control
Private Sub TraceFocus!)
ListBoxl.Additem ActiveControl.Name
ListBoxl.List(ListBoxl.ListCount - 1, 1) = _
ActiveControl.Tabindex
End Sub
Private Sub UserForm_Initialize()	'
События объектов UserForm
855
ListBoxl.ColumnCount = 2
ListBoxl.Additem "Использованные элементы "
ListBoxl.List(0, 1) = "Индекс элемента" End Sub
Private Sub Framel_Ent^r() TraceFocus
End Sub
Private Sub ListBoxl_Enter() TraceFocus
End Sub
Private Sub OptionButtonl_Enter() TraceFocus
End Sub
Private Sub 0ptionButton2_Enter() TraceFocus
End Sub
Private Sub ScrollBarl_Enter() TraceFocus
End Sub
Если вы запустите этот код на выполнение, то сможете, выделяя в любой последовательности элементы управления на форме, наблюдать в окне элемента ListBox имя активного элемента и его индекс.
Error
Инициируется, когда элемент управления обнаруживает какую-либо ошибку и не может возвратить информацию об ошибке в вызывющую программу.
Синтаксис
Для элементов MultiPage:
Private Sub object_Error( index As Long, ByVai Number As Integer, ByVai Description As MSForms.Returnstring, ByVai SCode As SCode, ByVai Source As String, ByVai HelpFile As String, ByVai HelpContext As Long, ByVai CancelDisplay As MSForms.ReturnBoolean)
Для других элементов управления:
Private Sub object_Error( ByVai Number As Integer, ByVai Description As MSForms.Returnstring, ByVai SCode As SCode, ByVai Source As String, ByVai HelpFile As String, ByVai HelpContext As Long, ByVai CancelDisplay As MSForms .ReturnBoolean)
Параметры (все обязательные):
index	Индекс страницы в MultiPage, связанной с этим событием.
Number	Определяет уникальное значение, используемое элементом управления для идентификации ошибки.
Description	Текстовое сообщение об ошибке.
SCode	Определяет код OLE-состояние для ошибки. Младшие 16 битов указывают значение, которое идентично аргументу Number.
Source	Строка, определяющая элемент управления, который инициализировал это событие.
HelpFile	Определяет полное имя для Help-файла с описанием ошибки.
856
Приложение Е
HelpContext	Определяет контекстный ID в Help-файле для указания раздела с описанием ошибки.
CancelDisplay	Определяет, отображать ли error-строку в окне функции MsgBox.
Код для события Error определяет, как элемент управлёния должен реагировать на ошибочную ситуацию.
Exit
Инициируется, когда с элемента управления снимается выделение.
Синтаксис
Private Sub object_Exit( ByVai Cancel As MSForms.ReturnBoolean)
Параметр (обязательный):
Cancel	Статус события. False обозначает, что элемент управления должен обрабатывать событие (по умолчанию). True обозначает, что приложение обрабатывает событие и фокус должен оставаться у текущего элемента управления.
Key Dow, Key Up
Инициируется при нажатии (отпускании) какой-либо клавиши в тот момент, когда форма имеет фокус.
Синтаксис
Private Sub object_KeyDown( ByVai KeyCode As MSForms.Retumlnteger, ByVai Shift As fmShiftState)
Private Sub ob/ect_KeyUp( ByVai KeyCode As MSForms.Retumlnteger, ByVai Shift As fmShiftState)
Параметры:
KeyCode	Обязательный. Целое, представляющее код клавиши, которая была нажата или освобождена.
Shift	Обязательный. Состояние SHIFT, CTRL и ALT.
Установки для Shift:
Константа	Значение	Описание
fmShiftMask	1	Была нажата SHIFT.
fmCtrlMask	2	Была нажата CTRL.
fmAltMask	4	Была нажата ALT.
Пример
Следующий пример отслеживает установки свойств CurLine и CurX в многострочном элементе TextBox. Эти настройки изменяются в событии KeyUp, когда пользователь выполняет ввод в свойство Text, перемещает место вставки и расширяет выбор, используя клавиатуру.
Для того чтобы использовать этот пример, выполните следующее:
Скопируйте этот код в область Declarations формы.
Добавьте в форму одно большое текстовое окно (TextBox) с именем TextBoxl.
События объектов UserForm
857
Добавьте три элемента управления TextBox с именами TextBox2, TextBox3 (в одном столбце).
Private Sub TextBoxl.KeyUp(ByVai KeyCode As _
MSForms.Returninteger, ByVai Shift As Integer)
TextBox2.Text = TextBoxl.CurLine ' текущая строка (начиная с 0) в окне TextBoxl
TextBox3.Text = TextBoxl.CurX ' текущая позиция курсора вставки по горизонтали End Sub
Private Sub UserForm_Initialize()
TextBoxl.MultiLine = True
TextBoxl.Text = "Вводите текст сюда. Используйте CTRL + " _ "ENTER для начала новой строки." End Sub
KeyPress
Инициируется, когда пользователь нажимает алфавитно-цифровую клавишу.
Синтаксис
Private Sub object_KeyPress( ByVai KeyANSI As MSForms.Returninteger)
Параметр (обязательный):
KeyANSI	Целое значение, которое представляет стандартный цифровой ANSI-код.
Пример
Следующий пример использует событие KeyPress для копирования нажатий-клавиш из одного элемента TextBox в другой. Пользователь выполняет ввод в соответствующим образом отмеченное текстовое окно.
Для того чтобы использовать этот пример, скопируйте код в часть Declarations формы. Поместите на форму два элемента управления TextBox с именами TextBoxl и TextBox2.
Private Sub TextBoxl_KeyPress(ByVai KeyAscii As _
MSForms.Returninteger)
TextBox2.Text = TextBox2.Text & Chr(KeyAscii)
1 Чтобы обрабатывать комбинации клавиш клавиатуры (используя
1 SHIFT, CONTROL, OPTION, COMMAND и какую-либо другую клавишу),
' или TAB или ENTER, используйте событие KeyDown или KeyUp.
End Sub
Private Sub UserForm_Initialize() Move 0, 0, 570, 380
TextBoxl.Move 30, 40, 220, 160
TextBoxl.MultiLine = True
TextBoxl.Wordwrap = True
TextBoxl.Text = "Ввести текст сюда."
TextBoxl.EnterKeyBehavior = True
TextBox2.Move 298, 40, 220, 160
TextBox2.MultiLine = True
TextBox2.Wordwrap = True
TextBox2.Text = "Введенный текст копируется сюда."
TextBox2.Locked = True
End Sub
858
Приложение Е
Layout
Инициируется при изменении размера элемента Frame (или MultiPage).
Синтаксис
Для элемента MultiPage:
Private Sub object_Layout( index As Long)
Для других элементов управления:
Private Sub object_Layout( )
Параметр:
Index	Обязательный. Индекс страницы в MultiPage, которая изменила размер.
MouseDown, MouseUp
Инициируются при щелчке мышью. MouseDown — пользователь нажимает на клавишу мыши, MouseUp — отпускает клавишу.
Синтаксис:
Для элементов MultiPage и TabStrip:
Private Sub object_MouseDown( index As Long, ByVai Button As fmButton,
ByVai Shift As fmShiftState, ByVai X As Single, ByVai Y As Single)
Private Sub object_MouseUp( index As Long, ByVai Button As fmButton, ByVai Shift As fmShiftState, ByVai X As Single, ByVai У As Single)
Для других элементов управления:
Private Sub object_MouseDown( ByVai Button As fmButton, ByVai Shift As fmShiftState, ByVai X As Single, ByVai Y As Single)
Private Sub object_MouseUp( ByVai Button As fmButton, ByVai Shift As fmShiftState, ByVai X As Single, ByVai Y As Single)
Параметры (все обязательные):
index	Индекс страницы или вкладки в MultiPage или TabStrip с определенным событием.
Button	Целое значение, которое определяет, какая кнопка мыши вызвала событие.
Shift	Состояние SHIFT, CTRL и ALT.
X, Y	Горизонтальное или вертикальное положение (в точках) от левого или верхнего края формы, Frame или Page.
Установки для Button:
Константа	Значение	Описание
FmButtonLeft	1	Была нажата левая кнопка.
FmButtonRight	2	Была нажата правая кнопка.
FmButtonMiddle	4	Была нажата средняя кнопка.
События объектов UserForm
859
Установки для Shift:
Значение	Описание
1	Была нажата SHIFT.
2	Была нажата CTRL.
3	Были нажаты SHIFT и CTRL.
4	Была нажата ALT.
5	Были нажаты ALT и SHIFT.
6	Были нажаты ALT и CTRL.
7	Были нажаты ALT, SHIFT и CTRL.
Вы можете идентифицировать индивидуальные модификаторы клавиатуры, используя следующие константы:
Константа	Значение	Описание
fmShiftMask	1	Маска для обнаружения SHIFT.
fmCtrlMask	2	Маска для обнаружения CTRL.
fmAltMask	4	Маска для обнаружения ALT.
MouseMove
Инициируется при перемещении мыши.
Синтаксис
Для элементов MultiPage и TabStrip:
Private Sub object_MouseMove(index As Long, By Vai Button As fmButton ByVai Shift As fmShiftState, ByVai X As Single, ByVai Y As Single)
Для других элементов управления:
Private Sub ot>y'ect_MouseMove(ByVal Button As fmButton, ByVai Shift A fmShiftState, ByVai X As Single, ByVai Y As Single)
Параметры (все обязательные):
index	Индекс страницы или вкладки в MultiPage или TabStrip, ассоцииро ванной с этим событием.
Button	Целое значение, которое определяет состояние кнопок мыши.
Shift	Определяет состояние SHIFT, CTRL и ALT.
X, Y	Горизонтальное или вертикальное положение (в точках) от левого или верхнего края элемента управления.
Настройки
Аргумент index определяет, на какой странице или вкладке щелкнули khoi кой мыши. Значение -1 обозначает, что пользователь не щелкнул ни на како странице или вкладке.
Настройки для Button:
Значение	Описание
0	Никакая кнопка не нажата
1	Нажата левая кнопка
860
Приложение Е
Значение	Описание
2	Нажата правая кнопка
3	Нажаты правая и левая кнопки
4	Нажата средняя кнопка
5	Нажаты средняя и левая кнопки
6	Нажаты средняя и правая кнопки
7	Нажаты все три кнопки
Настройки для Shift:
Значение	Описание
1	Была нажата клавиша SHIFT
2	Была нажата клавиша CTRL
3	Были нажаты клавиши SHIFT и CTRL
4	Была нажата клавиша ALT
5	Были нажаты клавиши ALT и SHIFT
6	Были нажаты клавиши ALT и CTRL
7	Были нажаты клавиши ALT, SHIFT и CTRL
Вы можете идентифицировать индивидуальные модификаторы клавиатуры, используя следующие константы:
Константа	Значение	Описание
fmShiftMask	1	Маска для обнаружения SHIFT.
fmCtrlMask	2	Маска для обнаружения CTRL.
fmAltMask	4	Маска для обнаружения ALT.
Следующий пример демонстрирует операцию перетаскивания элементов списка из одного окна списка (ListBox) в другое (элементы из окна-источника не удаляются), используя объект DataObject для содержимого перетаскиваемого текста. Этот пример кода использует методы SetText и StartDrag в событии MouseMove для реализации операции перетаскивания.
Для того чтобы использовать этот пример, скопируйте код в область Declarations формы. Поместите на форму два элемента управления типа ListBox с именами ListBoxl и ListBox2. Также необходимо добавить элементы выбора во второе окно списка (ListBox).
Private Sub ListBox2_BeforeDragOver(ByVai Cancel As _
MSForms.ReturnBoolean, ByVai Data As _
MSForms.DataObject, ByVai X As Single, _
ByVai Y As Single, ByVai DragState As Long, _
ByVai Effect As MSForms.ReturnEffect, _
ByVai Shift As Integer)
 Cancel = True Effect = 1 End Sub
Private Sub ListBox2_BeforeDropOrPaste(ByVai _
Cancel As MSForms.ReturnBoolean, _
1 f
События объектов UserForm
861
ByVai Action As Long, ByVai Data As _ , MSForms.DataObject, ByVai X As Single, _
ByVai Y As Single, ByVai Effect As _
MSForms.ReturnEffeet, ByVai Shift As Integer)
Cancel = True
Effect = 1
ListBox2.Additem Data.GetText
End Sub
Private Sub ListBoxl_MouseMove(ByVai Button As _ Integer, ByVai Shift As Integer, ByVai X As _ Single, ByVai Y As Single)
Dim MyDataObject As DataObject If Button = 1 Then
Set MyDataObject = New DataObject
Dim Effect As Integer
MyDataObject.SetText ListBoxl.Value
Effect = MyDataObject.StartDrag End If
End Sub
Private Sub UserForm_lnitialize() For i = 1 To 10
ListBoxl.Additem "Элемент выбора " & (ListBoxl.ListCount + 1) Next i
End Sub
Removecontrol
Инициируется при удалении элемента управления из контейнера.
Синтаксис
Для элемента MultiPage:
Private Sub object_RemoveControl( index As Long, Ctrl As Control)
Для других элементов управления:
Private Sub object_RemoveControl( Ctrl As Control)
Параметры (все обязательные):
index	Индекс страницы в MultiPage, которая содержала удаленный элемент управления.
Ctrl	Удаленный элемент управления.
Scroll
Инициируется при изменении положения ползунка линейки прокрутки.
Синтаксис
Для элемента ScrollBar:
Private Sub object_Scroll()
Для элемента MultiPage:
Private Sub object Scroll( index As Long, ActionX As fmScrollAction, ActionY As fmScrollAction, ByVai ReguestDx As Single, ByVai RequestDy As Single, ByVai ActualDx As MSForms.Returnsingle, ByVai ActualDy As MSForms.Returnsingle)
Для элемента Frame:
Private Sub object_Scroll( ActionX As fmScrollAction, ActionY As fmScrollAction, ByVai RequestDx As Single, ByVai RequestDy As Single, ByVai ActualDx As MSForms.Returnsingle, ByVai ActualDy As
MSForms.Returnsingle)
862
Приложение Е
Параметры (все обязательные):
index	Индекс страницы в MultiPage, ассоциированной с этим событием.
| ActionX	Действие, которое произошло в горизонтальном направлении.
1 ActionY	Действие, которое произошло в вертикальном направлении.
RequestDx	Расстояние (в точках), на которое необходимо переместить линейку прокрутки в горизонтальном направлении.
RequestDy	Расстояние (в точках), на которое необходимо переместить линейку прокрутки в вертикальном направлении.
ActualDx	Расстояние (в точках), на которое линейка прокрутки переместилась в горизонтальном направлении.
\ActualDy	Расстояние (в точках), на которое линейка прокрутки переместилась в вертикальном направлении.
Настройки для ActionX и ActionY-.
Константа	Значение	Описание
FmScrollActionNoChange	0	Никакого изменения не произошло.
fmScrollActionLineUp	1	Небольшое расстояние по направлению вверх на вертикальной линейке прокрутки; небольшое расстояние влево на горизонтальной линейке прокрутки. Перемещение эквивалентно нажатию клавиш со стрелками вверх или влево на клавиатуре для перемещения линейки прокрутки.
fmScrollActionLineDown	2	Небольшое расстояние вниз на вертикальной линейке прокрутки; небольшое расстояние вправо на горизонтальной линейке прокрутки. Перемещение эквивалентно нажатию клавиш со стрелками вниз или вправо на клавиатуре для перемещения линейки прокрутки.
fmScrollActionPageUp	3	Перемещение на одну страницу вверх на вертикальной линейке прокрутки; перемещение на одну страницу влево на горизонтальной линейке прокрутки. Перемещение эквивалентно нажатию Page Up на клавиатуре для перемещения линейки прокрутки.
fmScrollActionPageDown t t	4	Перемещение на одну страницу вниз на вертикальной линейке прокрутки; перемещение на одну страницу вправо на горизонтальной линейке прокрутки. Перемещение эквивалентно нажатию Page Down на клавиатуре для перемещения линейки прокрутки.
fmScrollActionBegin	5	Верх вертикальной линейки прокрутки; левый край горизонтальной линейки прокрутки.
События объектов UserForm
863
Константа	Значение	Описание
fmScrollActionEnd	6	Низ вертикальной линейки прокрутки; правый край горизонтальной линейки прокрутки.
fmScrollActionProperty-Change	8,	Значение свойства ScrollTop или ScrollLeft изменилось. Направление и величина перемещения зависят от того, какое свойство было изменено, и от нового значения свойства.
fmScrollActionControl- Request	9	Элемент управления указал своему контейнеру выполнить прокрутку. Величина перемещения зависит от конкретного элемента управления и контейнера.
fmScrollActionFocus- Request	10	Пользователь перешел к другому элементу управления. Величина перемещения зависит от размещения выбранного элемента управления и обычно в результате выбранный элемент управления перемещается так, чтобы он был полностью видимым для пользователя.
Пример
Следующий пример демонстрирует автономную линейку прокрутки (ScrollBar) и представляет изменение в ее значении, когда пользователь перемещает ползунок линейки прокрутки. Пользователь может перемещать ползунок линейки, щелкая на любой стрелке на концах элемента управления, щелкая в зоне между ползунком и любой стрелкой или перетаскивая ползунок. Когда пользователь перетаскивает ползунок линейки прокрутки, событие Scroll отображает сообщение, указывающее, что пользователь выполнил прокрутку для получения нового значения.
Для того чтобы использовать этот пример, скопируйте код в область Declarations формы. Поместите на форму ScrollBar с именем ScrollBarl и элемент управления типа Label с именем Labell.
Private Sub UserForm_Initialize()
' минимальное значение для ScrollBarl.Value:
ScrollBarl.Min = -200	’	(
1 максимальное значение для ScrollBarl.Value: ScrollBarl.Max = 200
' текущее значение для ScrollBarl.Value: ScrollBarl.Value = 200
End Sub
Private Sub ScrollBarl_Scroll()
Labell.Caption = "Текущее значение ScrollBar : " & ScrollBar1.Value End Sub
SpinDown, SpinUp
Событие SpinDown инициируется при щелчке на стрелке «вниз» (или «влево») кнопки счетчика. Событие SpinUp инициируется при щелчке на стрелке «вверх» (или «вправо») кнопки счетчика.
864
Приложение Е
Синтаксис
Private Sub objесt_SpinDown( )
Private Sub object_SpinUp( )
Пример
Следующий пример демонстрирует временной интервал между последовательными событиями Change, SpinUp и SpinDown, которые возникают, когда пользователь удерживает нажатой кнопку мыши для изменения значения SpinButton или ScrollBar.
В этом примере пользователь выбирает настройку задержки, затем щелкает и удерживает нажатой любую часть SpinButton. События SpinUp и SpinDown при инициализации записываются в ListBox.
Для того чтобы использовать этот пример, скопируйте код в область Declarations формы. Создайте на форме:
1.	SpinButton с именем SpinButtonl.
2.	Два элемента управления OptionButton с именами OptionButtonl и OptionBut-ton2.
3.	ListBox с именем ListBoxl.
Dim Eventcount As Long 'счетчик событий
Private Sub Resetcontrol()
ListBoxl.Clear
Eventcount = 0
SpinButtonl.Value = 5000
End Sub
Private Sub UserForm_Initialize() ' инициализация формы
1 установка минимального и максимального значений
1 свойства Value элемента SpinButtonl
SpinButtonl.Min = 0
SpinButtonl.Max = 10000
SpinButtonl.Delay = 50
' заголовки для переключателей:
OptionButtonl.Caption = "задержка 50 миллисекунд "
OptionButton?.Caption = "задержка 250 миллисекунд "
' инициализация переключателя OptionButtonl.Value = True
End Sub	•->
Private Sub OptionButtonl_Click()
SpinButtonl.Delay = 50
ResetControl
End Sub
Private Sub OptionButton2__Click()
SpinButtonl.Delay = 250
ResetControl	,
End Sub
Private Sub SpinButtonl_SpinDown()
Eventcount = Eventcount + 1 ListBoxl.Additem Eventcount End Sub
Private Sub SpinButtonl_SpinUp()	'
Eventcount = Eventcount +1	,	.
События объектов UserForm
865
ListBoxl.Additem Eventcount
End Sub
Zoom
Инициируется при изменении свойства Zoom.
Для элемента Frame:	v
Private Sub object_Zoom( Percent As Integer)
Для элемента MultiPage:
Private Sub object_Zoom( index As Long, Percent As Integer)
Параметры (все обязательные):
index	Индекс страницы в MultiPage, ассоциированной с этим событием.
Percent	Процентное выражение изменения масштаба формы. Диапазон допустимых значений от 10% до 400%.
Пример
Следующий пример использует событие Zoom для оценки нового значения свойства Zoom и добавляет линейки прокрутки в форму в соответствующих случаях. Этот пример использует Label для отображения текущего значения. Пользователь задает размер для формы, используя SpinButton, и затем щелкает Command-Button для установки значения в свойстве Zoom.
Для того чтобы использовать этот пример, скопируйте код в область Declarations формы. Поместите на форму:
	Label с именем Label 1.
	SpinButton с именем SpinButtonl.
	CommandButton с именем CommandButtonl.
	Другие элементы управления, помещенные рядом с краями формы.
Private Sub UserForm_Initialize() ' инициализация формы
' минимальное/максимальное значение
' свойства элемента SpinButtonl:
SpinButtonl.Min = 10
SpinButtonl.Max = 400
' начальное значение свойства элемента SpinButtonl: SpinButtonl.Value = 100
' заголовок метки:
Labell.Caption = "SpinButton-значение: " & SpinButtonl.Value
CommandButtonl.Caption = "Масштабировать форму"
End Sub	'
Private Sub UserForm_Zoom(Percent As Integer) ' обработка события изменения размеров формы
Dim MyResult As Double
If Percent > 99 Then
ScrollBars = fmScrollBarsBoth
ScrollLeft = 0
ScrollTop = 0
MyResult = Width * Percent / 100
866
Приложение Е
Scrollwidth = MyResult
MyResult = Height * Percent / 100
ScrollHeight = MyResult
Else
ScrollBars = fmScrollBarsNone
ScrollLeft =0	1	e
ScrollTop = 0
End If
End Sub
Private Sub CommandButtonl_Click()
' масштабирование формы
Zoom = SpinButtonl.Value
End Sub	,
Private Sub SpinButtonl_SpinDown()
Labell.Caption = "SpinButton-значение: " 5 SpinButtonl.Value End Sub
Private Sub SpinButtonl_SpinUp()
Labell.Caption = "SpinButton-значение: " 5 SpinButtonl.Value End Sub
Предметный указатель
А Abs(N)	*	152
Accelerator	346
Activate	232, 234, 338, 513
ActiveCell	227
ActiveChart	227
ActiveControl	336
ActiveDocument	229
ActivePrinter	229
ActiveSheet	227
ActiveWindow	229
Add	398
AddCallout	251, 253-254
AddCanvas	251
AddComment	254
AddConnector	253-254
AddControl	348
AddCurve	252-253, 255
AddDiagram	252-253, 255
AddForm	253
Addins	245-246, 429
AddLabel	252-253, 255
AddLine	252, 254-255
AddMediaObject	255
AddOLECon tr ol	252
AddOLEObject	252, 254-255
AddPicture	252, 254-255
AddPlaceholder	255
AddPolyline	252, 254-255
Address	227
AddShape	256
AddTable	256
AddTextbox	253-254, 256
AddTextEffect	253-254, 256
AddTitle	256
After Update	348
Anchor	462
AND в SQL-инструкции SELECT	580	
Application	224-225
ASC в SQL-инструкции SELECT	584	
Asc(S)	153
Atn(N)	152
AutoUpdate	463
AVG в SQL-HHCTpyKiiHHSELECT	585-586	
В
BackColor BeforeClose BeforeDoubleClick
336, 343, 346
512
514
BeforePrint	519
BeforeUpdate	348
BETWEEN в SQL-инструкции SELECT 580	
Bookmark	225, 246
Boolean	96
BottomRightCell	463
Break	375
ByRef	216
Byte	94-95
c	
Calculate	232, 518
Call Stack	375
Cancel	346, 618
Caption	336, 346
CBool(N)	154
CByte(E)	154
CCur(E)	154
CDate(E)	154
CDbl(E)	154
Cells	227
Change	348, 356, 515
Characters	246, 431
Chart	224
Chartobjects	246
Charts	227, 245
ChDir	302
ChDrive	302
CheckBox	344
CheckSpelling	234
Chr(N)	153
Cint(E)	154
Clear	233, 420
ClearContents	420
ClearFormats	420
ClearNotes	420
Click	338, 348
CLng(E)	154
Close	233-234
Code Window	55
ComboBox	344
CommandButton	345
Comments	246
Const	110
Controls	336
ControlTipText	346
Copy	337, 409, 420
Cos(N)	152
Count	227, 229
COUNT в SQL-инструкции SELECT	585	
868
Программирование на VBA 2002
CreateRelation	599
CreateTableDef	599
Create Workspace	597
Critical	149
CSng(E)	154
CStr(E)	154
CurDir	303
Currency	z	94, 96, 168
Cut	337, 420
CVar(E)	154
Cycle	336
D	
Date	155
DateAdd	155
DateDiff	156
DatePart	156
DateSerial	156
DateValue	156
Day	155
dbDriverComplete	614
dbDriverCompleteRequired	614
dbDriver N oPr ompt	614
dbDriverPrompt	614
DBEngine.DefaultPassword	596
DBEngine.DefaultType	595
DBEngine.DefaultUser	596
DBEngine.IniPath	596
DBEngine.LoginTimeout	596
DBEngine. V ersion	596
DblClick	338, 343. 348
dbOpenDynamic	600
dbOpenDynaset	600
dbOpenForwardOnly	600
dbOpenSnapshot	600
dbOpenTable	600
dbRun Async	614
dbUseJet	597
dbUseODBC	597
DDEExecute	487
Deactivate	338, 513
Debugging	61
Default	346
Delete	234
DESC в SQL-инструкции SELECT	584	
Dialogs	246
Dim	100
dimension (измерение)	287
Dir	303
Do While	273
Do...Loop While	277
Document	225, 246
Documentchange	529
Double	94
Dynamic data exchange (DDE)	482
E
Empty	118
Enabled	336, 346
End	209
End Function *	178
End Sub	178
EndKey	437
Enter	348
Error	349
Exclamation	149
Exit	348
Exp(N)	152
F
FileCopy	•	303
FileDateTime	303
FileLen	303
FindFirst	610
FindLast	610
FindNext	610
FindPrevious	610
Fix(N)	152
Fixed	168
Font	225,	336
For Each...Next	261
For...Next	261
ForeColor	336,	346
Format	319
FORMAT в SQL-инструкции SELECT 582
Format(E, S)	153
FormatCurrency	171
FormatDateTime	171
FormatNumber	171
FormatPercent	171
Formula	227,	418
Frame	345
Function	178
G
General Date	167
General Number	168
GetAttr	303
GetOpenFilename	313
GetOpenFileName	303
GetSaveAsFilename	303, 313
GoTo	234
GROUP BY в SQL-инструкции SELECT 587
H
HAVING в SQL-инструкции SELECT 587
Height	463
Hex(N)	153
Предметный указатель
869
Hide HomeKey host-приложение Hour
l-J
If...Then...ElseIf	195
Image	345
Immediate Window	375
IN в SQL-инструкции SELECT	580
Index	227
Information	149
Initialize	339
InputBox	116, 150
InsertAfter	440
InsertBefore	440
InsertParagraphAfter	440
InsertParagraphBefore	440-441
InStr	157
InStrRev	157
Int	153
Int(N)	152
Integer	94
IS NOT NULL в SQL-инструкции	
SELECT	581
IS NULL в SQL-инструкции	
SELECT	580
Justify	233
К	
KeyDown	349
KeyPress	349
KeyUp	349
Kill	303, 329
337
437
55-56, 59, 64-65
155
LTrim	157
M	
Max	347
MAX в SQL-инструкции SELECT	585-586
Medium Date	167
Medium Time	167
Microsoft DAO	598
Microsoft Jet	593
Microsoft Jet workspace	594
Mid	157
Min	347
MIN в SQL-инструкции	
SELECT	585-586
Minute	155
MkDir	303
Modules (Модули)	52
Month	155
MouseDown, MouseUp	349
MouseMove	349
Move	409
MultiPage	345
L
Label	344
Layout	349
LCase	157
Left	157, 463
Len	157
LenTrim	179
LIKE в SQL-инструкции SELECT	580
Line	463
LinkFormat	463
List	347
ListBox	1	344
Load	339
Locals Window	375
Log(N)	152
Long	94-95
Long Date	1	167
Long Time	167
N		
Name	225, 227, 229, 303,	
	319, 347, 409, 463	
Names	>		419
New		529
NewW orkbook		520
Next		262
NOT BETWEEN в SQL-инструкции		
SELECT		581
NOT IN в SQL-инструкции SELECT		581
NOT LIKE в SQL-инструкции		
SELECT		581
NOT в SQL-инструкции SELECT		580
Now		155
Null		118
NumberFormat		419
0		
Object		463
Oct(N)		153
ODBCDirect		593
ODBCDirect workspace		594
Offset		-415
OLEFormat		463
On/Off		163
OnAction		463
OnKey		520,522
OnTime		525, 534
On Window		521
Open	397, 510, 527	
870
Программирование на VBA 2002
Option Base	287
Option Explicit	108
OptionButton	344
OR в SQL-инструкции SELECT	580
ORDER BY в SQL-инструкции
SELECT	584
RmDir	308
Rnd(N)	152
RowSource	347
RTrim	157
Run	233, 235
runtime-ошибки	88
s
Paragraph	225, 246, 432
Paste	337
Path	227, 229
Percent	1	168
PopulatePartial	599
PrintForm	337
Printout	234
Private	287, 291
Progid	463
project (проект)	52
Project Explorer (Окно	проекта)	55
Properties Window (Ok	но свойств)	55
Public	291
Q
Question
Quick Watch
149
375
Quit
R
Range Recordset. AddN ew Recordset.BOF Recordset.CancelUpdate Recordset.Close Recordset.Delete Recordset.Edit Recordset.EOF Recordset.FindFirst R ecordset. FindLast Recordset.FindN ext Recordset.FindPrevious R ecordset. MoveFirst Recordset. Mo veLast Recordset. MoveNext Recordset.MovePrevious Recordset.NoMatch Recordset.RecordCount Recordset. Seek Recordset.Update Repaint Reset Resize
RGB(N, N, N) Right
225, 229, 437
602
602
602
602
602
602
602
602
602
602
602
602
602
602
602
602
602
602
602
337
375
339, 343, 416
154
157
Save	233, 235	
SaveAs		233, 235
SaveCopyAs		400
Saved		228-229
Scientific		168
ScrollBar		345
Second		155
Sections		246
Select		233, 235
Selected		347
Selection	228-229, 437	
SelectionChange		517, 520
SendKeys		233
Sentences		432
SetAttr		303
Sgn(N)		152
Shadow		463
Sheets	>		228, 407
Shell		483
Short Date		167
Short Time		167
Show		337
Sin(N)		152
Single		94
Space		157
SpinButton		345
SpinDown, SpinUp		349
SQL (Structured Query Language)		547
SQL-инструкция SELECT		574
Sqr(N)		152
Standard		168
Static		287
Static		291
StatusBar		228-229
Step		262
Step Into (шаг с заходом)		375, 380
Step Out		375
Step Over		375
Stop		378
Str(N)		154
StrComp		157
StrConv		157
String		96, 157
Style		225
Styles		246
Sub		178
Предметный указатель
871
SUM в SQL-инструкции SELECT Synchronize	585-586 599
т	
Tabindex	347
Table	225
TableOfContents	225
TabStop	347
TabStrip	345
Tan(N)	152
Template	225, 429
Templates	246, 429
Terminate	339, 340
TextBox	344
ThisWorkBook	228
Time	155
Timer	156
TimeSerial	156
TimeValue	156
Toggle Breakpoint	375
Toggle Folders (Папки)	55
ToggleButton	345
Top	463
TopLeftCell	464
Trim	158
True/False	168
Type	228, 464
TypeParagraph	440
u	
UBound	296
UCase	158
Underline	412
Unload	339
V
Val(S)	154
Value	228, 348, 418
Variant	97
vbAbort	150
vbAbortRetrylgnore	149
vbAlias	305
vbApplicationModal	149
vbArchive	305
vbBinaryCompare	161
vbCancel	150
vbCr	165
vbCritical	149
vbCrLf	165
vbDatabaseCompare	161
vbDefaultBu tton 1	149
vbDefaultButton2	149
vbDefaultButton3	149
vbDefaultButton4	149
vbDirectory	305
vbExclamation	149
vbGeneralDate	172
vbHidden	1	305
vblgnore	150
vblnformation	149
vbLf	165
vbLongDate	173
vbLongTime	173
vbMsgBoxHelpButton	149
vbNewLine	165
vbNo	150
vbNormal	305
vbOK	150
vbOKCancel	150
vbOKOnly	150
vbQuestion	150
vbReadOnly	305
vbRetry	i	150
vbRetryCancel	150
vbShortDate	173
vbShortTime	173
vbSystem	305
vbSystemModal	150
vbTab	166
vbTextCompare	161
vbVolume	305
vbYes	150
vbYesNo	150
vbYesNoCancel	150
View Code (Программа)	55
View Object (Объект)	1	55
Visible	228-229, 348, 464	
Volatile	233
w	
Watch Window	375
wdCell	435
wdCharacter	435
wdCollapseDirection	439
wdCollapseEnd	439
wdCollapseStart	439
wdColumn	437
wdColumn	435
wdDialogFileOpen	319
wdDialogFileSaveAs	319
wdExtend	437
wdFormatDocument	427
wdFormatDOSText	427
wdFormatDOSTextLineBreaks	427
wdFormatEncodedText	427
wdFormatFiltere dHTML	427
872
Программирование на VBA 2002
wdFormatHTML	427	Worksheets	'	228,	246
wdFormatRTF	427	Workspace		597
wdFormatTemplate	427	Workspaces		612
wdFormatText	427			
wdFormatTextLineBreaks	427	X		
wdFormatUnicodeText	427	xlExclusive		403
wdFormatWebArchive	427	xlLocalSessionChanges		403
wdGoTo Absol ute	438	xlNoChange		403
wdGoToBookmark	438	xlOtherSessionChanges		403
wdGoToComment	438	xlShared		403
wdGoToDirection	438	xlUnderlineStyle		412
wdGoToField	438	xlUnderlineStyleDouble		412
wdGoToFirst	438	xlUnderlineStyleNone		412
wdGoToHeading	438	xlUnderlineStyleSingle		412
wdGoToItem	438	xlUnderlineStyleDoubleAccounting		412
wdGoToLast	438	xlUnderlineStyleSingleAccounting		412
wdGoToLine	439	xlUserResolution		403
wdGoToNext	438	xlWBATChart		398
wdGoToObject	438	xlWBATExcel4IntlMacroSheet		398
wdGoToPage	439	xlWBATWorksheet		398
wdGoToPercent	439			
wdGoToPrevious	438	Y-Z		
wdGoToRelative	438	Year		155
wdLine	435, 437	Yes/No		168
wdMainTextStory	431	Zoom		349
wdMove	437			
wdMovementType	437	A		
wdParagraph	435			
wdPrimary Footer S tory	431	автоматический отступ		84
wdPrimaryHeaderStory	431	(auto indenting)		
wdRow	435, 437	агрегирующая функция		585
wdS a veFormat	427	апплет (applet)		450
wdSection	435	аргумент (argument)	83, 85	
wdSentence	435	аргумент InitialFilename		331
wdStory	435, 437	аргумент обязательный (required)		194
wdStoryType wdTable	431 436	атрибут - Archive		541 304
wdTypeDocument wdTypeTemplate	319 319	- Directory - Hidden		304 304
wdUnits	437	- Read-Only	304, 308	
wdWord	436	- System		304
Weekday	155	- Volume Label		305
WeekdayName WHERE в SQL-инструкции	155	- файла Normal r"		304
SELECT	579-580	Б		
Width	464	бесконечный цикл (infinite loop)		261
Window	225	библиотеки динамической компоновки		
Windows	246	(Dynamic link libraries, DLL)		496
Words	431	блок кода обработки прерывания		388
Workbook	225, 396	блок (block) оператора		193
WorkbookBeforePrint	519	булевы (Boolean) значения		96
WorkbookBeforeSave	519			
Workbooks	228, 246	В		
Worksheet	225, 396	ветвь (branch) кода		190
Предметный указатель
873
вложение (nesting) циклов	279
вложение операторов (nesting)	197
вложенный запрос в инструкции
SELECT	588
внешний ключ	549
внутренних констант	*
(intrinsic constants)	' 114
входные данные (input)	116
вызов (calling)	145
выражение (expression)	118
вычисляемая информация	542
вязное отношение	548
Д-З	
действительные (real) числа	95
динамический (dynamic) массив	286
директива Option Compare	132
директивы компилятора (compiler	
directives)	109
запрос к базе данных	547
знак &	141
И
идентификатор (identifier)	98
идентификационный номер задачи (task	
identification number)	483
извлечение информации	573
именованные аргументы (named arguments) функций	148
именованные константы (named constants)	110
именованный формат (named format)	167
индекс (subscript или index) элемента	284
информационное сообщение (information	
message)	207
исключающим “ИЛИ” (exclusive or)	138
исходный код (source code)	42, 52
итерация (iteration) цикла	260
К каталоги (directories)	г	302
клиентская часть программного обеспечения	639
ключевое слово Binary	132
- - By Vai	216
	Dim	287
- - Is	203
	Loop	273
— Optional	194
	Preserve	y	291
— Public	287
- - Until	271
- - While	271
ключ отношения	548
коллекция Connections	612
коллекция Workspaces	597
коллекция (collection) объектов	241
комментарий (comment)	73
компилятор Option Base	286
компиляция (compiling)	87
конкатенация (concatenate) конкатенация (concatenation)	96
строк	139
константа (constant)	110
константа wdDialogFileopen	, 319
контейнер (container)	242
кортеж критическое предупредительное	541
сообщение (Critical Warning message)	207
л-м	
литеральные константы	
(literal constants)	110
логическое выражение	
(logical expression)	119, 136
макрокоманды	
(macro-commands)	24
макрос (macro) маркеры изменения размеров	24, 81
(sizing handles)	350
массив (array)	284
- статический (static)	286
метка строки (line label)	204
метод (method)	187, 222
- Activate	399,	408, 425
- Add	408, 424
- Cells	412
- Close	404, 428
- Collapse	439
- Copy	442
- CreateProperty	599
- CreateQueryDef	599
- CreateWorkspace	597
- Cut	441
- DDEInitiate	485
- DDETerminate	485
- Delete	410, 442
- Display	319
- Execute	599
- Expand	436
- GetOpenFilename	314, 329
- GetSaveAsFilename	317
- GoTo	438
874
Программирование на VBA 2002
- InsertParagraphAfter	441
- MakeReplica	599
- Open	423
- OpenConnection	613
- OpenRecordset	599-600
- Paste	442
- Range	411
- Save	400, 426
- SaveAs	401
- SetRange	434
- TypeText	439
- Volatile	187
многомерные (multi-dimensional) массивы	285
модальными (modal) приложениями	337
модель данных	541
модификация данных	573
f н надстройка (add-in)	423
надстрочные (superscript) символы	93
неопределенные циклы (indefinite loops)	260
нечеткий поиск (fuzzy search)	132
неявное объявление переменной (implicit	
variable declaration)	100
номер строки (line number)	204
нормализованное отношение	550
обеспечение целостности данных	573
область действия (scope) 	процедурного уровня	99, 104
(procedure-level scope) обработчик событий	105
(event handler)	503
объект Connection	612
- Err	388
- Database	597
- DBEngine	594
- Recordset	599
- Selection	436
- UserForm	334
- Workspace	612
объектная модель (object model) объектное выражение	243
(object expression)	237
объектное отношение объектно-ориентированное	548
программирование (obj ect-oriented	
programming, OOP) обязательный аргумент	221
(required argument)	116
ограниченные ключевые слова
(restricted keywords)	99
одномерный (single-dimensional)	
массив	284
оператор (statement)	74
- And	136
- AppActivate	484
- ChDir	324
- ChDrive	325
- Declare	497
- Dim	291
- Do	270
- Do Until	275
- Eqv	138
- Erase	296
- Exit Sub	210
- Exit	209
- FileCopy	327
- If...Then	191
- If...Then...Else	195
- Imp	139
- Like	132
- MkDir	326
- Name	330
- Not	137
- On Error	387
- Or	137
- ReDim	286, 291
- Resume Next	390
- Resume	389
- RmDir	327
- Select Case	201
- SendKeys	494
- SetAttr	308
- To	203
- Xor	138
- безусловного перехода	190
- управления программой	
(program control)	190
- условного и безусловного	
перехода (conditional и	
unconditional branching)	190
- условного перехода	190
- присваивания (=)	122
операция выбора	546
- вычитания	543
- декартова произведения	544
- деления	544
- объединения	542
- пересечения	543
- проекции	545
- соединения	546
- сравнения (comparison operation)	97
- отношения (relational operation)	130
Предметный указатель
875
определенные пользователем
функции (user-defined functions) 177
организация данных	573
отмечающие запятые
(place holding commas)	231
отношение (relation)	541
ошибка времени исполнения
(runtime error)	88
- несоответствия типа
(type mismatch)	89, 120
- синтаксиса (syntax error)	87
п
папка (folder)	f 302
переменная (variable)	87, 97
персистенция (persistence)	107
плавающие (floating)	55
по значению (by value)	215
по ссылке (by reference)	215
побочный результат (side effect)	216
подзапрос в инструкции SELECT	588
подпроцедурами (subprocedures)	81
пользовательские данные (user data) 222 последовательность перехода
(tab order)	360
последовательные даты (serial Dates)	93
предмет DDE-обмена
(conversation topic)	482
предопределенными константами
(predefined constants)	114
предупредительного сообщения
(warning message)	207
привязка к сетке (snap to grid)	351
прикрепленный (docked)	54
программный идентификатор
(programmatic identifier)	475
процедуры (procedures)	81
процедуры обработки событий
(event procedures)	338, 503
процессор баз данных (database engine) 539
Р
Рабочий стол (desktop)	221
режим исполнения (run time)	376
- прерывания (break mode)	376
- разработки (design time)	376
результат функции
(function result)	119
рекурсивная (recursive) функция	217
реляционная база данных	541
С
свойства (properties)	.,	222
- Dialogs	319
-, доступные на чтение/запись
(read-write)	225
-, доступные только на чтение
(read-only)	? 225
свойство AttachedTemplate	431
- CollatingOrder	599
- Connection	599
- Control Source	361
- DefaultType	596
- Enable	356
- Format	319
- Name	319
- QueryTimeout	599
- Repl ace Selection	439
- RowSource	361
- ThisDocument	429
- формы Width	343
символы-заполнители
(placeholders)	' 16?
символ определения типа
(type-definition character)	103
- продолжения строки
(line-continuation character)	76
синтаксис (syntax)	87
синтаксические ошибки
(syntax errors)	372
синтаксический анализ (parsing)	87
сложное (составное) выражение
(complex expression)	142
сложный SELECT-запрос	588
событие (event)	338, 503
- Click	339
- Deactivate	340
- Initialize	342
событийные процедуры
(event procedures)	338
совместное использование данных 573 сообщение запроса
(Query message)	207
составные документы
(compound documents)	444
списки аргументов (argument lists)	86
ссылочная целостность	550
стек (stack)	217
строка (string)	96
-	заголовка (title bar)	55
-	объявления (declaration) макроса	73
-	подключений (connection string)	614
строковое выражение (string expression) 119
т
таблица истинности (truth table)	136
текущая папка (current folder)	323
876
Программирование на VBA 2002
текущий диск (current drive) тело (body) - (body) цикла тип Date - Object - данных (data type) - даты (date expression) типизированные переменные трехмерная ссылка
(three-dimensional reference)
У , унарный минус (unary minus) управление доступом - потоком (flow control) - файлами (file management)
Ф
форма элемента Label функция (function)	116,
-	CStr - CurDir - Dir
-	FileDateTime
-	FileLen
-	Fix
-	GetAttr
-	IsMissing
-	LBound
-	MsgBox
-	RGB
-	Sleep - Time функция-процедура (или функция)
323
73 261
93 135
91 119 101
408
126 573 190
302
352 144 145
323 309 331
332 153 305
194 296 148
343 501 145
177
Х-Ч хранимая информация	542
цикл For Each...Next числа с плавающей точкой	267
(floating point numbers)	95
- двойной точности	
(double-precision numbers)	95
- одинарной точности (single-precision numbers) - с фиксированной точкой	95
(fixed-point numbers)	96
численное выражение	
(numeric expression)	119
член класса (class member)	223
э-я
экспоненциальное представление (scientific
notation)	93
элемент массива	284
-	коллекции	241
элементы управления (controls)	343
язык запросов данных
(data query language —	DQL)	573
-	обработки данных (data
manipulation language — DML)	573
--транзакций (transaction
processing language — TPL)	573
-	определения данных
(data definition language — DDL)	573
-	реляционной алгебры	547
-	управления данными
(data control language — DCL)	573
--курсором (cursor
control language — CCL)	574