VBA. Эффективное использование [В. Г. Кузьменко] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

If К II
■ UГ1

Эффективное
использование

В. Г. Кузьменко

Москва
Издательство БИНОМ
2012

УДК 004.432
ББК 32.973.26-018.1
К89

Кузьменко В. Г.
VBA. — М.: ООО «Бином-Пресс», 2012 г. — 624 с.: ил.

В книге содержится краткий курс по языку программирования Visual Basic for
Applications (VBA), используемого в качестве языка программирования в приложе­
ниях Microsoft Office (2000/2/3 и 2007). Книга предназначена для тех, кто в своей
профессиональной деятельности часто использует приложения Microsoft Office и
кому необходимо повысить эффективность работы с этими приложениями посред­
ством автоматизации многих повторяющихся операций.
Материала книги достаточно для изучения основ языка Visual Basic и создания как
простых макросов, предназначенных для автоматизации рутинной повторяющейся
работы с документами, электронными таблицами, диаграммами, презентациями и
т.д., так и для разработки довольно сложных приложений обработки данных с ис­
пользованием диалоговых окон, обеспечивающих пользователей самыми современ­
ными интерфейсными средствами для работы с Windows-приложениями.
ISBN 978-5-9518-0444-0

© Кузьменко В. Г.
© Издательство Бином

Научно-техническое издание
Кузьменко В. Г.

VBA
Оформление обложки И. Ю. Буровой
Подписано в печать 12.12.2011. Формат 70x100/16. Усл. печ. л. 50,7.
Гарнитура «Школьная». Бумага газетная. Печать офсетная.
Тираж 1000 экз. Заказ № 1012
Издательство «Бином-Пресс», 2012 г.
141077, Королев, Московская обл., ул. 50 лет ВЛКСМ, 4-Г

Содержание
Введение................................................................................................................. 13
Глава 1. Введение в макросы......................................................................... 15
Из истории VBA............................................................................................................ 16
Для чего нужен язык программирования VBA.................................................. 19
Создание макросов........................................................................................................ 20
Создание макроса в Word.......................................................................................... 21
Запись новых макросов.............................................................................................. 23
Запись макроса в Word..............................................................................................26
Запись макроса в Excel..............................................................................................32
Запись действий......................................................................................................... 34
Код макроса..................................................................................................................... 35
Выполнение макросов................................................................................................ 37
Сохранение документа с записанным макросом..............................................38

Глава 2. Редактирование макросов............................................................ 41
Модули............................................................................................................................. 41
Модули в Word............................................................................................................. 41
Редактор Visual Basic................................................................................................. 42
Панели инструментов Редактора VB....................................................................... 54
Редактирование макросов.......................................................................................... 58
Составные части записанного макроса................................................................... 62
Написание новых макросов и процедур................................................................ 71

Глава 3. Типы данных, переменные, константы и выражения . . 83
Экспоненциальное представление........................................................................... 85
Тип Date........................................................................................................................ 85
Числа............................................................................................................................ 87
Текстовые строки......................................................................................................... 89
Логические значения................................................................................................. 89
Тип данных Variant..................................................................................................... 90
Переменные..................................................................................................................... 90
Что такое переменная?..............................................................................................90
Выбор имен для переменных.................................................................................. 91
Создание переменных................................................................................................. 93
Задание типа данных переменной........................................................................... 96
Требование явного объявления переменных........................................................ 103
Константы..................................................................................................................... 105
Создание именованных констант........................................................................... 106
Область действия констант...................................................................................... 106
Написание литеральных констант....................................................................... 107
Поиск имеющихся внутренних констант с помощью Object Browser. . . . Ill
Получение данных от пользователя....................................................................... 112
Выражения в Visual Basic....................................................................................... 114
Совместимость типов данных.................................................................................. 116
Преобразования численных типов....................................................................... 118
Арифметические операции...................................................................................... 121
Сравнение строк......................................................................................................... 128

6

VBA
Сравнение объектов..................................................................................................132
Логические операторы.............................................................................................. 133
Конкатенация строк.................................................................................................. 138
Приоритеты выполнения операций при вычислении сложных выражений . . 141

Глава 4. Функции в Visual Basic.................................................................143
Использование функций в выражениях.......................................................... 144
Аргументы и возвращаемое значение функции.................................................145
Игнорирование результата функции................................................................... 145
Использование именованных аргументов функции............................................. 147
Использование других функций VBA.............................................................. 151
Математические функции...................................................................................... 152
Функции преобразования данных........................................................................... 153
Функции даты и времени...................................................................................... 155
Строковые функции..................................................................................................156
Использование функций для манипулирования строками.............................. 158
Удаление ненужных символов............................................................................... 159
Определение длины строки...................................................................................... 160
Сравнение и поиск строк.......................................................................................... 161
Разбиение строки на меньшие части................................................................... 163
Форматирование значений данных....................................................................... 167
Использование функций host-приложений........................................................ 177
Создание функций и функций-процедур................................................................ 179
Использование функций-процедур в VBA............................................................ 185
Использование функций пользователя в рабочих листах Excel .... 188
Создание функций для Excel.................................................................................. 190

Глава 5. Изменение порядка выполнения операторов в VBA . . 195
Простой выбор............................................................................................................ 196
Использование необязательных аргументов........................................................ 200
Выбор ветви с помощью If...Then...Else................................................................201
Сложный выбор......................................................................................................... 203
Использование If...Then...Elself...............................................................................205
Безусловный переход................................................................................................ 211
Использование MsgBox для обеспечения возможности выбора . . . . 213
Дополнительные свойства процедур и функций............................................. 216
Раннее окончание процедур, функций и целых программ............................. 216
Использование оператора Exit...............................................................................216
Использование оператора End...............................................................................219
Дополнительные свойства необязательных аргументов ..................................... 222
Управление передачей аргументов....................................................................... 223
Передача аргументов по ссылке и по значению................................................ 223
Определение способа передачи аргумента............................................................ 224
Рекурсия......................................................................................................................... 226
Примеры рекурсивных функций........................................................................... 226
Как избежать случайной рекурсии и других проблем..................................... 228

Глава 6. Введение в объекты и коллекции............................................ 231
Объекты......................................................................................................................... 231
Свойства объекта..................................................................................................... 232
Методы объекта......................................................................................................... 233
Классы объекта......................................................................................................... 233
Использование объектов.......................................................................................... 234
Объявление объектных переменных................................................................... 248
Объекты в выражениях.......................................................................................... 249
Ссылка на объекты с помощью With...End With................................................ 253

Содержание

7

Работа с коллекциями объектов и контейнерами объектов.........................254
Добавление объектов к коллекциям....................................................................... 257
Ссылка на конкретные объекты в коллекции или контейнере...................... 258
Фигуры в слое векторной графики....................................................................... 259
Добавление к коллекции Shapes «автофигур».................................................... 259
Добавление к коллекции Shapes специальных фигур......................................... 262
Использование Object Browser для работы с объектами, методами
и свойствами........................................................................................................ 271

Глава 7. Повторение действий в Visual Basic: циклы
и массивы...................................................................... 275
Команды организации циклов............................................................................... 275
Повторение цикла фиксированное число раз:циклы For.......................... 277
Циклы Do.................................................................................................................... 286
Как прервать выполнение макроса илипроцедуры.............................................. 288
Использование циклов, тестирующих условия до выполнения тела цикла . . 289
Использование циклов, тестирующих условия после выполнения
тела цикла......................................................................................................... 294
Вложенные циклы.................................................................................................... 297
Вложение циклов For.............................................................................................. 297
Вложенные циклы Do.............................................................................................. 299
Пример использования коллекции в Word........................................................ 301
Массивы......................................................................................................................... 302
Размерность массива................................................................................................. 302
Статические и динамические массивы............................................................... 304
Оператор Option Base..............................................................................................304
Объявление массивов.............................................................................................. 305
Использование массивов.......................................................................................... 306
Использование ReDim с динамическими массивами......................................... 309
Функции LBound и UBound.................................................................................. 315
Использование Erase для очистки или удаления массивов..............................316
Использование массивов в качестве аргументов процедур и функций . . . 318

Глава 8. Управление файлами с помощью VBA................................ 321
Управление файлами................................................................................................ 321
Что такое управление файлами...............................................................................321
Возможности VBA по управлению файлами........................................................ 322
Атрибуты файла........................................................................................................ 323
Получение атрибутов файла.................................................................................. 325
Изменение атрибутов файла.................................................................................. 328
Как находить файлы................................................................................................ 329
Использование функции Dir для нахождения файлов..................................... 329
Использование встроенных диалоговых окон Excel для получения
имен файлов........................................................................................................ 334
Использование метода GetOpenFilename............................................................... 334
Использование метода GetSaveAsFilename............................................................ 338
Использование встроенных диалоговых окон Word для получения
имен файлов........................................................................................................ 341
Использование Word-диалогового окна Open........................................................ 342
Использование Word-диалогового окна Сохранение документа...................... 344
Работа с дисками и папками............................................................................... 346
Получение пути текущей папки и буквенной метки диска............................. 346
Изменение текущей папки........................................................
347
Создание дисковых папок...................................................................................... 349

8

VBA

Копирование и удаление файлов........................................................................... 351
Копирование файлов................................................................................................. 351
Удаление файла......................................................................................................... 352
Переименование или перемещение файлов...................................................... 353
Получение информации о файлах.......................................................................355
Получение времени и даты создания/модификации файла..............................355
Получение длины файла.......................................................................................... 356

Глава 9. Элементы диалоговых окон........................................................ 359
Формы пользователя................................................................................................ 359
Свойства объекта UserForm.................................................................................. 361
Методы объекта UserForm...................................................................................... 362
События и событийные процедуры....................................................................... 363
Примеры программ модуля класса формы............................................................ 365
Элементы управления................................................................................................ 370
Использование Toolbox (панели элементов)...................................................... 377
Добавление к форме элементов управления........................................................ 378
Редактирование элементов управления на форме............................................. 387
Копирование, вставка и удаление элементов управления................................. 388
Редактирование или форматирование заголовков элементов управления. . 388
Управление последовательностью перехода........................................................ 389
Задание свойств формы и элементов управления в режиме разработки . . 390
Использование дополнительных элементов управления..................................... 392

Глава 10. Управление host-приложениями VBA................................ 397
Работа с Excel............................................................................................................ 397
Работа с объектами Worksheet...............................................................................406
Методы, возвращающие объекты Range............................................................... 411
Использование метода Cells.................................................................................. 413
Работа с Cells и Ranges.......................................................................................... 418
Работа с объектами Word....................................................................................... 423
Работа с объектами Document...............................................................................424
Работа с объектами Template.................................................................................. 432
Компоненты объекта Document...............................................................................435
Как задать диапазон................................................................................................. 436
Работа с объектом Selection.................................................................................. 441
Как переместить или «свернуть» объекты Selection и Range..........................441
Добавление текста..................................................................................................... 444
Как вырезать, скопировать, вставить и удалить текст..................................... 447

Глава 11. Отладка VB-кода. Поиск и устранение ошибок .... 451
Типы ошибок................................................................................................................ 451
Средства отладки........................................................................................................ 454
Режимы отладки........................................................................................................ 455
Режим останова........................................................................................................ 456
Переход в режим останова из окна сообщения об ошибке............................. 456
Точки останова............................................................................................................ 457
Использование оператора Stop.............................................................................. 458
Переход в режим останова прерыванием исполнения кода............................. 459
Выход из режима останова...................................................................................... 459
Использование команды Step Into...................................................................... 460
Наблюдение за значениями выражений.......................................................... 461
Редактирование наблюдаемого выражения........................................................ 463
Удаление наблюдаемого выражения................................................................... 464

Содержание

9

Использование команды Step Over.......................................................................464
Использование окна Locals................................................................................... 465
Трассировка вызовов процедур..............................................................
465
Использование окна Immediate........................................................................... 467
Оператор Debug.Print............................................................................................. 468
Оператор Debug.Assert..............................................................................................468
Обработчик ошибок.................................................................................................... 469
Выход из блока обработки прерывания по ошибке.............................................471
Программная обработка ошибок при помощи оператора On Error . . 475

Приложение А. Операторы в VBA............................................................ 477
AppActivate................................................................................................................ 477
Веер............................................................................................................................ 477
Call............................................................................................................................... 478
ChDir..............................
479
ChDrive........................................................................................................................ 479
Close............................................................................................................................479
Синтаксис................................................................................................................ 479
Const............................................................................................................................ 480
Date............................................................................................................................ 481
Declare........................................................................................................................ 481
Deftype........................................................................................................................ 483
DeleteSetting............................................................................................................. 484
Dim............................................................................................................................... 485
Do... Loop.................................................................................................................... 486
End............................................................................................................................... 486
Enum............................................................................................................................ 487
Erase............................................................................................................................ 488
Error............................................................................................................................ 489
Event............................................................................................................................ 490
Exit............................................................................................................................ 490
FileCopy.................................................................................................................... 491
For Each...Next......................................................................................................... 492
For...Next.................................................................................................................... 493
Function.................................................................................................................... 493
Get............................................................................................................................... 496
GoSub...Return......................................................................................................... 498
GoTo............................................................................................................................ 499
If...Then...Else......................................................................................................... 499
Implements.................................................................................................................501
Input #........................................................................................................................ 501
Kill................................................................................................................................ 502
Let................................................................................................................................502
Line Input #............................................................................................................. 503
Load............................................................................................................................ 504
Lock, Unlock............................................................................................................. 504
LSet............................................................................................................................ 505
Mid................................................................................................................................505
MkDir........................................................................................................................ 506
Name............................................................................................................................ 506
On Error.................................................................................................................... 507
On...GoSub, On...GoTo.......................................................................................... .509
Open............................................................................................................................ 510
Option Base.................................................................................................................511
Option Compare......................................................................................................... 511
Option Explicit......................................................................................................... 511

10

VBA
Option Private............................................................................................................. 512
Print #..................................................................................................................... ....
Private.............................................
513
Property Get............................................................................................................. 514
Property Let................................................................................................................. 517
Синтаксис............................................................................................................. ....
Property Set.................................................................................................................519
Public............................................................................................................................ 521
Put................................................................................................................................ 522
RaiseEvent.................................................................................................................524
Randomize.................................................................................................................525
ReDim........................................................................................................................ 525
Rem............................................................................................................................ 526
Reset............................................................................................................................ 526
Resume........................................................................................................................ 526
Примеры.................................................................................................................... 527
RmDir........................................................................................................................ 529
RSet............................................................................................................................ 529
SaveSetting.................................................................................................................529
Seek............................................................................................................................ 530
Select Case.................................................................................................................531
SendKeys.................................................................................................................... 532
Set................................................................................................................................ 534
SetAttr........................................................................................................................ 534
Static............................................................................................................................ 535
Stop............................................................................................................................ 536
Sub................................................................................................................................ 536
Time............................................................................................................................ 538
Type............................................................................................................................ 538
Unload........................................................................................................................ 539
While... Wend............................................................................................................. 539
Width #.................................................................................................................... 540
With............................................................................................................................ 540
Write #........................................................................................................................ 540

Приложение Б. Функции в VBA................................................................ 543
Abs................................................................................................................................543
Array........................................................................................................................ 543
Asc................................................................................................................................ 543
Atn................................................................................................................................ 544
CallByName.................................................................................................................544
Функции преобразования типов........................................................................... 545
Choose........................................................................................................................ 545
Chr................................................................................................................................ 546
Cos................................................................................................................................ 546
CreateObject.................................................................................................................546
CurDir........................................................................................................................ 547
CVErr............................................................................................................................ 547
Date............................................................................................................................ 548
DateAdd.................................................................................................................... 548
DateDiff.................................................................................................................... 548
DatePart.................................................................................................................... 549
DateSerial.................................................................................................................... 550
DateValue.................................................................................................................... 551
Day................................................................................................................................ 551
DDB............................................................................................................................ 551
Dir................................................................................................................................ 552
Environ........................................................................................................................ 553

Содержание

1

EOF............................................................................................................................ 553
Error............................................................................................................................ 553
Exp................................................................................................................................ 554
FileAttr........................................................................................................................ 554
FileDateTime............................................................................................................. 554
FileLen........................................................................................................................ 555
Filter............................................................................................................................ 555
Fix................................................................................................................................556
Format........................................................................................................................ 556
FormatCurrency......................................................................................................... 557
FormatDateTime......................................................................................................... 558
FormatNumber......................................................................................................... 559
FormatPercent............................................................................................................. 559
FreeFile........................................................................................................................ 560
FV................................................................................................................................560
GetAllSettings............................................................................................................. 561
GetAttr........................................................................................................................ 562
GetObject.................................................................................................................... 562
GetSetting.................................................................................................................... 563
Hex................................................................................................................................564
Hour............................................................................................................................ 564
Ilf................................................................................................................................564
Input
.................................................................................................................... 565
InputBox.................................................................................................................... 565
InStr...............................................................................
566
InStrRev.................................................................................................................... 567
Int................................................................................................................................568
IPmt............................................................................................................................ 568
IRR............................................................................................................................... 569
IsArray........................................................................................................................ 570
IsDate........................................................................................................................ 570
IsEmpty........................................................................................................................ 571
IsError........................................................................................................................ 571
IsMissing.................................................................................................................... 571
IsNull............................................................................................................................ 572
IsNumeric.................................................................................................................... 572
IsObject........................................................................................................................ 572
Join............................................................................................................................ 573
LBound........................................................................................................................ 573
LCase............................................................................................................................ 574
Left............................................................................................................................ 574
Len................................................................................................................................574
Log............................................................................................................................... 575
LOF............................................................................................................................ 575
Log................................................................................................................................575
LTrim............................................................................................................................ 576
Mid................................................................................................................................576
Minute........................................................................................................................ 576
MIRR............................................................................................................................ 577
Month........................................................................................................................ 577
MonthName................................................................................................................ 577
MsgBox........................................................................................................................ 578
Now............................................................................................................................ 579
NPer............................................................................................................................ 580
NPV............................................................................................................................ 580
Oct................................................................................................................................581
Partition.................................................................................................................... 581

12

VBA
Pmt............................................................................................................................ 582
PPmt............................................................................................................................ 583
PV................................................................................................................................ 584
QBColor........................................................................................................................ 585
Rate............................................................................................................................ 586
Replace........................................................................................................................ 587
RGB............................................................................................................................ 588
Right............................................................................................................................ 589
Rnd................................................................................................................................ 589
Round........................................................................................................................ 590
RTrim........................................................................................................................ 590
Second........................................................................................................................ 591
Seek............................................................................................................................ 591
Sgn................................................................................................................................591
Shell............................................................................................................................ 592
Sin................................................................................................................................593
SLN............................................................................................................................ 593
Space............................................................................................................................ 593
Spc................................................................................................................................593
Split............................................................................................................................ 594
Sqr............................................................................................................................... 595
Str............................................................................................................................... 595
StrComp.................................................................................................................... 595
StrConv........................................................................................................................ 596
StrReverse................................................................................................................ 597
String............................................................................................................................ 597
Switch........................................................................................................................ 597
SYD............................................................................................................................ 598
Tab............................................................................................................................... 598
Tan............................................................................................................................... 599
Time............................................................................................................................ 599
Timer............................................................................................................................ 599
TimeSerial.................................................................................................................... 599
TimeValue.................................................................................................................... 600
Trim............................................................................................................................600
TypeName.................................................................................................................... 600
UBound........................................................................................................................ 601
UCase............................................................................................................................ 602
Vai............................................................................................................................... 602
VarType........................................................................................................................ 602
Weekday.................................................................................................................... 603
WeekdayName.............................................................................................................604
Year............................................................................................................................ 605

Предметный указатель.....................................................................................607

Посвящается моей маме

Введение
Несмотря на то, что многие задачи Microsoft Office позволяет выполнить
и без программирования, одним из наиболее важных и полезных его свойств
является возможность автоматизации процессов взаимодействия пользовате­
ля и приложений Microsoft Office, которая позволяет решать, практически,
все современные бизнес-задачи: от создания простых документов и отчетов до
полной автоматизации документооборота с использованием систем управле­
ния базами данных. Это обстоятельство связано с тем, что все приложения
Microsoft Office поддерживают язык программирования Visual Basic for
Applications (VBA), совместимый c Visual Basic 6. Важнейшим достоинством
VBA является возможность объединять любые приложения Microsoft Office
для выполнения одной или нескольких задач.
Привлекательная особенность VBA в том, что он очень удобен для первого
знакомства с программрованием в среде Windows. В наиболее используемых
приложениях Microsoft Office имеется Редактор VB (Visual Basic Editor)
и макрорекордер — средство кодирования действий пользователя для после­
дующего их повторения. Эти инструменты, кроме всего прочего, могут с успе­
хом использоваться для обучения программированию — без утомительного по­
иска информации по различного рода справочникам вы можете «записать»
многие свои действия посредством макрорекордера, а затем рассмотреть результрующий код. Редактор VB — это не только средство редактирования ко­
да, но и замечательное средство отладки кода и изучения языка Visual Basic,
так как вы можете в интерактивном режиме проверить действие любой син­
таксической конструкции.
В настоящее время Microsoft Office является не набором программных про­
дуктов индивидуального применения, а комплексной интегрированной систе­
мой, в которую, кроме уже знакомых многим пользователям средств (Word,
Excel и т.д.), входят серверы, службы и приложения для настольных компью­
теров, предназначенные для использования при решении широкого спектра
бизнес-задач. Несмотря на то, что многие практические задачи с использова­
нием Microsoft Office можно выполнить без программирования, имеет смысл
изучения языка VBA для расширения спектра решаемых проблем.
Приложения Microsoft Office обеспечивают доступ ко многим современным
системам баз данных. Пользователь может внести результаты сложного SQLзапроса из удаленной базы данных коллективного доступа в любой создавае­
мый им отчет или проект. Применение для этих целей VBA-кода расширяет
такие возможности и улучшает пользовательский интерфейс.

14

VBA

В этой книге содержится вводный курс по использованию языка и систе­
мы VBA в основном для Microsoft Word 2007, Microsoft Excel 2007, хотя
почти все Word/Excel-программы (процедуры) будут работать и для
Word/Excel 2000/2/3. Книга предназначена для начинающих программиро­
вать в среде Windows 2000/ХР с использованием в качестве базовых объектов
Word и Excel, таких как документы, рабочие книги, листы, презентации и так
далее, т.е. объекты, которые хорошо известны пользователям этих приложе­
ний. Только теперь имеется возможность посмотреть на эти объекты «изнут­
ри», узнать их строение: свойства, методы, взаимосвязи.
Поработав с этой книгой, вы сможете создавать как простые макросы, по­
могающие автоматизировать рутинную повторяющуюся работу над докумен­
тами и электронными таблицами, так и довольно сложные приложения, обра­
батывающие данные в диалоговых окнах, обеспечивающих пользователя са­
мыми современными интерфейсными средствами. Далее вам ничто не
помешает начать изучение системы Visual Basic (системы программирования
подобной C++Buider или Delphi) и Visual Basic .NET, открывающих перед ва­
ми еще большие горизонты и позволяющих также использовать объекты при­
ложений Microsoft Office.
Большую пользу эта книга может принести менеджерам, которые в своей
профессиональной деятельности много времени работают за компьютерами
и решают задачи, в которых нет места таким системам программирования,
как Visual C++, Delphi и так далее. Более того, поскольку менеджерам чаще
всего приходится использовать продукты Microsoft Office, именно VBA им мо­
жет пригодиться больше всего, потому что это — «родной» язык для этих про­
дуктов. К тому же возможности VBA совсем не уступают другим языкам про­
граммирования в Windows и постоянно растут.

Элементы оформления книги
Для улучшения восприятия материала книги в ней используются следую­
щие элементы оформления:
□ впервые встречающиеся термины выделены курсивом;
□ ключевые слова языка программирования, наименования элементов уп­
равления выделены шрифтом Courier New Cyr, Bold;
□ команды меню, наименования кнопок, окон и других элементов управле­
ния диалоговых окон выделены шрифтом Arial, Bold;
□ имена переменных VB-кода, наименования файлов и просто тект, на ко­
торый следует обратить внимание, отмечен как Bold.

Введение в макросы
Далеко не все пользователи Word и Excel и других продуктов Microsoft
Office знают о том, что эти приложения совершенно не настроены для выпол­
нения тех задач, для которых предназначены. Мало кто из пользователей, ак­
тивно работающих, например, с Word или Excel, когда-либо вообще читал по­
собие по работе с этими продуктами — просто установили их (может быть, при
помощи кого-нибудь поопытнее, чем сами) и начали создавать полезные (и не
очень) документы. Между тем, все приложения Microsoft Office являются та­
кими же конструкторами, как и те компьютеры, которые мы обычно исполь­
зуем с этими приложениями. Для многих типов задач, решаемых при помощи
этих приложений, их нужно настраивать. Примером настроек могут служить
многочисленные шаблоны документов в Word, о которых, впрочем, тоже зна­
ют далеко не все пользователи. Даже среди знающих о существовании шабло­
нов и стилей (!) многие не знают самых простых дополнительных возможно­
стей этих продуктов, которые реализуются посредством макросов. Конечно,
и Word, и Excel предоставляют достаточно широкий набор функций для вы­
полнения самых разнообразных офисных задач, но все же знание и использо­
вание макросов VBA дает такие преимущества, которые невозможно переоце­
нить.
Перед тем как вы начнете писать собственные макросы, вам следует хорошо
понять, что такое макросы и чем отличается VBA-программируемый макрос
от записанного макрорекордером.
Независимо от используемых вами операционной системы и программных
приложений вы часто выполняете одни и те же последовательности команд
для многих рутинных задач. Вместо повторения последовательности команд
каждый раз, когда вам необходимо выполнить какую-либо задачу, вы можете
создать макрос (macro), который вместо вас будет выполнять эту последова­
тельность. Макросы позволяют вводить одиночную команду, выполняющую
ту же задачу, для реализации которой вам было бы необходимо вводить не­
сколько команд вручную. Например, если вам нужно для многих абзацев
большого документа изменить стили на другие (стандартные, ранее вами под­
готовленные или экспортированные из других документов), вы могли бы запи­
сать действия, связанные с поиском и выбором стиля, при помощи макроре­
кордера с назначением записанному макросу «горячих клавиш». В этом слу­
чае для изменения стиля абзаца вам достаточно было бы поместить курсор
вставки на нужный абзац и нажать комбинацию клавиш. Чем больше подоб­
ных изменений необходимо внести в документ, тем больший эффект можно
получить от такого элементарного записанного макроса или нескольких:
сколько используемых стилей — столько и макросов с «горячими клавиша­
ми».

16

Глава 1. Введение в макросы

Записанные макрорекордером последовательности команд первоначально
назывались макрокомандами (macro-commands). Сейчас этот термин сокра­
тился до более простого слова макрос. (Термин macro используется как пре­
фикс в нескольких словах в английском языке; он произошел от греческого
слова, означающего расширенный или растянутый). Применительно к ин­
форматике и программным приложениям под словом макрос всегда подразу­
мевается макрокоманда.
Макросы, кроме удобства, имеют и другие преимущества. Поскольку ком­
пьютеры приспособлены для выполнения повторяющихся задач больше, чем
люди, запись макрорекордером неоднократно выполняемых команд повышает
точность и скорость работы. Другим преимуществом использования макросов
является то, что при их выполнении обычно нет необходимости в присутствии
человека-оператора. В случае, если макрос очень длинный или выполняет опе­
рации, требующие значительного времени (например, поиск в базе данных
и сортировка), вы можете оставить работающий компьютер и, например, по­
пить кофе или переключиться на другое приложение, если, конечно, вы свято
верите в то, что Windows — многозадачная система.
Макрорекордер (или просто «рекордер») записывает все действия пользова­
теля, включая ошибки и неправильные запуски. Когда программа воспроизво­
дит макрос, она выполняет каждую записанную рекордером команду точно
в такой последовательности, в которой вы их выполняли во время записи.
Первые макрорекордеры имели серьезный недостаток. Если вы записывали
длинную серию действий, содержащую небольшую ошибку, единственной воз­
можностью удалить эту ошибку являлась повторная запись макроса. Кроме
того, если вам было необходимо внести небольшое изменение в длинный мак­
рос, то также приходилось перезаписывать весь макрос. Перезапись длинного
макроса часто приводила к дополнительным ошибкам в новой записи. По этим
причинам разработчики программного обеспечения добавили макрорекорде­
рам возможность редактирования макросов, чтобы вы могли легко исправлять
небольшие ошибки или вносить другие изменения в макрос без его полной пе­
резаписи.

Из истории 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) компьютера.

Из истории УВА

17

С годами первоначальная структура и спецификации 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 начала вклю­
чать элементы языка 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 VBA реализуется
в Word, Excel, Access. В основные приложения Office (Word, Excel, Po­
werPoint), начиная с версии 2000, включен редактор сценариев — Microsoft
Visual Basic Script Editor, который позволяет редактировать Web-страницы
(например, в Word) и придать им динамику. Язык VBScript (Visual Basic
Scripting Edition) входит в семейство языков Visual Basic и, являясь упрощен­
ной версией языка Visual Basic, позволяет программировать документы, ото­
бражаемые браузерами World Wide Web.

18

Глава 1. Введение в макросы

Visual Basic for Applications в основном является тем же, что и Visual Basic
for Windows, с некоторыми небольшими различиями. Макропрограммы VBA
сохраняются в файловом формате, используемом приложением, в котором вы
написали макрос Visual Basic for Applications, а не в отдельных текстовых
файлах. Например, макропрограммы VBA, созданные в Excel, сохраняются
в файле рабочей книги Excel, программы VBA в Word сохраняются в файле до­
кумента, а программы VBA в Access — в файле данных Access. Для выполне­
ния макропрограммы VBA вы должны сначала запустить приложение, в кото­
ром написали этот макрос. Например, вы не можете запустить макрос Excel
VBA из любой другой программы, кроме Excel. Несмотря на то, что основные
возможности VBA остаются теми же в приложениях, каждое приложение до­
бавляет специальные команды и объекты (в зависимости от конкретного при­
ложения) в Visual Basic for Applications. Например, VBA в Excel содержит
много команд, которые относятся только к рабочим листам и задачам, кото­
рые вы можете выполнить с рабочим листом. Аналогично, VBA в Word содер­
жит команды, относящиеся только к операциям над текстом в документе, то­
гда как VBA в Access содержит команды, относящиеся только к операциям
с базой данных, и так далее.
Если до появления MS Office 97 средства программирования в офисных па­
кетах предназначались в основном для создания макрокоманд, расширяющих
возможности конкретных приложений, то с выходом MS Office 97 специали­
сты получили универсальную систему программирования для прикладных
программ на базе Visual Basic. Впервые MS Office был представлен как единая
платформа для создания бизнес-приложений, предназначенных для решения
специализированные задачи пользователей. Это новое качество MS Office обу­
славливалось специальным выпуском для разработчиков — Developer Edition.
По сведениям Microsoft, в настоящее время MS Office в качестве платформы
создания бизнес-приложений используют несколько миллионов профессио­
нальных разработчиков.
Пакет Microsoft Office по мере развития из набора приложений индивиду­
ального применения превратился в комплексную интегрированную систему,
в которой ее разработчики большое внимание уделили именно совместной ра­
боте пользователей. В Microsoft Office System, кроме привычных пользовате­
лям средств (Word, Excel и т.д.), входят серверы, службы и приложения, раз­
работанные для совместного применения при решении широкого круга бизнес-задач. Microsoft Office 2007 позволяет эффективно разрабатывать мощные
и удобные приложения и предоставлять пользователям информацию из любых
источников в рамках удобного и многофункционального интерфейса. Разра­
ботчики могут создавать приложения, использующие средства языка XML
и Web-служб, возможности смарт-тегов инструменты Visual Studio .NET и ин­
формацию из баз данных таких систем, как Microsoft Access 2007 и Microsoft
SQL Server 2000/5.
Поскольку книга адресована в основном тем, кто только начинает програм­
мировать в среде Windows, здесь рассматривается VBA-программирование
только для двух наиболее используемых приложений — Word и Excel. Основ­
ной целью, которую преследует автор книги, является представление основ
языка VBA, который, как утверждает Microsoft, начиная с версии MS Office
2000, не отличается от обычного Visual Basic 6. VBA-программирование (раз­
работка макросов) рассматривается для самого распространенного (по крайней

Для чего нужен язык программирования УВА

19

мере, в России) пакета MS Office 2007, в состав которого входят такие прило­
жения, как Microsoft Office Access, Microsoft Office Word, Microsoft Office
Excel, Microsoft Office Outlook, Microsoft Office PowerPoint, Microsoft Office
InfoPath, Microsoft Office OneNote, Microsoft Office Publisher.

Для чего нужен язык программирования VBA
Поскольку вы можете использовать макрорекордер в Word или Excel для
записи ваших действий в макрос (а в Access для этой цели использовать своего
рода конструктор) и затем воспроизводить их, сначала может показаться, что
изучать VBA необязательно. Однако одни записанные макросы не могут удов­
летворить все ваши потребности. Записанный макрорекордером макрос может
только воспроизводить без отклонений каждое действие в той же последова­
тельности, в которой вы первоначально выполняли эти действия. VBA можно
использовать для улучшения макросов, записанных макрорекордером, значи­
тельно повышая их мощь и возможности.
Записанные макрорекордером макросы лишены гибкости, поэтому они
не могут реагировать на изменившиеся или меняющиеся условия. На язы­
ке VBA вы можете написать макрос, который проверяет соответствие раз­
личным предопределенным условиям и выбирает последовательность дей­
ствий на основе этих условий. Если вы, например, выполняете какой-либо
Excel-макрос, который пытается выбрать рабочий лист с именем «Прода­
жи», в то время, когда в книге нет такого рабочего листа, записанный
вами макрос будет выполняться неправильно и Excel выведет на экран со­
общение об ошибке. Добавив VBA-команды к этому записанному макросу,
вы могли бы с его помощью выполнить проверку наличия этого определен­
ного рабочего листа перед его выбором или даже вставить новый рабочий
лист и дать ему соответствующее имя, если нужный рабочий лист не суще­
ствует.
Что касается повторяющихся действий в самом макросе, записанные рекор­
дером макросы имеют значительные ограничения. Если вам необходимо, что­
бы записанный макрос повторял какое-либо действие несколько раз, вы долж­
ны вручную повторить это действие нужное количество раз, когда записываете
макрос. Такой макрос всегда повторяет это действие одинаковое количество
раз, всякий раз, когда вы его запускаете, до тех пор, пока вы не отредактируе­
те или не перезапишете его. Напротив, VBA-макрос, написанный пользовате­
лем, может использовать предопределенные условия или вводимые пользова­
телем данные для повторения действия различное количество раз или для при­
нятия решения о необходимости выполнения этого действия.
В качестве примера вы можете записать рекордером макрос для изменения
ширины нескольких смежных столбцов в рабочем листе Excel. Если вам необ­
ходимо, чтобы макрос изменял ширину первых трех столбцов в рабочем листе,
вы должны вручную повторить операцию изменения размера для каждого из
трех столбцов при записи макроса. Записанный макрос будет только (и всегда)
изменять ширину первых трех столбцов в рабочем листе. Вы не можете ис­
пользовать тот же макрос для изменения ширины двух или четырех столбцов.
Кроме того, если вы изменили ширину первых трех столбцов, записанный
макрос будет выполнять действие только над тремя первыми столбцами. Вы не

20

Глава 1. Введение в макросы

сможете использовать тот же макрос для изменения ширины столбцов со вто­
рого по четвертый. Добавив команды VBA к этому записанному рекордером
макросу, вы можете создать макрос, который запрашивает, размер скольких
и каких столбцов необходимо изменить, и даже позволяет задавать новую ши­
рину столбцов.
Эти два примера представляют пару простейших задач, которые вы можете
выполнить с командами VBA в макросах. Существует много обстоятельств,
при которых вам может понадобиться добавлять команды принятия решений
к макросам, записанным макрорекордером. Единственный способ получить
такие возможности — это вручную добавить операторы VBA к записанному
макросу.'
Кроме улучшения определенных макросов, записанных макрорекордером,
вы можете использовать VBA для соединения, организации и управления не­
сколькими записанными макросами, с помощью которых вы выполняете
сложную общую задачу, состоящую из нескольких меньших задач. Например,
вы можете регулярно импортировать данные из базы данных в рабочий лист
Excel, форматировать эти данные для вывода на экран, генерировать диаграм­
му из этих данных и затем распечатывать эту диаграмму и отформатирован­
ный отчет.
Для того чтобы объединить эти отдельные задачи для создания единственной
задачи, выполняемой одним макросом, вы можете сначала написать отдельный
макрос для каждой из отдельных задач: для импортирования данных, формати­
рования этих данных для последующего отображения, создания диаграммы
и печати данных. Далее вы могли бы организовать записанные макросы так,
чтобы они выполнялись в нужной последовательности одним макросом, кото­
рый вы напишете посредством команд VBA.
С помощью макросов можно создавать пользовательские меню, диалоговые
окна, которые могут до неузнаваемости изменить интерфейс всем известных
продуктов Word и Excel. Уместно здесь отметить также и возможность созда­
ния разнообразной системы проверки данных, вводимых пользователем в диа­
логовых окнах. Когда вы научитесь писать программы на языке VBA, вы, ско­
рее всего, уже никогда не станете начинать создание макроса с использования
рекордера. С другой стороны, довольно часто будете обращаться к нему за по­
мощью при выполнении задач, которые раньше делать не приходилось: рекор­
дер запишет макрос, а вы узнаете, ранее не используемые вами свойства или
методы.

Создание макросов
Существует мнение, что изучение языка VBA легче всего начать с записи
нового макроса при помощи рекордера. Поэтому большая часть литературы по
VBA следует схеме, по которой читателю предлагается сначала посмотреть,
как макросы создаются самими продуктами, такими как Word и Excel, а за­
тем, осторожно внедряя свои инструкции в работающие макросы, изучить но­
вый для них язык. Мне же представляется более продуктивным другой под­
ход, при котором вы начнете писать макросы (с использованием Visual Basic
Editor — Редактора), как обычные программы на новом для вас языке про­
граммирования, и каждый свой шаг будете проверять контрольными запуска­
ми кода.

Создание макросов

21

Создание макроса в Word
Запустите Microsoft Office Word 2007, добавьте к панели Ribbon вкладку
Разработчик (Developer), для чего нужно, щелкнув кнопку Office, выбрать Пара­
метры Word и в появившемся окне для группы параметров Основные устано­
вить флажок Показывать вкладку «Разработчик» налейте (рис. 1.1).

Рис. 1.1. Чтобы вкладка Разработчик появилась на панели Ribbon, нужно, щелкнув
кнопку Office, выбрать Параметры Word и в появившемся окне для группы
параметров Основные установить флажок Показывать вкладку «Разработчик»
на ленте

На вкладке Разработчик (рис. 1.2) расположены команды, предназначенные
для работы с VBA, макросами, элементами управления, XML, шаблонами и др.
Для вывода диалогового окна Microsoft Visual Basic (Редактора Visual Basic)
щелкните на вкладке Разработчик кнопку Visual Basic (в левом углу вкладки)
или нажмите комбинацию клавиш Alt+Fll.
Далее следует создать модуль, в котором будет размещаться код вашего первого
макроса. Щелкните для этого на значке Рго)ес1( 100 Then MsgBox "Тяжело!" Else MsgBox "He так тяжело!"
В этом примере, если значение переменной Вес больше 100, то условное вы­
ражение равно True и VBA выполняет оператор MsgBox для отображения сооб­
щения «Тяжело!». Если переменная Вес содержит число, равное или мень­

202

Глава 5. Изменение порядка выполнения операторов в УВА

шее 100, то рассматриваемое условие равно 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
выполняет все операторы (представленные с помощью ElseStatements) между ключе­
вым словом Else и ключевыми словами End If. Затем VBA продолжает выполнение
кода с первого оператора, появляющегося после ключевых слов End If. Как и в блоке
оператора If...Then, ключевые слова End If должны помещаться в отдельной строке,
хотя в эту строку можно добавлять конечный комментарий (см. схему 5.2).

Простой выбор

203

Оператор If...Then...Else выбирает одну или другую ветвь, но никогда не
выбирает обе ветви одновременно. В следующем примере (листинг 5.4) пока­
зан типичный блок оператора If...Then...Else:

Листинг 5.4. Функция GetBookName4
1 : Function GetBookName!(Optional lDflt) As String
2:
Dim ITitle As String, IPrmpt As String, IVar As String
3:
4:
ITitle = "Ввод наименования книги"
5:
IPrmpt = "Введите.наименование новой книги"
6:
7:
'включен ли lDflt в список аргументов
8:
If IsMissing(lDflt) Then lDflt = "Отчет о продажах"
9:
10:
'использование InputBox для получения имени файла.
11:
IVar = Trim(InputBox(prompt:=lPrmpt,
12:
Title:=lTitle,
13:
Default:=lDfIt))
14:
15:
'проверить наличие строки ввода
16:
If Len(IVar) = 0 Then
17:
MsgBox "Наименование не введено!"
18:
GetBookName! = lDflt 'имя по умолчанию
19:
Else
20:
GetBookName! = IVar
21:
End If
22:
23: End Function
'GetBookName

Никаких преимуществ у этого кода по сравнению с кодом листинга 5.3 нет,
но здесь был использован оператор If...Then...Else и строки 16-21 представля­
ют собой более понятный код. Этот пример содержит тот же оператор, приво­
димый для однострочного If ...Then...Else, но теперь использует форму блока.

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

Вложенные операторы If...Then

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

204

Глава 5. Изменение порядка выполнения операторов в УВА

Хотя можно вкладывать и однострочные формы операторов If...Then
и If...Then...Else, такие операторы трудно понимать. При вложении If...Then
и If...Then...Else используйте для ясности блочную форму этих операторов.
Листинг 5.5 показывает простую процедуру для иллюстрации того, как ра­
ботают вложенные операторы If...Then...Else. Процедура EvalDiscount полу­
чает от пользователя количество покупемого клиентом товара (числовое значе­
ние), а затем оценивает это число и определяет скидку, на которую может рас­
считывать клиент.
Листинг 5.5. Вложенные операторы If...Then...Else

1 Sub EvalDiscount ()
2 'Определение скидки (в %) в зависимости от
3 'количества продаваемого товара
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

Простой выбор

205

Написанная так процедура будет работать только в Excel, так как она ис­
пользует метод Application. InputBox. Этот метод применен для того, чтобы
не дать пользователю во время работы функции InputBox ввести что-либо,
кроме числа. VBA отображает сообщение об ошибке, если пользователь вводит
не число (рис.5.1), и ожидает до тех пор, пока пользователь не введет числен­
ное значение или не выберет кнопку Cancel. Если пользователь, не вводя дан­
ные в окне функции Application. InputBox, щелкнет на кнопке OK, VBA
также выдаст сообщение об ошибке (рис.5.2).
Рис. 5.1

Сообщение Excel при неправильном вводе в окне функции
Application.InputBox

Обратите внимание на степень защищенности программы листинга 5.5 от не­
правильных действий пользователя. Во-первых, функция Application. In­
putBox не дает возможности ввести в окно ввода нечисловое значение. Во-вторых,
если пользователь использует «спасительную» кнопку Cancel, чтобы отказаться от
ввода, программа (в строке 10) проверит результат ввода, который при щелчке на
кнопке Cancel имеет тип Boolean, и выберет необходимую ветвь оператора
If...Then...Else. При щелчке на кнопке Cancel выполнится оператор в строке 23 и
на экран будет выдано сообщение о том, что количество товара не указано.

Рис. 5.2. Сообщение Excel при щелчке на кнопке ОК без ввода данных в окне
функции Application.InputBox

Использование lf...Then...Elself
VBA предоставляет сокращенную версию оператора If...Then...Else, являю­
щуюся сжатым эквивалентом вложенных операторов If...Then...Else, показан­
ных в листинге 5.5. Такой краткой формой является оператор If...Then...ElseIf.
Оператор If...Then...ElseIf имеет следующий синтаксис:

Синтаксис
If Conditionl Then

Statements
Elself Conditions

El selfStatements
[Else

Else Statements]
End If

206

Глава 5. Изменение порядка выполнения операторов в УВА

Condition 1 и Condition2 — любые логические выражения; Statements, ElselfStatements и ElseStatements — один, несколько или ни одного оператора VBA.
При выполнении оператора lf...Then...Elself VBA сначала оценивает логическое вы­
ражение, представленное с помощью Condition 1. Если это выражение равно True, то
VBA выполняет все операторы (представленные с помощью Statements) между клю­
чевыми словами Then и Elself. Затем VBA возобновляет выполнение кода с первого
оператора после ключевых слов End If, которые указывают на конец оператора
If...Then...Elself.

Если логическое выражение Condition 1 равно False, VBA оценивает логическое вы­
ражение, представленное с помощью Condition2. Если выражение Condition2 равно
True, VBA выполняет все операторы (представленные с помощью ElselfStatements)
между ключевым словом Elself и ключевыми словами End If (или необязательным
Else), Затем VBA продолжает выполнение кода с первого оператора, появляющего­
ся после ключевых слов Endlf. Ключевые слова End If должны находиться на отдель­
ной строке.
Если логическое выражение Condition2 равно False, то VBA пропускает
ElselfStatements и продолжает выполнение кода с первого оператора после ключе­
вых слов End If. Можно по желанию включать оператор Else в оператор
If...Then...Elself, Если логическое выражение Conditionl и логическое выражение
Condition2 равны False и имеется оператор Else, то VBA выполняет операторы,
представленные с помощью ElseStatements. После выполнения операторов
ElseStatements VBA продолжает выполнение кода с первого оператора после ключе­
вых слов End If (см. схему 5.4).

ElseStatements

Простой выбор

207

В следующем листинге (5.6) показано, как с учетом вышеизложенного
можно изменить строки 12-20 листинга 5.5.
Листинг 5.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"
16
Else
17
IStr = "0"
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 листинга 5.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...ElseIf показывают, что эти операторы позволяют выбирать из трех вет­
вей кода, но что если необходимо выбрать между 5, 8 или 10 различными воз­
можными действиями?

208

Глава 5. Изменение порядка выполнения операторов в УВА

Для выполнения выбора из нескольких возможных ветвей кода можно
вкладывать операторы 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 Express!onList2

statements2

Case ExpressionListN

statementsN
[Case Else
Else Statements]
End Select

TestExpression — любое численное или строковое выражение. ExpressionListl,
ExpressionList2 и ExpressionListN — (каждый) представляют список логических выра­
жений, отделенных запятыми. Statementsl, statements2, statementsN и ElseStatements (каждый) представляют один, несколько или ни одного оператора VBA. В
Select Case можно включать столько операторов Case Expression List, сколько необ­
ходимо (см. схему 5.5) .

При выполнении VBA-оператора Select Case сначала оценивается
TestExpression, а затем сравнивается результат этого выражения с каждым
выражением, перечисленным в каждом ExpressionList. Если значение, пред­
ставленное с помощью TestExpression совпадает с выражением в Expres­
sionList для одного из Case, VBA выполняет операторы для этого предложе­
ния Case. Если значение TestExpression совпадает более, чем с одним операто­
ром Case, VBA выполняет только операторы в первом совпадающем
предложении Case. Часто TestExpression — это просто имя одной переменной,
математическое или численное, а не логическое выражение. Выражения
в ExpressionList — это обычно логические выражения.

Простой выбор

209

После завершения выполнения операторов в первом совпадающем операто­
ре Case VBA продолжает выполнение кода с первого оператора после ключе­
вых слов End Select, которые обозначают конец Select Case.
Если значение TestExpression не совпадает ни с каким из Case, а необяза­
тельный Case Else присутствует, VBA выполняет операторы, представлен­
ные с помощью ElseStatements перед переходом к оператору после Select
Case.
В отдельных операторах Case выражение ExpressionList может состоять из
одного или более выражений, отделяемых запятой. Список ExpressionList
имеет следующий синтаксис:

Синтаксис
expression!, expression2,

..., expressionN

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

expression! То expression2

210

Глава 5. Изменение порядка выполнения операторов в УВА

Например, для определения диапазона чисел от 10 до 150 в операторе Case
ExpressionList используется следующее выражение:
Cas'e 10 То 150

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

Синтаксис
Is Comparisonoperator expression
В этой строке Comparisonoperator — это любые VBA-операторы отношения, кроме
операторов Is и Like; expression — любое выражение VBA.

Для выполнения операторов в ветви Case, когда, например, TestExpression
больше 10, используется следующее выражение:
Case Is > 10

Ключевое слово Is здесь — это не то же самое, что оператор Is. В этом опе­
раторе Is означает ссылку на TestExpression.
Листинг 5.7 представляет пример оператора Select Case.
Листинг 5.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

Обратите внимание на строки 11-18. После рассмотрения двух предыду­
щих примеров эти строки не могут не вызвать вздох облегчения. Эта конструк­
ция хороша и простотой для понимания, и легкостью при наращивании новых
условий. В остальном код этого примера переписан из предыдущих листингов.

Безусловный переход

211

Безусловный переход
Оператор безусловного перехода, пожалуй, самый спорный оператор во
всех языках программирования. В ранних языках он являлся почти единст­
венным средством организации циклических выполнений блоков кода. Сто­
ронники структурного программирования посвящают много времени критике
программ и языков программирования, в которых используется этот оператор.
Поэтому не очень увлекайтесь применением этого оператора в своем коде и
старайтесь вспоминать о нем только в чрезвычайных ситуациях, когда все
другие средства уже испробованы и не помогли.
Оператор безусловного перехода всегда изменяет порядок выполнения опе­
раторов в процедуре или функции VBA. При этом VBA не проверяет никаких
условий (отсюда термин безусловный (unconditional)), а просто переходит
к выполнению кода с другого места.
VBA имеет только один оператор безусловного перехода: GoTo. Существует
очень мало причин для использования оператора GoTo; в действительности,
процедуры, которые используют несколько операторов GoTo, трудны для по­
нимания. Почти в каждом случае, когда вы можете использовать оператор
GoTo, можно использовать один из операторов If, оператор Select Case или
одну из структур организации циклов, о которых вы узнаете в главе 7, для вы­
полнения той же задачи с большей легкостью и ясностью.
Оператор GoTo остался от ранних версий языка программирования BASIC,
которые не имели сложного оператора принятия решений Select Case, опи­
санного в этой главе, или мощных структур организации циклов. Программи­
сты, работавшие с ранними версиями BASIC, использовали GoTo для имита­
ции результатов более сложных операторов VBA.
Следует знать, как оператор GoTo работает в качестве оператора безусловно­
го перехода, главным образом для того, чтобы понимать, как действует обра­
ботчик ошибок GoTo, но также потому, что вам может встретиться эта коман­
да, используемая другими программистами.
Оператор GoTo имеет следующий синтаксис:

Синтаксис
GoTo line
Выражение line представляет любую допустимую метку или номер строки в той же
процедуре или функции, которая содержит оператор GoTo. При выполнении опера­
тора GoTo VBA немедленно переходит к выполнению оператора в строке, опреде­
ленной с помощью line.

Метка строки (line label) — это особый тип идентификатора, который задает
определенную строку по имени. Метки строк имеют следующий синтаксис:

212

Глава 5. Изменение порядка выполнения операторов в УВА

Синтаксис
Name:
Выражение пате — любой допустимый идентификатор VBA. Метка строки может на­
чинаться в любом столбце в строке, если она является первым непустым символом в
строке. Номер строки (line number) — в основном, то же самое, что и метка строки, но
он является просто номером, а не идентификатором. Использование номеров строк в
процедурах VBA является крайне нежелательным, следует всегда использовать метку
строки вместо них.

В листинге 5.8 показана процедура, демонстрирующая наиболее обоснован­
ное использование оператора GoTo в процедуре VBA: эта процедура использует
оператор GoTo для перехода к концу процедуры при выборе пользователем ко­
мандной кнопки Отмена (Cancel) в окне ввода.
Листинг 5.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 и не выдавать сообщения о том, что количество не было введено.

Использование MsgBox для обеспечения возможности выбора

213

Еще раз отметим, что так процедуры писать не нужно. Это — просто при­
мер оператора GoTo. И лучше пока забыть о существовании этого оператора.

Использование MsgBox для обеспечения
возможности выбора
До сих пор мы использовали оператор MsgBox с целью отображения сообще­
ний для пользователя в диалоговых окнах с заголовками. Как уже отмечалось в
главе 4, при помощи необязательного аргумента Buttons можно использовать
VBA-процедуру MsgBox как функцию для получения выбора от пользователя в
ответ на сообщения или вопросы, которые отображает ваша процедура. Для
многих простых вариантов выбора использование функции MsgBox для получе­
ния ответа от пользователя является гораздо более легким, чем Получение тек­
стового ввода с помощью функции InputBox и последующий анализ этого тек­
ста для определения того, какой выбор сделал пользователь.
При включении аргумента Buttons с необходимыми круглыми скобками
оператор MsgBox работает подобно функции и отображает окно сообщения, со­
держащее различные командные кнопки. MsgBox возвращает численный ре­
зультат, указывающий, какую командную кнопку выбрал пользователь. Чис­
ло и тип командных кнопок, отображаемых диалоговым окном MsgBox, зада­
ется с помощью аргумента Buttons.
В листинге 5.9 показана простая процедура, которая демонстрирует ис­
пользование аргумента Buttons.
Листинг 5.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

214

Глава 5. Изменение порядка выполнения операторов в УВА

Процедура Demo_MsgBoxFunction демонстрирует использование операто­
ра MsgBox как функции, результаты использования различных аргументов
Buttons и оценку значения, которое возвращает функция MsgBox. Диалоговое
окно, в котором пользователю необходимо сделать выбор, представлено на
рис. 5.3. Результаты работы кода этой процедуры при всех трех (по отдельно­
сти, конечно) выборах представлены на рис. 5.4.
Рис. 5.3

Окно кода листинга 5.9 предоставляет пользователю
выбор из трех кнопок

Демонстрация кнопок MsgBox [х|] Демонстрация кнопок MsgBox (Xj;

Демонстрация' кнопок MsgBox | XI

Вы выбрали кнопку 'Отмена'

ж

Ш

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

Аргумент Buttons для MsgBox позволяет задавать количество и тип кнопок
и наличие или отсутствие в окне сообщения одного из значков Windows для
обозначения предупредительного сообщения (Warning message), сообщения за­
проса (Query message), информационного сообщения (Information message)
и критического предупредительного сообщения (Critical Warning message).
Можно также использовать аргумент Buttons для определения того, какая из
отображаемых кнопок (кнопка 1, 2, 3 или 4) является кнопкой по умолчанию
в окне сообщения. Каждый раз можно задавать только один тип кнопки, один
значок и одну кнопку по умолчанию.
Чаще используйте в разрабатываемых вами интерфейсный окнах кнопки
по умолчанию. Это экономит пользователям таких программ много времени,
так как всегда можно для подачи команды приложению вместо мыши исполь­
зовать клавиатуру. Понятно, что «ударить» по кнопке Enter на клавиатуре
быстрее и легче, чем переместить мышь (не всегда в хорошем состоянии) в оп­
ределенное место на экране и щелкнуть левой клавишей.
В строке 9 (часть оператора вызова функции MsgBox, начинающегося в
строке 7) константа vbYesNoCancel определяет, что диалоговое окно MsgBox
должно содержать три командные кнопки: кнопку Yes (Да), кнопку No (Нет) и
кнопку Cancel (Отмена). Константа vbQuestion определяет, что окно сообще­
ния должно содержать значок сообщения запроса (Query message) Windows.
Как только пользователь выбирает командную кнопку в окне сообщения,
VBA возвращает численное значение, соответствующее выбору пользователя.
В строке 7 результат функции MsgBox присваивается переменной Resp. VBA
использует различные значения в зависимости от того, какую командную
кнопку выбрал пользователь: одно значение для обозначения кнопки Yes, дру­

Использование MsgBox для обеспечения возможности выбора

215

гое — для обозначения кнопки No и еще одно — для кнопки Cancel. Функция
MsgBox может также отображать окна с кнопками Abort (Стоп), Retry (Повтор) и
Ignore (Пропустить) в различных комбинациях. Поскольку каждая кнопка
имеет свое определенное возвращаемое значение, VBA имеет несколько внут­
ренних констант для представления возможных возвращаемых значений
функции MsgBox. Полный список значений констант VBA, которые может
возвращать MsgBox, приведен в главе 4.
В строке 10 начинается оператор Select Case, который оценивает значе­
ние, возвращаемое функцией MsgBox в строке 7 и сохраняемое в переменной
Resp. Тестовое выражение для оператора Select Case — это сама переменная
Resp, поэтому VBA сравнивает значение в переменной Resp, чтобы проверить,
совпадает ли оно с каким-либо условием Case в операторе Select Case.
Помните, что можно увидеть все доступные внутренние константы, имею­
щие отношение к MsgBox, в окне Object Browser (Просмотр объектов). Для про­
смотра внутренних констант аргумента Buttons выберите VBA в списке Ргоject/Library (Проект | Библиотека) в окне Object Browser, а затем выберите
VbMsgBoxStyle в списке Classes (Классы); список Members of 'VbMsgBoxStyle' (Ком­
понент) отображает внутренние константы для значений аргумента Buttons.
Если вы выберете VbMsgBoxResult в списке Classes, список Members of
'VbMsgBoxResult' отображает внутренние константы для возвращаемого значения
функции MsgBox.
. Остается один элемент, который можно задать с помощью аргумента
Buttons для MsgBox и который не был включен в листинг 5.9: можно указать,
является ли первая, вторая, третья или четвертая командная кнопка в окнах
MsgBox кнопкой по умолчанию.
Как вы видели до сих пор, MsgBox обычно делает первую командную кноп­
ку в своем окне кнопкой по умолчанию. Посмотрите на рис. 5.3 и обратите
внимание, что кнопка Да (Yes) помечена как кнопка по умолчанию. Если после
того, как VBA отобразит это диалоговое окно, пользователь нажимает на кла­
вишу Enter, VBA действует так, как если бы пользователь выбрал кнопку Да.
Вам может понадобиться, чтобы кнопкой по умолчанию была какая-либо
другая кнопка, а не первая в списке в окне сообщения. Например, если вы ис­
пользуете MsgBox для запроса от пользователя подтверждения удалить рабо­
чий лист в рабочей книге, может быть предпочтительнее, чтобы командной
кнопкой по умолчанию была кнопка No, а не кнопка Yes; поскольку удален­
ный рабочий лист не может быть восстановлен, имеет смысл помочь пользова­
телю избежать нечаянного подтверждения удаления при простом нажатии на
клавишу Enter.

Рис. 5.5

Сравните это диалоговое окно с окном, показанным
на рис. 5.3. Заметьте, что кнопка No является теперь
командной кнопкой по умолчанию как результат
добавления vbDefaultButton2 к аргументу Buttons

Чтобы изменить командную кнопку по умолчанию, добавьте одну из
внутренних констант VBA — vbDefaultButtonl, vbDefaultButton2,

216

Глава 5. Изменение порядка выполнения операторов в УВА

vbDe£aultButton3 или vbDefaultButton4 — к аргументу Buttons. Сле­
дующий фрагмент процедуры показывает оператор MsgBox из строк 7-9
листинга 5.9, модифицированный так, чтобы командной кнопкой по умол­
чанию в окне сообщения была кнопка No:
Resp = MsgBox(prompt:="Выберите кнопку",
Title:=mTitle, _
Buttons:=vbYesNoCancel + vbQuestion +
VbDefaultButton2)

При выполнении этого оператора VBA отображает диалоговое окно, пока­
занное на рис. 5.5. Это окно идентично окну, показанному ранее на рис. 5.3, за
исключением того, что добавление значения vbDefaultButton2 к аргументу
Buttons делает вторую кнопку (в данном случае — кнопку No) кнопкой по
умолчанию.

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

Раннее окончание процедур, функций и целых программ
Существуют обстоятельства, такие как отмена окна ввода пользователем
или отсутствие некоторых ожидаемых данных, при которых нет смысла про­
должать выполнение процедуры или функции. Если у вас имеется программа,
содержащая процедуры, которые вызывают другие функции и процедуры, вы
можете задать условия, при которых вся программа должна прекращать вы­
полнение: например, отсутствует рабочий лист, диапазон, документ и так да­
лее.
VBA имеет операторы Exit и End, которые дают возможность либо завер­
шать процедуру или функцию, либо останавливать всю программу.

Использование оператора Exit
Для того чтобы процедура или функция прекратила выполнение, использу­
ется одна из двух доступных форм VBA-оператора Exit, в зависимости от того,
необходимо ли завершить функцию или процедуру.
Оператор Exit имеет две синтаксические формы:
Exit Sub
Exit Function

Exit Sub и Exit Function работают одинаково и имеют один и тот же ре­
зультат; Exit Sub используется для окончания процедуры, a Exit Function —
для окончания функции.
Сначала рассмотрим простой пример — листинг 5.10, который отличается
от листинга 5.8 тем, что в нем нет оператора GoTo.

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

217

Листинг 5.10. Пример использования оператора Exit Sub

1: Sub EvalDiscount5()
2: 'Определение скидки (в %) в зависимости от
3: 'количества продаваемого товара
4:
Dim IStr As String
5:
Dim IntNum
6:
IntNum = Application.InputBox(
7: ■ ,
prompt:“"Введите количество товара",
8:
Title:“"Процедура EvalDiscount5",
9:
,
Type:=l)
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) & ". Скидка " & IStr & "%"
26:
2 7 : End Sub

В строках 11-14 этой процедуры содержится код проверки того, была ли
выбрана пользователем в окне ввода кнопка Cancel. Если это — так, программа
выдает сообщение о том, что количество не указано, и прекращает выполнение
кода оператором Exit Sub. Для такой небольшой задачи это — самый подхо­
дящий код. Видимо, даже сторонники структурного программирования не
найдут здесь причин для критики, хотя оператор Exit Sub также нельзя отне­
сти к структурным языковым конструкциям.
В листинге 5.11 приведена процедура MakeSalesRpt_Chart, в которой так­
же для раннего окончания процедуры используются операторы Exit Sub.
Причиной раннего окончания процедуры является отказ пользователя от вво­
да имени рабочего листа (в Excel). Можно только представить последствия вы­
полнения кода без проверки того, ввел ли пользователь имя листа для даль­
нейшей его обработки!
Листинг 5.11. Использование оператора Exit Sub

1:
2:
3:
4:
5:
6:
7:
8:

Sub MakeSalesRpt_Chart()
'Запрашивает имя листа, содержащего исходные данные,
'затем запрашивает диапазон ячеек с данными для диаграммы.
'Далее запрашивается имя листа для помещения в него круговой
'диаграммы. Затем процедура создает диаграмму и использует
'метод Chartwizard для получения круговой диаграммы
Const sTitle = "Отчет о продажах"

218

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:

Глава 5. Изменение порядка выполнения операторов в УВА

Dim SrcShtName As String
Dim SourceRng As String
Dim DestShtName As String
'получить имя исходного листа
SrcShtName = InputBox(prompt:= _
"Введите имя листа, " &
"содержащего данные для диаграммы",
Title: =sTitle)
10 Then
MsgBox prompt:="Вы ввели четное число, " &
"большее, чем 10 - Цикл заканчивается",
Title:=evTitle
EvenFlag = True
Else
MsgBox prompt:="Вы ввели четное число, " &
"меньшее, чем (или равное) 10",
Title:=evTitle
End If
Else
MsgBox prompt:="Вы ввели нечетное число",
Title:=evTitle
End If
Loop
MsgBox prompt:="Выполнение цикла прекращено", Title:=evTitle
End Sub

Процедура Test_DoUntil показывает, как построить цикл Do Until. Цикл
в этой процедуре демонстрирует управляемый условием цикл и выполняется
до тех пор, пока пользователь не введет четное число, большее 10. Условие, за­
канчивающее выполнение цикла — это ввод пользователем четного числа. На
самом деле, этим условием является получение значения True переменной
EvenFlag, что происходит (в строке 19), когда код обнаруживает с помощью
вложенных операторов If (в строках 14-15) факт введения пользователем чет­
ного числа, большего 10.
Перед выполнением цикла переменной EvenFlag присваивается значение
False, чем и обеспечивается, по крайней мере, первое выполнение цикла.
Внутри цикла организуется прием числа, и анализ его на предмет четности
и превышения 10. Если эти последние проверки дают положительный резуль­
тат, выводится сообщение (строки 16-17) об окончании цикла и переменная
EvenFlag получает значение True, что приводит к окончанию цикла.

Глава 7. Повторение действий в Visual Basic: циклы и массивы

294

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

Использование циклов, тестирующих условия
после выполнения тела цикла
Для VBA-тестирования условий после выполнения тела цикла необходимо
поместить логическое выражение для детерминанта цикла в конец блока опе­
раторов, составляющих тело цикла, после ключевого слова Loop, которое сооб­
щает о конце цикла.
Циклы Do...Loop While

Первая рассматриваемая нами конструкция цикла, тестирующая условие
детерминанта после выполнения тела цикла, — это Do...Loop While.
Оператор Do...Loop While имеет следующий синтаксис:

Синтаксис
Do

Statements
Loop While Condition

Statements — один, ни одного или несколько операторов VBA, составляющих тело
цикла. Ключевое слово Loop после Statements обозначает конец тела цикла и также
указывает место, из которого VBA возвращается в начало цикла; Condition представ­
ляет логическое выражение для детерминанта цикла (см. схему 7.3).

В этой форме синтаксиса оператора Do...Loop While VBA проверяет условие
детерминанта после выполнения операторов цикла. Поскольку эта форма опе­
ратора Do использует ключевое слово While, VBA выполняет цикл, пока логи­
ческое выражение, представленное с помощью Condition, равно True.
При выполнении оператора Do...Loop While VBA сначала выполняет опера­
торы, представленные с помощью Statements. Когда VBA достигает ключевых

Повторение цикла фиксированное число раз: циклы For

295

слов Loop While, выполняется тестирование логического выражения, пред­
ставленного с помощью Condition', если это выражение равно True, VBA воз­
вращается в начало цикла и снова выполняет тело цикла. Когда VBA снова
достигает ключевых слов Loop While в конце цикла, снова выполняется про­
верка, является ли логическое выражение Condition все еще равным True.
Если Condition равно True, VBA выполняет цикл снова; если — нет, VBA про­
должает выполнение кода с любых операторов после строки, содержащей клю­
чевое слово Loop, т.е. прекращает работу цикла.
Заметьте, что независимо от значения логического выражения, представ­
ленного с помощью выражения Condition, этот цикл всегда выполняется, по
крайней мере, один раз. (Сравните с циклами, проверяющими условие детер­
минанта до выполнения тела цикла.)
Процедура Test_DoLoopWhile в листинге 7.9 использует конструкцию цик­
ла Do...Loop While для получения в диалоговом окне данных от пользователя
до тех пор, пока пользователь не введет слово «exit», указывая на то, что ввод
данных завершен.
Листинг 7.9. Пример использования структуры Do...Loop While

1: Sub Test_DoLoopWhile()
2:
'демонстрирует структуру 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:=iTitle,
12:
Default:="exit")
13:
'операторы обработки или проверки вводимых данных
14:
'или сохранения данных в ячейках рабочего листа и т.д.
15:
MsgBox рготрб:="Вы ввели: " & 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.

296

Глава 7. Повторение действий в Visual Basic: циклы и массивы

Оператор Do...Loop Until имеет следующий синтаксис:

Синтаксис
Do

Statements
Loop Until Condition

Statements представляет операторы VBA, составляющие тело цикла; Condition — ло­
гическое выражение для детерминанта цикла (см. диаграмму синтаксиса цикла
Do...Loop While).

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 в листинге 7.10 использует конструкцию
цикла Do...Loop While для получения данных ввода от пользователя до тех
пор, пока пользователь не введет слово «exit», указывая на то, что ввод дан­
ных завершен.
Листинг 7.10. Пример использования структуры Do...Loop Until

1:

2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:'

Sub Test_DoLoopUntil()
'демонстрирует структуру Do...Loop Until. Цикл
'повторяется, пока не будет введено слово "exit"
Const ilitle = "Ввод данных"
Dim uStr As String
Do

uStr = InputBox(prompt:="Введите строку " &
"('exit' для окончания):",
Title:=iTitle,
Default:="exit")
'операторы обработки или проверки вводимых данных
'или сохранения данных в ячейках рабочего листа и т.д.
MsgBox prompt:="Вы ввели: " & uStr, Title:=iTitle

Вложенные циклы

297

16:
Loop Until uStr = "exit"
17 :
18:
MsgBox prompt:="Ввод данных завершен.",
19:
Title:=iTitle, buttons:=vbExclamation
20: End Sub

Код этого листинга практически ничем не отличается от кода предыдущего
листинга, кроме того, что здесь используется структура Do...Loop Until, а не
Do...Loop While (строка 16).

Вложенные циклы
Можно помещать циклы внутрь других циклов, аналогично тому, как мож­
но помещать операторы If...Then один в другой. Помещение одной структуры
цикла в другую называют вложением (nesting) циклов. Можно помещать
структуры циклов любого типа (смешанные For и Do циклы) в любой уровень.
□ При вложении циклов необходимо соблюдать следующие правила:
□ При вложении циклов For...Next каждый цикл должен иметь свою уни­
кальную переменную счетчика.
□ При вложении циклов For Each...Next каждый цикл должен иметь свою
уникальную е/етпелг-переменную.
□ Если вы используете оператор Exit For или Exit Do во вложенном цик­
ле, этим оператором заканчивается только выполняемый в данный мо­
мент цикл; VBA продолжает выполнение следующего цикла более высо­
кого уровня.

Вложение циклов For
В листинге 7.11 показана простая процедура, которая использует вложен­
ные циклы For...Next. Процедура Test_ForNext предназначена для использо­
вания в Excel и применяет полужирный шрифт к первым п (вводится пользо­
вателем) строкам первых ш (вводится пользователем) столбцов активного
в данный момент рабочего листа. Внешний цикл в процедуре считает строки,
а внутренний — столбцы.
Листинг 7.11. Вложенные циклы For...Next

1: Sub Test_ForNext()
2:
'Применяет шрифт Arial, полужирный
3:
'к первым п строкам и m столбцам активной рабочей
4:
Dim sTitle As String
5:
Dim Rnum As Integer, Cnum As Integer
6:
7:
Dim n As Integer, m As Integer
8:
sTi.tle = "Форматирование ячеек листа"
9:
10:
n = Application.InputBox(prompt:="Введите число
11:
Title^"Форматирование ячеек",
12:
If' n - 0 Then Exit Sub
13:
14:
m = Application.InputBox(prompt:="Введите число

книги

строк",
Type:=1)
столбцов", _

298

Глава 7. Повторение действий в Visual Basic: циклы и массивы

15:
Title:^'Форматирование ячеек", Туре:=1)
16:
If m = 0 Then Exit Sub
17:
18:
Worksheets("Sheetl").Activate
19:
For Rnum = 1 To n
20:
For Cnum = 1 To m
21:
22:
Cells(Rnum, Cnum).Select
23:
24:
With Selection.Font
25:
.Name = "Arial"
26:
.Fontstyle = "Bold"
27:
' .Strikethrough = False
28:
.Superscript = False
29:
.Subscript = False
30:
.OutlineFont = False
31:
.Shadow = False
32:
.Underline = xlNone
33:
.Colorindex = xlAutomatic
34:
End With
35:
36:
Next Cnum
37:
Next Rnum
38: End Sub

Процедура Test_ForNext использует циклы For...Next, один, вложенный
в другой, для применения полужирного шрифта Arial к ячейкам листа, начи­
ная с первой и заканчивая в строке п и столбце т. Значения пит вводятся
в строках 10-11, 14-15 при помощи метода Application. InputBox, кото­
рый, как уже отмечалось, позволяет сократить проверочный код пользователя
использованием необязательного аргумента Туре. При значении Туре, равном
1, пользователь не сможет ввести в окне ввода ничего, кроме числа. Вы може­
те сами в этом убедиться. Набор чего-либо, не похожего на число, приведет
к выдаче окна сообщения, подобного приведенному на рис. 7.3.
Рис. 7.3

Excel-метод Application.InputBox
не позволяет вводить ничего, кроме
того, что определено его
необязательным аргументом Туре

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

Вложенные циклы

299

Счетчик внешнего цикла 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
В листинге 7.12 показана процедура, использующая вложенные циклы Do,
чтобы пользователь мог выполнить ввод данных, необходимых для получения
накладной. Внешний цикл в процедуре Makelnv получает номера накладных
от пользователя до тех пор, пока пользователь не отменит окно ввода. Внут­
ренний цикл в процедуре Makelnv получает элементы записей накладной до
тех пор, пока пользователь не отменит окно ввода. Когда вы будете изучать эту
процедуру, помните, что это просто эскизная процедура. На самом деле вам,
вероятно, потребуется получить гораздо больше информации, чем использует­
ся здесь. Вам, конечно, предстоит также самим писать код для занесения вво­
димой информации в какие-либо хранилища данных. (Листинг 7.12 будет вы­
полняться и в Excel, и в Word).
Листинг 7.12. Вложенные циклы Do

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

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

Const miTitle = ""

Dim InvcNum As String * 5
Dim ItemNuml As String * 16
Dim ItemNum2 As String * 16

'номер накладной

300

Глава 7, Повторение действий в Visual Basic: циклы и массивы

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:
. End If
27:
28:
pos = 1
29:
Do Until False
'цикл для получения элемента строки
30:
31:
'Ввод наименования товара
32:
ItemNuml = InputBox(prompt :=
33:
"Введите наименование товара",
34:
Title:="Накладная №" & InvcNum & "Позиция №" & роз)
35:
If Trim(ItemNuml) = "" Then
36:
MsgBox prompt:="Ввод позиций для накладной №" &
37:
InvcNum & " завершен.",
38 :
Title:=miTitle
39:
Exit Do
40:
End If
41:
42:
'ввод количества товара
ItemNum2 = InputBox(prompt:= _
43:
"Введите количество товара",
44 :
45:
Title:="Накладная №" & InvcNum & "Позиция №" & pos)
46:
If Trim(ItemNum2) = "" Then
47:
MsgBox prompt:="Ввод позиций для накладной №" &
48:
InvcNum & " завершен.",
49:
Title:=miTitle
50:
Exit Do
51:
End If
52 :
'операторы для сохранения вводимых данных, получения
53:
'большей информации об элементе записи и т.д.
54 :
MsgBox prompt:="Введенный элемент №" & pos & " " &
55:
ItemNuml & " кол-во " & ItemNum2 &
56:
" в накладной №" & InvcNum,
57 :
58:
Title:="Контрольная выдача "
59:
60:
pos = pos + 1
61:
Loop
62:
Loop
63:
MsgBox prompt:="Ввод накладной завершен", Title:=miTitle
64:
65: End Sub

Вложенные циклы

301

Процедура 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) производится контрольная выдача введен­
ных данных на экран.

Пример использования коллекции в Word
Предыдущая глава была посвящена объектам и коллекциям приложений.
Здесь мы рассмотрим пример использования коллекции Selection в Word
(текущая выделенная часть) с применением цикла For...Next.
Для выделения в тексте данной книги наименований элементов управления
диалоговых окон используется шрифт Arial, Bold. Например, кнопка Cancel.
При первой верстке оказалось, что на фоне основного текста такой шрифт
слишком велик. Правильнее было бы уменьшить его на один пункт. Так воз­
никла задача — написать макрос, который должен уменьшить размер шрифта
для слов, отформатированных при помощи Arial, Bold.
В листинге 7.13 приведен код процедуры, которая (в строке 6) определяет коли­
чество выделенных абзацев, а затем в цикле For...Next (строки 9-22) для каждого
абзаца проверяет его стиль (свойство Selection.Paragraphs (i) .Style). Если
наименование стиля совпадает с «Обычный», «Рис текст» и др., то во вложенном
цикле (строки 15-20) для каждого слова абзаца проверяется имя фонта. При сов­
падении его с Arial свойство Font. Size уменьшается на единицу (строка 17).
Листинг 7.13. Форматирование отдельных слов документа

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

Sub ЗаменаАг1а1()
'уменьшает размер слова,' отформатированного как Aria, Bold
Dim ZZ

'количество выделенных абзацев:
ii = Selection.Paragraphs.Count()
'цикл по абзацам:
For i = 1 То ii
If Selection.Paragraphs(i).Style = "Обычный" Or _
Selection.Paragraphs(i).Style = "Рис_текст" Or

Глава 7. Повторение действий в Visual Basic: циклы и массивы

302

Selection.Paragraphs(i).Style = "Рис_номер"
Or Selection.Paragraphs(i).Style = "Основной текст"
Or Selection.Paragraphs(i).Style = "No" Then
For j = 1 To Selection.Paragraphs(i).Range.Words.Count
If Selection.Paragraphs(i).Range.Words(j).Font.Name =
"Arial" Then
ZZ =
Selection.Paragraphs(i).Range.Words(j).Font.Size - 1
Selection.Paragraphs(i).Range.Words(j).Font.Size = ZZ
End If
Next
End If

12:
13:
14:
15:
16:
17:
18:
19:
2 0:
21:
22:
23:
24:

Next
End Sub

Массивы
Массив (array) — это коллекция переменных, которые имеют общие имя
и базовый тип. Массив является удобным способом хранения нескольких свя­
занных элементов данных в едином контейнере для большего удобства и эф­
фективности программирования. Все элементы данных, сохраняемых в масси­
ве, должны иметь один и тот же тип; например, при создании массива для со­
хранения типов Integer (Double, String, Currency и т.д.) все элементы
данных, сохраненных в этом массиве, должны быть числами Integer (Doub­
le, String, Currency и т.д.).
Массив позволяет сохранять и манипулировать многими элементами дан­
ных посредством единственной переменной. Кроме уменьшения общего числа
различных имен переменных, которые необходимо отслеживать, другим ос­
новным преимуществом использования массивов является то, что можно ис­
пользовать циклы для легкой обработки различных элементов массивов. Объе­
диняя массивы и структуры цикла (обычно For...Next или For...Each), можно
написать небольшое число операторов, которые обрабатывают большой объем
данных. Выполнение тех же задач с использованием отдельных переменных
может потребовать написания сотен операторов.

Размерность массива
В языках программирования обычно используются одномерные и много­
мерные массивы, одни из которых описывают относительно простые, а дру­
гие — более сложные объекты.

Одномерные массивы
Наименее сложный массив — это просто список элементов данных; такого
рода массив называется простым (simple) или одномерным (single-dimensional)
массивом. Такой массив можно представить в виде таблицы (рис. 7.4). Каждый
элемент данных, хранимых в массиве, называется элементом (element) масси­
ва. Массив на рис. 7.4 имеет 8 элементов; каждый элемент сохраняет число
типа Double. Заметьте, что элементы в массиве пронумерованы от 0 до 7, что
составляет 8 элементов. Такая система нумерации довольно распространена
в программировании и называется нумерацией с нулевой базой (zero-based).

Массивы

303

Для доступа к данным, хранящимся в определенном элементе массива, сле­
дует указывать имя массива с последующим числом, называемым индексом
(subscript или index) элемента. Индекс всегда заключается в круглые скобки.
Например, если массив на рис. 7.4 имеет имя DoubleArray, то следующий опе­
ратор присваивает число 0.11 переменной DoubleAny:
DoubleAny = DoubleArray (6)

В этом операторе число 6 является индексом массива; заметьте, что он за­
ключен в круглые скобки и не отделяется пробелами от имени массива. По­
скольку нумерация элементов начинается с нуля, элемент, на который ссыла­
ется этот оператор, является, фактически, седьмым элементом массива
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-й
элемент

Рис. 7.4. Одномерный числовой массив; одномерные массивы — это, в основном,

просто списки данных одного и того же типа

Посмотрите снова на рис. 7.4 и обратите внимание, что элемент массива
с номером 6 содержит значение 0.11. При выполнении приведенного выше
оператора VBA выбирает значение 0.11 из указанного элемента массива и со­
храняет это значение в переменной DoubleAny — точно так же, как в любом
другом присваивании переменной.
Можно также использовать индекс всякий раз, когда необходимо сохра­
нить данные в отдельном элементе массива. Например, следующий опера­
тор сохраняет число 12.3 в восьмом элементе массива, показанном на
рис. 7.4:
DoubleArray (7) =12.3

При выполнении этого оператора VBA помещает значение 12.3 в указанный
элемент массива, заменяя предыдущее содержимое этого элемента — точно
так же, как в любом другом присваивании переменной. Можно использовать
элемент массива в любом выражении VBA — точно так же, как используется
значение константы или переменной в каком-либо выражении.
Одномерные массивы обычно используются для представления различных
списков данных.
Многомерные массивы
Одномерные массивы хорошо подходят для представления простых списков
данных. Однако часто бывает необходимо представить таблицы данных в про­
граммах с организацией данных в формате строк и столбцов, подобно ячейкам
в рабочих листах Excel. Для этого необходимо использовать многомерные
(multi-dimensional) массивы. Поскольку вы уже имеете опыт работы с ячейка­
ми Excel, то нет необходимости в подробном разъяснении сущности двумерно­
го массива. Адрес каждой ячейки листа состоит из двух чисел (измерений),
одно из которых (номер строки) является первым индексом, а второе (номер
столбца) — вторым индексом массива. На примере организации листов Excel

304

Глава 7, Повторение действий в Visual Basic: циклы и массивы

можно представить и трехмерные массивы. Здесь третьим индексом массива
может быть номер листа.
В VBA можно, также создавать массивы, имеющие более трех измерений;
фактически, VBA позволяет создавать массивы, имеющие до 60 измерений. Ра­
бота с массивами, имеющими 4 или более измерений, быстро становится запу­
танной; к счастью, вам, вероятно, не придется работать с такими массивами.
Чаще всего в программировании используются одно- и двумерные массивы.

Статические и динамические массивы
В следующем разделе вы узнаете, что число элементов в массиве обычно за­
дается’во время объявления массива. Объявление массива указывает VBA ве­
личину различных измерений массива (диапазон изменения каждого индек­
са). После того как массив объявлен, VBA выделяет достаточный объем памя­
ти для всех элементов массива. Например, для массива на рис. 7.4 VBA
выделит объем памяти, достаточный для 8 чисел типа Double.
Переменные типа массив подчиняются тем же правилам области действия,
что и любые другие переменные.
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.

Массивы

305

Директива компилятора 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
Option Base 1

'установка по умолчанию
'индексы массивов начинаются с 1

Объявление массивов
Вы уже знакомы с оператором Dim, используемым для объявления перемен­
ных. Этот же оператор используется и для объявления массивов. В действитель­
ности, ключевое слово Dim является сокращением слова dimension (измерение).
В оригинальном языке программирования BASIC ключевое слово Dim использо­
валось исключительно для изменения размеров массивов (dimensioning), отсюда
и сокращение Dim. Однако современный язык VBA расширил использование
ключевого слова Dim до использования со всеми переменными. С помощью Dim
можно объявлять как одномерные, так и многомерные массивы.
Объявление массива с помощью оператора Dim имеет следующий синтаксис:

Синтаксис
Dim VarName([Subscripts])

[As Type]

VarName — любое имя для массива, удовлетворяющее VBA-правилам для имен
идентификаторов. Subscripts — измерение (измерения) массива-. Можно объявлять
массивы, имеющие до 60 измерений. Для одномерного массива включается один
Subscripts-, для двумерного массива — два (отделенные друг от друга запятой) и так
далее. Каждый Subscripts добавляет новое измерение в массив.
Можно также объявлять статические и динамические массивы, используя
ключевые слова Public, Private и Static — точно так же, как для любой
другой переменной и с тем же влиянием на область действия. Используйте по­
казанный здесь синтаксис объявления массива и просто подставляйте ключе­
вое слово Public, Private или Static вместо ключевого слова Dim, если не­
обходимо.

306

Глава 7. Повторение действий в Visual Basic: циклы и массивы

Оператор Subscripts имеет следующий синтаксис:

Синтаксис
[lower То] upper [,[lower То] upper]...
Здесь lower определяет нижний диапазон допустимых индексов для массива;
upper — верхний предел. Заметьте, что только верхний предел является обязатель­
ным; часть tower То оператора 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).
Следующие примеры являются допустимыми объявлениями массива:
Dim str_array(l То 100) As String
Dim variant_array()
Dim str_Multiplication(0 To 15, 0 To 15) As String

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

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

Массивы

307

Синтаксис
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
Рассмотрим простой пример работы с одномерным массивом, представлен­
ный кодом листинга 7.14. Процедура в первом цикле For...Next принимает
в диалоговом окне целые числа (для простоты без всякой проверки) и заносит
их в элементы массива. Во втором цикле значения элементов массива заносят­
ся в строку и выводятся на экран в диалоговом окне оператора MsgBox.
Листинг 7.14. Работа со статическим одномерным массивом

1: Sub DemoStatArray()
2:
Dim Int_Array(5) As Integer
3:
Dim str_msg AsString
4:
5:
str_msg = ""
6:
7:
For i = 1 To 5
8: .
Int_Array(i) = InputBox("Введите целое число для "
9:
& i & "-го элемента массива",
10:
"Ввод элементов массива")
11:
Next
12 :
13:
For j = 1 То 5
14:
str_msg = str_msg & Int_Array(j) & ", "
15:
Next
16:
17:
MsgBox "Введено: " & str_msg, _
18:
, "Вывод ранее введенного массива"
19:
20: End Sub

308

Глава 7. Повторение действий в Visual Basic: циклы и массивы

В строке 2 объявляется одномерный массив Int_Array (размерностью 5 эле­
ментов) целых чисел Int_Array. Далее (строка 3) объявлена рабочая перемен­
ная str_msg для завершающего вывода данных из массива в диалоговом окне
(строка 19). В первом цикле For...Next (строки 7-11) в массив Int_Array запи­
сываются значения из окна ввода. Обратите внимание, как формируется зна­
чение аргумента Prompt функции InputBox. На рис. 7.5 приведен фрагмент
ввода 3-го элемента массива.
Рис. 7.5

Фрагмент ввода 3-го элемента массива

В строках 13-15 располагается второй цикл, который формирует строку из
значений элементов массива для выдачи ее в диалоговом окне (рис. 7.6).
Рис. 7.6

Вывод ранее введенного массива |.Х|

Результат работы кода листинга 7.14
Введено: 4, 5. 76, 4, 56,

Процедура DemoStatArray2 в листинге 7.15 предназначена для демонстра­
ции работы с двумерным массивом.
Листинг 7.15. Работа со статическим двумерным массивом

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
For j = 1 To 6 .
8:
Int_Array(i,j)=InputBox("Введите целое число для "
9:
& " элемента (" & i & ", " & j & ") ",
10:
"Ввод элементов массива; строка " & i)
11:
12:
Next j
Next i
13:
14:
15:
For i = 1 To 3
16:
For j = 1 To 6
.str msg = str_msg & Int_Array(i, j) & ", "
17 :
Next j
18.:
19:
str__msg = str_msg & Chr (13) 'перевод строки
20:
Next i
21:

Массивы

309

22 :
23:
MsgBox "Введено: " & Chr(13) & str_msg,
24:
, "Вывод ранее введенного массива"
25:
26: End Sub

Для инициализации массива используется вложенный цикл в строках
7-13. Обратите внимание на строки 12-13. Здесь, как ранее отмечалось, ука­
зывается, по какой переменной заканчивается цикл. Это необязательно, но
лучше привыкнуть к такому стилю программирования с самого начала.
В окне ввода теперь для указания, какой элемент вводится в конкретный
момент времени, выводятся оба индекса (рис. 7.7). Это уже довольно дружест­
венный интерфейс для ввода двумерного массива: пользователю трудно не до­
гадаться, чего от него «добивается» программа. Чтобы понять, как это дости­
гается, внимательно проанализируйте оператор в строках 9-11.
Рис. 7.7

Дружественный интерфейс для ввода
элемента двумерного массива

Вторая часть процедуры DemoStatArray2 также состоит из вложенных
циклов и, как и в предыдущем листинге, эта часть предназначена для выдачи
инициализированного массива в окне MsgBox при помощи переменной
str_msg. Для осуществления этой задачи во внутреннем цикле (строки 16-18)
формируется строка из элементов массива при постоянном первом индексе (пе­
ременная i). При этом меняется только второй индекс (переменная j). После
заполнения строки, но перед изменением первого индекса к переменной
str_msg добавляется символ перехода на другую строку (строка 20).
Результат работы кода листинга 7.15 приведен на рис. 7.8.
Рис. 7.8

В результате работы кода листинга 7.15
инициализирован массив размерностью 3x6

Вывод ранее введенного массива
Введено:
3, 3,6, 45, 52, 56,
3,55, 6, 7, 3, 32,
44,22,11, 54, 67, 45,

ок ..Д

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

310

Глава 7. Повторение действий в Visual Basic: циклы и массивы

Динамические массивы создаются с помощью оператора Dim, затем их размер
устанавливается с помощью оператора ReDim во время выполнения процедуры.
Оператор ReDim имеет следующий синтаксис:

Синтаксис
ReDim [Preserve] varname(subscripts)
varname(subscripts) [As type]]

[As type]

[,

Необязательное ключевое слово Preserve, как предполагает его имя, приводит
к тому, что VBA сохраняет данные в имеющемся массиве, когда изменяется размер
массива с помощью ReDim; varname — имя существующего массива; subscripts — это
измерения массива (синтаксис для оператора subscripts в операторе ReDim такой же,
как для оператора Dim); type — любой тип VBA или определенный пользователем тип.
Необходимо использовать отдельный оператор As type для каждого массива, который
вы определяете.

Далее следуют допустимые примеры объявлений динамических массивов
и возможные операторы ReDim, используемые с этими динамическими масси­
вами:
Dim aMonth() As String
ReDim aMonth(l To 30)
ReDim aMonth(31)
ReDim Preserve aMonth(l To

'объявляет динамический массив aMonth
'изменяет размер массива до 30 элементов
'изменяет размер массива до 31 элемента
31) 'изменяет размер массива до 31
'элемента, сохраняя содержимое
Dim Table()As Integer
'объявляет динамический массив
'делает массив двумерным
ReDim Table(3, 15)
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 для измене­
ния типа данных массива, если только массив не содержится в переменной
типа Variant или сами элементы массива не имеют тип Variant. Если дина­
мический массив сохраняется в переменной типа Variant, можно изменять
тип данных, используя оператор As type в операторе ReDim.

Массивы

311

Замечание
Попытка использовать ReDim для статического массива (массив, измерения кото­
рого были явно определены в объявлении Dim, Public, Private или Static) приводит
к тому, что VBA отображает runtime-ошибку.

Код листинга 7.16 является примером использования динамического одно­
мерного массива и выполняет задачу ввода данных в массив, подобную решае­
мой в листинге 7:14. Это делается для того, чтобы концентрировать внимание
читателя на отличиях использования разных типов массивов, а не деталях
различных задач.
Листинг 7.16. Работа с динамическим одномерным массивом

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:
str msg = ""
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:
'изменение размера массива
18:
'с сохранением элементов
19:
ReDim Preserve Int__Array (i)
20:
21:
'ввод данных в i-й элемент массива
22 :
Int_Array(i) = Num
Loop
23:
24:
25:
For j = 1 To i - 1
2 6:
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) вводятся значения для
элементов массива. Если значение введено (пользователь не отказался от ввода

312

Глава 7. Повторение действий в Visual Basic: циклы и массивы

посредством кнопки Cancel), размерность массива увеличивается (строка 19)
с сохранением предыдущих значений элементов массива и очередному (ново­
му) элементу массива присваивается введенное значение (строка 22). За коли­
чеством элементов в массиве «следит» целая переменная i, значение которой
увеличивается в начале цикла. Если пользователь отказывается от ввода, опе­
ратор Exit Do (строка 15) прекращает работу цикла Do. При этом значение пе­
ременной i в этот момент оказывается на единицу больше размерности масси­
ва: оператор в строке 11 выполнился (увеличение i), а в строке 19 — нет (уве­
личение размерности массива).
Во второй части процедуры размерность массива уже известна (i—1), поэто­
му можно для формирования строки выдачи на экран использовать цикл с оп­
ределенным количеством итераций, т.е. цикл For...Next (строки 25-27). Ос­
тальное по причине сходства с предыдущими двумя листингами должно быть
понятно без комментариев.
В листинге 7.17 приведен код, который демонстрирует один из возможных
способов работы с динамическим массивом.
Листинг 7.17. Работа с динамическим двумерным массивом

1: Option Base 1
2: Sub DemoDinArray2 ()
3:
Dim Int_Arrayl() As Integer
4:
Dim Int_Array() As Integer
5:
Dim str_msg As String
6:
Dim i As Integer, m As Integer, n As Integer
7:
Dim Num
8:
9:
str_msg = ""
10:
i = 0
11:
12:
Do
13:
i = i + 1
14:
Num = InputBox("Введите целое число для " _
15:
& i & "-го элемента массива", _
16:
"Ввод элементов массива")
17:
If Len(Num) = 0 Then Exit Do 'выход из цикла
18 :
19:
'изменение размера массива
20:
'с сохранением элементов
21:,
ReDim Preserve Int_Arrayl (i)
22 :
23:
'ввод данных в i-й элемент массива
24:
Int_Arrayl(i) = Num
25:
Loop
26:
27:
m = i - 1
'вторая размерность массива
28:
29:
'ввести первую размерность:
30:
n = InputBox("Введите количество строк массива ")
31:
ReDim Int_Array(n, m)
32:
33:
'запись в выходной массив уже введенной строки:
34:
For j = 1 То m
35:
Int_Array(l, j) = Int_Arrayl(j)

Массивы

313

36:
Next
37:
38:
39:
'теперь работаем с обычным двумерным массивом,
40:
'только первую строку не заполняем:
41:
For i = 2 То п
42:
For j = 1 То m
43:
Int_Array(i, j) = InputBox("Введите целое число для "
44:
& " элемента (" & i &
& j &
45:
"Ввод элементов массива; строка " & iT.
46:
Next j
47:
Next i
48:
49:
'подготовка строки выдачи
50:
For i = 1 То n
51:
For j = 1 To m
52:
str_msg = str_msg & Int_Array(i, j) & ", "
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 программа почти ничем не отличается от кода листинга 7.15,
начиная со строки 7. Отличие состоит только в том, что в последнем коде за­
полнение двумерного массива во вложенном цикле осуществляется со второй
строки и пределы цикла заданы не литерами, а переменными.
В качестве еще одного примера использования динамического массива рас­
смотрим программу, при помощи которой можно пронумеровать выделенное
количество строк. При этом эта нумерация будет отличаться от автонумерации
Word тем, что строки, пронумерованные таким образом, ничем не отличаются
от обычного текста и могут быть восприняты другими редакторами при пере­
даче в них данного текста.

314

Глава 7. Повторение действий в Visual Basic: циклы и массивы

Листинг 7.18. Нумерация строк

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:

НумерацияСтрок Macro
Macro recorded 28.04.01 by Владимир Кузьменко

Нумерует строки выделенного текста
Вызов: Ctrl+Alt+N
'количество выделенных строк:
ii = Selection.Paragraphs.Count()
'объявление массива для хранения строк:
Dim mas() As String

'цикл считывания строк и добавления нумерации:
For i = 1 То ii
ReDim Preserve mas(i)
tt = Selection.Paragraphs(i)
mas(i) = Str(i) & ":" & vbTab & tt
Next

'удаление выделенного
Selection.Cut

фрагмента:

'цикл печати массива:
For i = 1 То ii
Selection.TypeText Text:=mas(i)
Next

Если вам необходимо начинать нумерацию с некоторого числа и вместо
символа
использовать какой-либо другой, макрос можно переписать, на­
пример, так, как это сделано в следующем листинге.
Листинг 7.19. Работа с динамическим одномерным массивом

1. Sub НумерацияСтрок()
2. '
3. ' НумерацияСтрок Macro
4. ' Macro recorded 28.04.01 by Владимир Кузьменко
5. '
6. ' Нумерует строки выделенного текста
7. ' Вызов: Ctrl+Alt+N
8. '
9.
BeginNumber = CInt(InputBox("Введите начальный номер строки",
10.
"Ввод номера первой строки", 1))
11.
12.
NumberChar = InputBox("Введите символ разделения",
13.
"Ввод символа разделения", ":")
14.
15.
'количество выделенных строк:
16.
17.
ii = Selection.Paragraphs.Count()
18.
'объявление массива для хранения строк:
19.
Dim mas() As String
20.

Массивы

21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
3 6.

315

'цикл считывания строк и добавления нумерации:
For i = 1 То ii
ReDim Preserve mas(i)
tt = Selection.Paragraphs(i)
mas(i) = Str(i + BeginNumber - 1) & NumberChar & vbTab & tt
Next

'удаление выделенного фрагмента:
Selection.Cut

'цикл печати массива:
For i = 1 То ii
Selection.TypeText Text:=mas(i)
Next
End Sub

Как и в предыдущем макросе, в строке 26, кроме вводимого символа разде­
ления номера и кода, используется символ табуляции (его роль играет кон­
станта vbTab). Это необходимо для того, чтобы строки кода были выровнены
слева. Заметьте, что для нумерации последнего макроса в качестве символа
разделения использовался символ

Функции LBound и UBound
Для контроля за размерами как статических, так и динамических массивов
можно использовать одну или пару переменных для сохранения минимального
и максимального индекса массива, как это делается в ранее рассмотренных лис­
тингах. Если для отслеживания верхнего и нижнего пределов индексов массива
пользователь полагается на собственные переменные, то он полностью отвечает
за обновление и точность этих переменных. В противном случае процедуры не
будут работать правильно — будет обрабатываться меньше элементов, чем
в действительности содержит массив, или будет получено сообщение об ошибке
при попытке доступа к массиву с индексами, выходящими за фактический раз­
мер массива. Такие программные ошибки бывает трудно отслеживать.
VBA имеет пару функций, которые освобождают пользователя от необходи­
мости вручную отслеживать верхний и нижний пределы массива — функции
LBound и UBound. Эти функции возвращают нижнее и верхнее граничные зна­
чения индексов статического или динамического массива.
Функции LBound и UBound имеют следующий синтаксис:

Синтаксис
LBound(arrayName [, dimension])
UBound(arrayName [, dimension])
Функция LBound возвращает первый индекс массива, представленного с помощью

arrayName. Функция UBound возвращает наибольший индекс массива, представ­
ленного с помощью arrayName. Можно использовать эти две функции как со стати­
ческими, так и с динамическими массивами. Аргумент dimension представляет
целое число, определяющее измерение массива, для которого необходимо полу­
чить нижний или верхний предел. Если опустить dimension, VBA возвращает предел
для первого измерения массива.

316

Глава 7. Повторение действий в Visual- Basic: циклы и массивы

Следующие фрагменты кода являются примерами использования функций
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 позволяет полностью удалять
массив и его содержимое из оперативной памяти.
Когда элементы массива заполнены, данные в массиве остаются (независи­
мо от того, является данный массив статическим или динамическим) до тех
пор, пока пользователь не присвоит новые значения элементам массива или
пока VBA не освободится от массива. (Массивы следуют тем же правилам об­
ласти действия и персистенции, что и любая другая переменная в VBA.)
При некоторых обстоятельствах может понадобиться очистить все значения
в массиве, устанавливая числовые значения на 0, строковые значения на пус­
тые строки и так далее. Обычно следует использовать цикл For...Next или
For...Each для установки всех элементов в массиве на определенное значение.
Следующие фрагменты кода показывают оба цикла For...Next и For...Each, ис­
пользуемые для инициализации всех значений в числовом массиве на 0:
For k = LBound(NumArray) То UBound(NumArray)
NumArray(k) = 0
Next к
For Each Num In NumArray
Num = 0
Next Num

Первый фрагмент кода использует цикл For...Next и функции LBound
и UBound для прохождения в цикле по всем элементам массива; второй фраг­
мент кода использует For...Each для прохождения в цикле по каждому элемен­
ту массива, также устанавливая каждый элемент на 0. Хотя эти циклы до­

Массивы

317

вольно короткие, можно выполнить ту же самую задачу для статического мас­
сива даже более эффективно с помощью единственного оператора Erase:
Erase NumArray
Массивы «имеют тенденцию» занимать относительно большой объем опера­
тивной памяти — например, массив из 20 элементов занимает такой же объем
памяти, как 20 отдельных переменных одного и того же типа. Поскольку мас­
сивам требуется так много памяти, следует удалять динамические массивы из
оперативной памяти, когда они фактически не используются. (Статические
массивы не могут удаляться из оперативной памяти до тех пор, пока VBA ав­
томатически не освобождается от массива.)
VBA удаляет из памяти массивы, объявляемые локально в процедуре (так
же, как и любые другие локальные переменные), каждый раз, когда процеду­
ра прекращает выполняться. Однако массивы, объявляемые на модульном
уровне, существуют пока любая процедура в этом модуле выполняется. Если
программа большая, вам может понадобиться восстановить ресурс памяти, ис­
пользуемой динамическими массивами модульного уровня. Оператор Erase
позволяет делать именно это.
Оператор Erase имеет следующий синтаксис:

Синтаксис
Erase arrayl [, array2, ...]
Здесь arrayl v\ array2 представляют любое допустимое имя массива VBA. Можно пе­
речислить столько массивов в операторе Erase, сколько хотите, отделяя каждое имя
массива запятой.

Оператор Erase удаляет из памяти динамические массивы, освобождая
область памяти, ранее используемую этим массивом. При удалении динами­
ческого массива с помощью оператора Erase необходимо повторно создать
массив с помощью оператора ReDim перед тем, как можно будет использовать
этот определенный динамический массив снова. При попытке доступа к эле­
ментам в динамическом массиве, для которого был использован оператор
Erase, без его переопределения VBA отображает сообщение о runtime-ошиб­
ке.
Поведение оператора Erase для статических массивов немного сложнее
и зависит от конкретного типа элементов массива. В следующей таблице опи­
сывается действие оператора Erase со статическими массивами различных ти­
пов:
Тип статического массива

Действие оператора Erase

Любой числовой тип

Устанавливает элементы массива на 0.

: Любой строковый тип

Variant

Устанавливает элементы массива на строку нулевой
длины
устанавливает строки фиксированной
длины как все символы пробелов.

Устанавливает элементы массива на Empty.

318

Глава 7. Повторение действий в Visual Basic: циклы и массивы

Тип статического массива

Действие оператора Erase

Object

Устанавливает элементы массива на Nothing.

1 Любой пользовательский тип

Устанавливает каждую переменную
в пользовательском типе индивидуально: численные 1
типы устанавливаются на 0, строковые — на строки
нулевой длины, Variant — на Empty, Object — на
Nothing.

Использование массивов в качестве аргументов
процедур и функций
VBA дает возможность передавать массивы в качестве аргументов процедур
и функций. Эта возможность может быть очень полезной; поскольку нет необ­
ходимости задавать размер массива, который передается как аргумент, можно
писать универсальные процедуры или функции обработки массива. Напри­
мер, можно написать функцию, получающую числовой массив в качестве ар­
гумента и возвращающую среднее значение всех чисел в массиве как резуль­
тат функции. Еще один пример: можно написать процедуру, получающую
массив в качестве аргумента, передаваемого по ссылке, и сортирующую этот
массив. И в одном, и в другом примерах можно написать процедуру или функ­
цию для работы с массивом любого размера — пять элементов, 10 элементов,
100 элементов и так далее.
Общий синтаксис для аргументов-массивов для процедур или функций та­
кой же, как для любых аргументов процедур или функций:

Синтаксис
[ByVai | ByRef] arraynameAs type
Как в случае аргументов процедур и функций, о которых вы уже знаете, ключевое
слово ByVai указывает VBA передать аргумент-массив по значению, а ключевое сло­
во ByRef указывает VBA, что следует передавать аргумент-массив по ссылке. Если
ByVai и ByRef пропущены, VBA передает аргумент-массив по ссылке.
В этой синтаксической конструкции аггаупате() представляет аргумент-массив;
можно использовать любой допустимый идентификатор VBA в качестве имени аргу­
мента-массива. Необходимо всегда включать пустые круглые скобки после
arrayname; круглые скобки указывают VBA, что этот аргумент является массивом.
Параметр type представляет любой допустимый тип VBA или определенный пользо­
вателем тип.

Следующий фрагмент кода показывает, как включать массивы в качестве
аргументов для процедур и функций:
Sub ShowText(Lines(), NumLines As Integer)
'получает массив типа Variant, передаваемый по ссылке
End Sub
Sub SortList(ByRef List() As String, NumLines As Integer)
'получает массив типа String, передаваемый по ссылке
End Sub

Массивы

319

Если вы помните, передача аргументов по значению (с помощью ключевого
слова ByVai) приводит к тому, что VBA передает копию данных функции или
процедуре. Не передавайте массивы по значению, если в этом нет особой необ­
ходимости — передача больших массивов по значению может быстро исчер­
пать ресурсы памяти вашего компьютера, приводя к runtime-ошибкам из-за
нехватки памяти.
Если вы обратили внимание, в двух из трех последних примерах вместе
с именами массивов в качестве параметров передаются целые переменные
NumLines. Здесь подразумевается передача вместе с ссылкой на массив его
размерности. Однако замечательным свойством VBA является то, что он по­
зволяет посредством ранее рассмотренных нами функций LBound и UBound
внутри процедуры, которая принимает массив в качестве аргумента, опреде­
лить размерность переданного ей массива. Отметим, что далеко не все системы
программирования обладают такой возможностью. Ниже (листинг 7.20) при­
веден пример передачи массива в качестве параметра процедуре, единствен­
ный оператор которой выдает в диалоговом окне размерность переданного ей
массива.
Листинг 7.20. Определение размерности массива-аргумента

1:
2:
3:
4:
5:
6:
7:
8:
9:

Sub TestUBoundLBound(mas())
MsgBox "размерность массива " & "(" &
UBound(mas, 1) &
& UBound(mas, 2) & ")"
End Sub
Sub a ()
Dim arr(9,7)
Call TestUBoundLBound(arr)
End Sub

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

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

Microsoft Excel
размерность массива (9,7)
И """ ОК “

1

Управление файлами
с помощью VBA
Управление файлами — это одна из интереснейших задач для программи­
ста в любой системе программирования. Болеее того, программировать в сре­
де, состоящей из файлов, и не уметь работать с этими файлами (находить, ко­
пировать или удалять документ, рабочую книгу или другой файл, записывать
в файл или читать из него данные) — не очень полезное занятие. Visual Basic
for Applications предоставляет различные операторы, (функции и методы для
выполнения общих задач управления файлами.

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

Что такое управление файлами
Управление файлами (file management) — термин, используемый для опи­
сания действий, которые выполняются с файлами, сохраненными на диско­
вых драйверах. Управление файлами включает действия, такие как копирова­
ние файлов, удаление неиспользуемых файлов для освобождения области дис­
ковой памяти, перемещение файлов с одного диска (или папки) на другие
и создание или удаление каталогов диска. Управление файлами включает так­
же такие виды обработки, как просмотр списка файлов в папке для определе­
ния размера файла или даты и времени, когда этот файл был модифицирован
в последний раз.
VBA позволяет выполнять наиболее общие задачи управления файлами под
контролем процедуры или функции, которую вы можете написать сами.
Windows Desktop и справочная система используют термин папка (folder)
для обозначения того, что опытные пользователи Windows или DOS знают как
каталоги (directories). В этой книге используется термин папка для согласо­
ванности с терминологией Windows; в некоторых случаях также используется
термин каталог.

11

VBA. Эффективное использование

322

Глава 8. Управление файлами с помощью УВА

Возможности VBA по управлению файлами
В табл. 8.1 приведены VBA-функции, операторы и методы управления фай­
лами. В первом столбце таблицы находится ключевое слово VBA, во втором —
указывается, предназначено ли ключевое слово для функции, оператора или
объектного метода. Наконец, в третьем столбце содержится краткое описание
назначения каждой функции, оператора или метода.

Таблица 8.1. Функции, методы и операторы управления файлами
Имя

Категория

Назначение

ChDir

Оператор

Изменяет текущий каталог (папку).

ChDrive

Оператор

Изменяет текущий драйвер диска.

CurDir

Функция

Возвращает текущий каталог (папку).

Dir

Функция

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

FileCopy

Оператор

Копирует файл.

FileDateTime

Функция

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

FileLen

Функция

Возвращает длину файла в байтах.

GetAttr

Функция

Возвращает число, представляющее
объединенные атрибуты файла или каталога
диска, такие как System, Hidden и так далее.

GetOpenFileName

Метод

Отображает Excel-диалоговое окно Open
и возвращает имя файла, выбранное
пользователем. В Word не имеется.

GetSaveAsFileName

Метод

Отображает Excel-диалоговое окно (Save As)
и возвращает имя файла, выбранное
пользователем. В Word не имеется.

Kill

Оператор

Удаляет файлы с диска.

MkDir

Оператор

Создает каталог диска (папку).

Name

Оператор

Переименовывает или перемещает файл.

RmDir

Оператор

Удаляет каталог диска (папку).

[ SetAttr

Оператор

Устанавливает атрибуты файла.

Атрибуты файла

323

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

Атрибуты файла
Каждый файл, сохраненный на любом диске Windows (или более ранней
версии DOS), имеет атрибуты (attributes). Независимо от конкретного типа
драйвера диска (жесткий диск, гибкий диск, RAM-drive, ZIP-drive, Syquestdrive и так далее) Windows и DOS используют атрибуты файла для определе­
ния того, какие действия по управлению файлами допускаются для этого фай­
ла. Например, Windows (или любая другая операционная система) запрещает
вам (и любым программам приложений) удалять, модифицировать или пере­
именовывать файлы с атрибутом read-only.
Windows создает информацию об атрибутах файла, когда вы или программа
приложения, работающая на вашем компьютере, создает новый файл. В ка­
ком-то смысле, атрибуты файла подобны свойствам объекта: атрибуты файла
дают файлу некоторую характеристику в зависимости от конкретных атрибу­
тов, которые он имеет. Атрибуты файла являются частью информации файла,
которую Windows сохраняет на драйвере диска. Windows сохраняет информа­
цию об атрибутах файла вместе с информацией об имени файла, размере, дате
и времени.
Windows автоматически обновляет и сопровождает информацию об атрибу­
тах файла. Чаще всего пользователи ничего не знают об атрибутах файла,
и обычно нет причины, по которой им было бы необходимо знать, что такое ат­
рибуты. В некоторых же случаях бывает полезно понимать и использовать ат­
рибуты файла. В частности, необходимо понимать атрибуты файла и их значе­
ние для того, чтобы использовать все преимущества VBA-функции Dir.
Windows использует всего семь атрибутов файла для определения различ­
ных характеристик файла. Каждый отдельный атрибут может объединяться
с другими атрибутами, кроме атрибута Volume Label, например, файл может
иметь одновременно атрибуты Hidden, System, Directory, Archive и Re­
ad-Only. В следующем списке содержится имя каждого атрибута файла
и описывается его значение.

324

Глава 8. Управление файлами с помощью УВА

□ Archive. Атрибут Archive указывает, изменялся ли файл со времени, ко­
гда его резервировали последний раз с помощью backup-программы, та­
кой как BACKUP Windows, или backup-программы других поставщиков,
таких как Fastback!, Backlt, Norton Backup и других. Если файл имеет
атрибут Archive, это означает, что для этого файла необходимо резерви­
рование. Если файл не имеет атрибута Archive, то этот файл не изменял­
ся со времени, когда он был резервирован последний раз.
□ Directory. Если файл имеет атрибут Directory, это означает, что файл,
в действительности, является каталогом или подкаталогом (папкой —
в терминологии Windows). Каталог диска — это файл, который содержит
информацию о других файлах; когда вы создаете каталог, Windows соз­
дает специальный файл каталога и дает ему атрибут Directory. Атрибут
Directory сообщает Windows о том, что этот файл содержит информа­
цию о других файлах и препятствует переименованию, копированию или
удалению каталога.
□ Hidden. Если файл имеет атрибут Hidden, Windows «скрывает» файл, не
показывая его в большинстве случаев при отображении каталога, хотя
Windows имеет опцию просмотра, которая отображает имена скрытых
файлов.
□ Normal. Атрибут файла Normal является, на самом деле, признаком от­
сутствия каких-либо специальных атрибутов. Так называемый Nor­
mal-атрибут (иногда называемый general) файла просто означает, что
файл не имеет никаких других атрибутов, кроме, возможно, атрибута
Archive (для указания, необходимо ли резервирование для этого файла).
□ Read-Only. Атрибут Read-Only означает, что вы можете только читать из
файла, но не можете изменять его. Windows 95/98 препятствует измене­
нию, удалению или переименованию файла, который имеет атрибут
Read-Only.
□ System. Атрибут System указывает Windows, что файл является частью
операционной системы компьютера. Как в случае с файлами Read-Only,
Windows препятствует изменению файла, имеющего атрибут System.
Кроме того, если вы создаете диск автозапуска DOS-командой SYS (или
с Windows Conrol Panel), любые файлы, имеющие атрибут System, пере­
носятся на новый диск автозагрузки.
□ Volume Label. Атрибут Volume Label нформирует Windows о том, что
файл является меткой тома диска. [Метка тома (volume label) — это
имя, которое вы даете жесткому диску (или дискете) при форматирова­
нии, использовании DOS-команды LABEL или изменении свойства Label
в листе свойств диска.] Диск может иметь только одну метку тома одно­
временно.
Windows представляет каждый отдельный атрибут файла уникальным чис­
лом и сохраняет это число с информацией об имени и размере файла. Если
файл имеет несколько атрибутов, Windows складывает кодовые числа для ка­
ждого атрибута и сохраняет их сумму. В следующем разделе описывается, как
можно найти и интерпретировать кодовое число для атрибутов файла.
В табл. 8.2 перечисляются коды атрибутов файлов, которые использует
Windows, и внутренние константы VBA для этих кодов атрибутов. Как и в слу­
чае с другими числовыми кодами, для которых VBA определяет константу,

Атрибуты файла

325

следует использовать VBA-константу для кодового числа вместо самого кодо­
вого числа.

Таблица 8.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.

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

Синтаксис
GetAttr(pathname)
Аргумент pathname — любое строковое выражение VBA, представляющее допусти­
мое имя файла; pathname может включать буквенную метку диска и полный путь пап­
ки; если вы не включаете буквенную метку, GetAttr ищет указанный файл на текущем
драйвере диска; если вы не включаете путь папки, функция GetAttr выполняет поиск
в текущей папке.

В листинге 8.1 содержится пример, в котором используется функция
GetAttr и показывается, как интерпретировать результат функции.
Листинг 8.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

326

Глава 8. Управление файлами с помощью УВА

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 vbArchiye) 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\X!Start"
34:
ShowFA fName:=strPath
35:
36: End Sub

В листинге 8.1 содержатся две процедуры. Процедура ShowFA занимает
строки 1-24, а процедура ListFileAttr — строки 26-36. Процедура ListFi­
leAttr просто вызывает ShowFA несколько раз, передавая каждый раз другое
имя файла.
Процедура ShowFA имеет один обязательный аргумент с именем fName
и типом String. В строке 5 объявляется переменная fAttr типа Integer для
сохранения значения, возвращаемого функцией GetAttr. В строке 6 объявля­
ется переменная mStr типа String для сохранения сообщения, формируемого
этой процедурой.
При выполнении оператора в строке 8 VBA вызывает GetAttr, передавая
строку fName в качестве аргумента и сохраняя результат функции в перемен­
ной fAttr. Если строка в fName не содержит допустимого имени файла, VBA
отображает сообщение о runtime-ошибке (рис. 8.1).
Рис. 8.1

Сообщения VBA при ошибке
в аргументе функции GetAttr

Атрибуты файла

327

Строки 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 отображает атри­
буты файла для файла lO.Sys. Этот файл является частью операционной систе­
мы Windows и всегда находится в корневом каталоге диска автозагрузки. По­
скольку IO.SYS является частью операционной системы Windows, он имеет ат­
рибут файла System; он имеет также атрибут Read-Only для предотвращения
нечаянного удаления этого важного файла; кроме того, этот файл имеет атрибут
Hidden, чтобы он обычно не появлялся в папке рабочего стола Windows или
в списках каталога Проводника. При выполнении процедуры ListFileAttr по­
следовательно отображаются диалоговые окна, показанные на рис. 8.2.
Рис. 8.2

Такие окна последовательно
отображаются кодом
листинга 8.1

Microsoft Excel

C:\IO.SVS has these attributes:
Read-Only
Hidden
System
Archive

Microsoft Excel

C:|M5DOS.SY3 has these attributes:
Read-Only
Hidden
System
Archive

В процедуре ShowFA нет тестирования для атрибута файла Normal, пото­
му что атрибут файла Normal — это просто отсутствие любых других атрибу­
тов.
Объявляйте все переменные, которые используете для сохранения кодов ат­
рибутов файла, как переменные типа Integer, так кодовое число атрибута фай­
ла всегда находится в допустимом диапазоне типа Integer. Не следует также
забывать, что коды атрибутов всегда обрабатываются как одно число, содержа­
щее сумму всех отдельных кодовых чисел для атрибутов данного файла.

328

Глава 8. Управление файлами с помощью УВА

Изменение атрибутов файла
Атрибуты файлов можно устанавливать из кода VBA. Например, можно изме­
нить атрибуты файла шаблонного документа, чтобы включить атрибут ReadOnly для предотвращения нечаянного удаления этого шаблонного документа.
Для изменения атрибутов файла предназначен оператор SetAttr, который
выполняет ту же самую задачу, что и команда Файл | Свойства (доступная в лю­
бых окнах каталога Windows или с помощью щелчка правой кнопкой мыши
на значке файла), а также DOS-команда ATTRIB.
Оператор SetAttr имеет следующий синтаксис:

Синтаксис
SetAttr pathname, attributes
Здесь pathname — любое строковое выражение, содержащее допустимую специфи­
кацию файла Windows [имя файла и (необязательно) полный путь к каталогу, и бук­
венную метку диска]; attributes — это численное выражение. Численное выражение
для attributes должно быть числом между 1 и 255 и состоять из одного из кодовых чи­
сел атрибута файла или суммы кодовых чисел атрибутов.

В листинге 8.2 показан пример того, как можно использовать оператор
SetAttr.
Листинг 8.2. Использование оператора SetAttr для изменения атрибутов файла

1:
2:
3:
4:

Sub SetReadOnly(fName As String)
'устанавливает атрибут только на чтение
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, не влияя на другие атрибуты.

Как находить файлы

329

SetReadOnly имеет один обязательный аргумент типа String с именем
fName, который используется для передачи имени файла в процедуру. В стро­
ке 4 объявляется переменная fAttr; процедура использует эту переменную для
сохранения числа для атрибутов файла.
В строке 6 используется функция GetAttr для получения атрибутов файла,
определенного с помощью fName. В строках 9-11 содержится оператор If, вы­
полняющий оператор SetAttr, если только этой файл не имеет уже атрибут
Read-Only. В строке 10 содержится фактический вызов оператора SetAttr.
Заметьте, что старые атрибуты файла арифметически складываются с кон­
стантой vbReadOnly для задания новых атрибутов. Таким образом, ориги­
нальные атрибуты файла сохраняются.
Наконец, в строках 13-15 содержится оператор MsgBox, отображающий со­
общение пользователю о том, что атрибут Read-Only для файла установлен.
Процедура Test_SetReadOnly тестирует процедуру SetReadOnly. В стро­
ке 21 используется Excel-метод GetOpenFileName (который будет описан
в следующем разделе) для получения имени файла от пользователя. В стро­
ке 23 вызывается процедура SetReadOnly для задания атрибутов файла с це­
лью включения атрибута Read-Only. Наконец, в строке 24 вызывается проце­
дура ShowFA (приведенная в листинге 8.1) для отображения окна сообщения
с новыми атрибутами файла.
Для добавления нового атрибута файла к имеющемуся набору атрибутов ис­
пользуйте оператор Or. Применение оператора Or для объединения атрибутов
файла в побитовой операции исключает любые возможные проблемы, которые
могут возникнуть при использовании арифметического сложения для объеди­
нения новых атрибутов с уже имеющимися. Результатом выражения О Or 1
является 1; результатом выражения 1 Or 1 является также 1. Поэтому можно
объединять новый атрибут файла с имеющимся числом атрибута файла, ис­
пользуя выражение, подобное OldAttr Or vbArchive. Если атрибут Archive не
задан в OldAttr, он будет задан как результат операции Or. Если атрибут
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, —

330

Глава 8. Управление файлами с помощью УВА

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

Синтаксис
Dir(pathname[, attributes])
Здесь pathname представляет любое выражение типа String, имеющее результатом
допустимое имя файла. Имя файла может содержать буквенную метку драйвера
и полный путь папки. Имя папки может также включать символы универсального со­
поставления файлов. Необязательный аргумент attributes является числом, пред­
ставляющим атрибуты тех файлов, которые необходимо найти. При использовании
attributes функция Dir выполняет поиск файлов, имеющих эти атрибуты. Если опус­
тить аргумент attributes, функция Dir выполняет поиск обычных файлов, то есть лю­
бых файлов, кроме имеющих атрибуты Hidden, Volume Label, Directory или
System.

При вызове функции Dir с аргументом pathname она возвращает строку, содержа­
щую имя первого найденного ею файла, совпадающее с именем файла в аргументе
pathname. Если имя файла содержит символы универсального сопоставления (* или
?), то для того, чтобы найти все файлы в каталоге, совпадающие с этим именем фай­
ла, необходимо использовать функцию Dir в два этапа. Во-первых, вызывать Dir
с аргументом pathname для получения первого совпадающего файла, затем вызы­
вать Dir неоднократно без аргументов до тех пор, пока Dir не возвратит пустую стро­
ку. Как только Dir возвращает пустую строку, значит, больше не остается файлов,
совпадающих с этим именем файла. При вызове Dir без указания имени файла, VBA
выдает сообщение о runtime-ошибке.

В листинге 8.3 показан пример использования Dir для нахождения только
одного файла.
Листинг 8.3. Использование Dir для нахождения одного файла

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:

Function IsFile(fName As String) As Boolean
'возвращает Истина (True), если файл на диске найден,
'иначе - Ложь (False)
If (Dir(fName) О "") Then
IsFile = True
Else
IsFile = False
End If
End Function
Sub Test_IsFile()
Dim iName As String
Dim str_msg As String
iName = InputBox(prompt:="Введите имя файла:", _
Title^"Тестирование функции IsFile")
str_msg = "Файл " & iName &
результат поиска: "
If IsFile(iName) Then
str_msg = str_msg & " найден"

Как находить файлы

331

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. Если
результат функции Dir является пустой строкой, то никакого совпадающего
файла не было найдено и VBA выполняет строку 7, которая присваивает False
результату функции.
В строках 12-27 объявляется процедура для тестирования функции IsFile.
Учитывая номертекущей главы, не будем подробно останавливаться на разбо­
ре этого кода. Если в таком простом коде что-то неясно, следует прочитать
внимательнее предыдущие главы.
Функцию Dir можно также использовать для нахождения в папке всех
файлов, совпадающих с определенным именем файла. Эта возможность функ­
ции Dir наиболее полезна, когда имя файла содержит символы универсально­
го сопоставления. Можно использовать функцию Dir таким образом, если не­
обходимо, скажем, найти все файлы шаблонов в определенной папке.
В листинге 8.4 показан пример того, как функция Dir используется для на­
хождения нескольких файлов.
Листинг 8.4. Использование функции Dir для нахождения нескольких файлов

1: Sub ShowFA(fName As String, Number As Integer)
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

Глава 8. Управление файлами с помощью УВА

332

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:

If (fAttr And vbSystem) Then _
mStr = mStr & "System" & vbCr
If (fAttr And vbVolume) Then
mStr = mStr & "Volume" & vbCr
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
Dim
Dim
Dim

sAttr As
fName As
pName As
fCount As

Integer
String
String
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)
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, кото­
рая уже встречалась в листинге 8.1. Здесь были внесены небольшие измене­
ния: теперь процедура имеет еще один параметр Number типа Integer и ре­
зультирующая строка выдается не в окне оператора MsgBox (при длинном спи­
ске файлов это будет утомлять пользователя даже в процессе тестирования

Как находить файлы

333

кода), а записывается в 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 для обозначения текущего (.) и родительского катало­
га (..). Хотя такие особые имена файлов являются каталогами и функция Dir
будет сообщать об их существовании с таким атрибутом и спецификацией уни­
версального сопоставления, какие используются в данном примере, они, на са­
мом деле, не существуют на диске, и любая попытка получить их атрибуты
с помощью GetAttr приведет к возникновению runtime-ошибки.
Если fName не является пустой строкой и не содержит специальных эле­
ментов (. или ..), VBA выполняет оператор в строке 48, который устанавливает
счетчик найденных файлов в 1 (переменная fCount), и выполняет оператор
в строке 49, который вызывает процедуру ShowFA для записи в очередную
ячейку текущего листа открытой рабочей книги имени файла и его фактиче­
ских атрибутов.
Теперь, когда первый совпадающий файл найден, необходимо использовать
формат второй ступени функции Dir, чтобы найти остальные файлы в катало­
ге. В строках 52-60 содержится цикл Do, который выполняется, пока fName
не является пустой строкой. Если хотя бы один совпадающий файл был най­
ден в вызове функции Dir (в строке 45), то этот цикл будет выполняться, по
крайней мере, один раз.
Обратите особое внимание на- строку 53. Этот оператор снова вызывает
функцию Dir без аргументов. При таком вызове функции Dir VBA «полага­
ет», что пользователь хочет найти больше файлов, совпадающих со специфи­
кацией для аргументов пути и атрибутов, которые использовались в послед­

334

Глава 8. Управление файлами с помощью УВА

нем вызове Dir. Функция Dir возвращает следующий файл в каталоге, совпа­
дающий с предыдущими спецификациями имени и атрибутов. Если файлов
больше нет, Dir возвращает пустую строку.
Когда все совпадающие файлы в каталоге будут найдены, Dir возвращает
пустую строку и цикл прекращает выполняться. Оператор в строке 62 отобра­
жает окно сообщения, указывающее, сколько совпадающих файлов было най­
дено. На рис. 8.3 представлен результат работы кода этого листинга при вве­
денной в окне InputBox строке «H:\JURNALs\Delphi» (конечно, на каком-то
случайном компьютере).
Рис. 8.3

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

(Soft Ек Данные

ЖЬа
:


Visual Макросы
Bask

Реценгироеа Вид

-

Источник
Обновить данные

«

'

Обдать
документ»

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

Al

■ZZtZx'

X

Пакеты расширенна

ф!

Ёст»»»?,
Режим
*
конструктора

Разработчик^1

|

■NALS\DELPHI\DELPHI MAKET.₽MD has these а’

A
В
1 |H:\JURNAlS\DELPHi\DELPHI MAKET.PMD has these attributes: ERead-OnlyBArchiveB

2 H:\JURNALS\DELPHI\JOURNAL_FONTS.RAR has these attributes: BArchlveE
3 H:\iURNALS\DElPHi\REKlAMA.PMO has these attributes: BArchiveS
I 4 jH:\JURNALS\DEl₽HlVOURNAL_FONTS has these attribute;: BDIrectorys

‘ 5 H:\JURNAIS\DEIPHI\DELPHY-EMPTY,VP has these attributes: tSArchiyetS

6 H:\JURNALS\DELPHI\HAU]I4 200f
7 |H:\)URNAtS\DELPHI\HAUlM200;

SDirectoryS

8 H:\JURNALS\DELPHI\2OO6hasth

:oryS

9 -H:\JURNALS\DElPHI\2007 has th

ory®

10 H:\JURNALS\DELPHI\ADRESS.TX’

EArchive®

SDirectoryS

ГlljH:\JURNALS\DELPHI\DEU>HY06J

: ^Archive®

в!....
M:

15
1

».* I ...Ifrcri J
Готово

тестов,

а

ЛйсгЭ

%? J

о *

Использование встроенных диалоговых окон
Excel для получения имен файлов
Excel-объект Application имеет два метода — GetOpenFilename и GetSaveAsFilename, которые можно использовать в Excel-коде VBA для упроще­
ния задачи получения имени файла от пользователя. В следующих двух разде­
лах описывается, как использовать эти два метода в процедурах.

Использование метода GetOpenFilename
Во многих примерах в этой книге использовалась функция InputBox для
получения имен файлов от пользователя процедуры. Хотя получение имени
файла с помощью InputBox является обычной практикой, при этом не исполь­
зуются преимущества ориентированного на файл диалогового окна, такого как

Использование встроенных диалоговых окон Excel для получения имен файлов

335

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 (*.xlsx), *.xlsm"

Эта строка фильтра приводит к появлению двух опций (Templates
и Workbooks) в окне раскрывающегося списка Files of type.
В листинге 8.5 показан пример, использующий метод GetOpenFilename.

Глава 8. Управление файлами с помощью УВА

336

Листинг 8.5. Использование метода GetOpenFilename для получения имени

файла от пользователя процедуры

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:

Sub TestGetOpenFilename ()
'открывает указанную рабочую книгу и выбирает
'лист, указываемый пользователем в окне функции InputBox

Const iTitle = "Ввод имени рабочей книги"
Dim ShtName As String
Const FilterList =
"Templates (*.xlt),*.xlt,Workbooks (*.xlsx),*.xlsm"
Dim fName As String

fName = Application.GetOpenFilename(Title:=iTitle,
filefliter:=FilterList,
filterindex:=2)
If fName = "False" Then 'для русской версии "Ложь"
MsgBox prompt:="Операция отменена!",
Title:=iTitle
Exit Sub
End If
Workbooks.Open Filename:=fName

ShtName = InputBox("Введите наименование листа")
ActiveWorkbook.Sheets(ShtName).Select
MsgBox prompt:="Книга " & fName &
" открыта, лист " & ShtName &
" выбран ",
Title:=iTitle & " (Завершение)"
End Sub

Процедура TestGetOpenFilename открывает рабочую книгу, выбранную
пользователем в диалоговом окне с заголовком, определяемым константой
iTitle, а затем выбирает рабочий лист с именем, указываемым в окне функции
InputBox, в открытой рабочей книге.
В строках 8-9 объявляется константа FilterList, в дальнейшем передавае­
мая в качестве фильтра файла при обращении к методу GetOpenfilename.
В строках 14-16 содержится один оператор, вызывающий метод
GetOpenFilename и присваивающий его результат переменной fName. При
выполнении этого оператора VBA отображает диалоговое окно, показанное
на рис. 8.4. На этом рисунке показано открытое окно списка Тип файлов (Files
of type), чтобы можно было видеть действие аргумента fileFilter. Заметьте,
что диалоговое окно на рисунке идентично Excel-окну Орел (Открытие доку­
мента), за исключением заголовка окна и содержимого окна списка Тип фай­
лов (Files of type). Поскольку аргумент filterindex (строка 16) имеет значе­
ние 2, фильтром по умолчанию является фильтр Workbooks (*.xlsx), а не
Templates (*.xlt).

Использование встроенных диалоговых окон Excel для получения имен файлов

337

Рис. 8.4. Процедура TestGetOpenFilename использует метод GetOpenFilename
для отображения этого диалогового окна

Имя в диалоговом окне можно выбрать точно так же, как в Excel-окне Open.
Когда вы выбираете кнопку Open (Открыть), метод GetOpenFilename возвра­
щает строку, содержащую имя файла, буквенную метку диска и полный путь
каталога (аргумент multiSelect не был использован, поэтому можно выбрать
только одно имя файла). Если вы выберите Cancel (Отмена), GetOpenfilename
возвращает Boolean-значение False. Поскольку в данном случае fName явля­
ется переменной String, VBA автоматически преобразует False в строку
«False».
Если операторы в строках 19-23 не обнаружат факт отказа от ввода имени
файла, то в строке 25 вызывается метод Workbooks. Open, открывающий вы­
бранную пользователем рабочую книгу. В строке 27 с помощью функции
InputBox пользователь может ввести наименование листа уже открытой рабо­
чей книги. В это время ярлычки с 'именами листов будут видны пользователю
(рис. 8.5).
Завершается процедура, как обычно, оператором MsgBox с сообщением об
успешном выполнении задачи процедуры.
Не следует забывать, что GetOpenFilename возвращает строку, когда поль­
зователь выбирает имя файла, и Boolean-значение False — при отмене диа­
логового окна. Если вы присваиваете результат метода GetOpenFilename пе­
ременной типа Variant, необходимо выполнять тестирование для значения
False, а не строки «False».

338

Глава 8. Управление файлами с помощью УВА

Рис. 8.5

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

Главная

бставга

Рязистга стр

Оормуяы

ф

.

Данные ' Рецеюнрое» Вид

Разработчик

4^: Пакеты расширения

::
Ражим
конструктора я

ИСТОЧНИК /

длины*

Элементы *пйзс*сми!»

н

14.I1.200S,. (20) / 14.11.2605 1 14,11.

■ ГМ«М : J3 i

Метод GetOpenFilename возвращает массив строк, если используется зна­
чение True для необязательного аргумента multiSelect, даже если пользова­
тель выбирает только один файл.

Использование метода GetSaveAsFilename
Вы можете использовать Excel-метод GetSaveAsFilename для отображе­
ния диалогового окна, которое выглядит и работает так же, как окно, отобра­
жаемое Excel, когда пользователь выбирает команду File | Save As.... Метод
GetSaveAsFilename также возвращает строку, содержащую имя файла, кото­
рое выбирает пользователь, включая буквенную метку диска и полный путь
каталога. Если пользователь отменяет диалоговое окно, GetSaveAsFilename
возвращает Boolean-значение False.
Метод GetSaveAsFilename имеет следующий синтаксис:

Синтаксис
object. GetSaveAsFilename (ini tialFilename, fileFil.ter,
filterindex, title,buttonText)
Метод GetSaveAsFilename имеет почти такие же аргументы и синтаксис, как метод
GetOpenFilename. В этой синтаксической конструкции object — это ссылка на объект
Application, fileFilter — выражение String, форматированное для задания фильтров
файла, перечисленных в раскрывающемся списке Save as type; filterindex — числен­
ное выражение, указывающее, какой фильтр файла должен использовать VBA в каче­
стве фильтра по умолчанию, a title — выражение String для строки заголовка
диалогового окна. Если пропускается аргумент title, VBA отображает диалоговое окно
с обычным заголовком SaveAs.

Использование встроенных диалоговых окон Excel для получения имен файлов

339

Аргумент button Text— необязательный параметр типа Variant. Используется только
в Macintosh.
Метод GetSaveAsFilename имеет еще один аргумент — initialFilename, который
представляет любое допустимое имя файла. Если указать этот необязательный ар­
гумент, имя файла, которое задается для initialFilename, появляется в текстовом
окне File Name, когда диалоговое окно Save As отображается первый раз.

Строки фильтра файла для метода GetSaveAsFilename определяйте таким
же образом, каким форматируете их для GetOpenFilename.
В листинге 8.6 показан пример, использующий метод GetSaveAsFilename.
Листинг 8.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)
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 используется для сохранения выбираемого
пользователем имени файла.

340

Глава 8. Управление файлами с помощью УВА

В строках 10-16 устанавливается счетчик шаблонных файлов и формирует­
ся предлагаемое имя шаблонного файла. В строках 17-19 содержится один
оператор, который вызывает метод Ge tSaveAs Fil ename и присваивает его ре­
зультат переменной iName. При вызове этого метода VBA отображает диалого­
вое окно, показанное на рис. 8.6. Заметьте, что это окно точно такое же, как
Excel-окно Сохранение документа (Save As), за исключением заголовка диалого­
вого окна (поскольку он формируется процедурой и является аргументом ме­
тода GetSaveAsFilename) и содержимого списка Тип файла (Save as type).

Рис. 8.6. Процедура ConvTemplate использует метод GetSaveAsFilename для
отображения этого диалогового окна

В строке 21 с помощью оператора If...Then...Else проверяется, не отменил
ли пользователь диалоговое окно метода GetSaveAsFilename. Если пользова­
тель выбрал кнопку Cancel (Отмена) [или нажал Esc], то выполняется оператор
в строках 22-23, отображая окно сообщения, информирующее пользователя
о том, что преобразование в шаблон было отменено. Иначе оператор в строках
25-26 вызывает метод SaveAs, сохраняя активную рабочую книгу как
Excel-шаблонный файл.
Необходимо помнить, что и GetOpenFilename, и GetSaveAsFilename мо­
гут изменять текущий диск и папку. Можно использовать функцию CurDir
для получения текущего диска и папки и сохранять результат в переменной,
чтобы можно было переключаться снова на текущий диск и папку с помощью
ChDrive и ChDir (описываются далее в этой главе).

Использование встроенных диалоговых окон Word для получения имен файлов

341

Использование встроенных диалоговых окон
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-диалоговое окно Открытие документа,
а константа 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) диалоговых окон

342

Глава 8. Управление файлами с помощью УВА

Открытие документа и Сохранение документа, присваивая значение свойству Name
перед отображением этих диалоговых окон. Свойство Format указывает, ка­
кой тип документа открывается или сохраняется: документ или шаблон. Свой­
ство Format может содержать значение одной из двух Word-констант типа
файла: wdTypeDocument и wdTypeTemplate.
В целях сбора информации от пользователя для процедур VBA используйте
метод Display объекта Dialog. Метод Display возвращает значение, указы­
вающее, закрыл ли пользователь диалоговое окно щелчком кнопки Открыть
или кнопки Отмена. В табл. 8.3 приведены возвращаемые значения метода
Display и поясняется их смыл.

Таблица 8.3. Возвращаемые значения метода Display
Числовое Что означает
значение

-2

Диалоговое окно было закрыто с помощью кнопки Отмена.

-1

Диалоговое окно было закрыто щелчком кнопки Открыть в диалоговых
окнах wdDialogFileOpen и wdDialogFileSaveAs.

0

Диалоговое окно было отменено.

>0

Командная кнопка; 1 — для первой командной кнопки, 2 — для второй
и так далее.

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

Использование Word-диалогового окна Open
В листинге 8.7 показана процедура, использующая Word-встроенное диало­
говое окно Open (Открытие документа) для получения имени файла документа
от пользователя. Процедура открывает документ и помещает курсор в конец
документа.
Листинг 8.7. Использование Word-встроенного диалогового окна
wdDialogFileOpen для получения имени файла

1: Sub OpenWordFile()
2:
'открывает указанный документ и перемещает
3:
'указатель вставки в конец документа
4:
5:
Const iTitle = "Открытие файла"
6:
7:
Dim fName As String
8:
Dim IRetVal As Long
9:
10:
With Application.Dialogs(wdDialogFileOpen)
11:
IRetVal = .Display
12:
fName = .Name
13:
End With
14:

Использование встроенных диалоговых окон Word для получения имен файлов

343

15:
If IRetVal -1 Then
16:
MsgBox prompt:="Операция отменена",
17:
Title:=iTitle
18:
Exit Sub
19:
End If
20:
21:
Documents.Open FileName:=fName
22:
Selection.EndKey unit:=wdStory
23:
24:
MsgBox prompt:="Документ
& fName &
25:
открыт",
26:
Title:=iTitle & " завершено"
27: End Sub

Процедура OpenWordFile использует только одну константу — iTitle —
в качестве заголовков диалоговых окон, отображаемых этой процедурой (заго­
ловок диалогового окна Open изменить невозможно). В строках 7 и 8 объявля­
ются переменные, используемые процедурой: fName используется для сохра­
нения имени файла, введенного пользователем, a IRetVal — для сохранения
результата метода Display, чтобы процедура могла определить, отменил ли
пользователь диалоговое окно Word, не делая выбора.
В строке 10 производится ссылка на диалоговое окно Open (Открытие доку­
мента), а строке 11 используется метод Display объекта Dialog для вывода на
экран этого окна. В результате отображается диалоговое окно, показанное на
рис. 8.7. Это окно идентично во всех отношениях окну, отображаемому Word,
когда выбирается команда Файл | Открыть (File | Open).

Рис. 8.7. Word-диалоговое окно Open (Открытие документа), отображаемое

оператором в строке 11 листинга 8.7

344

Глава 8. Управление файлами с помощью УВА

Выполнение процедуры OpenWordFile приостанавливается на то время,
пока открыто диалоговое окно; после закрытия окна Открытие документа (поль­
зователем) значение, возвращаемое методом Display, сохраняется в IRetVal
и выполнение кода возобновляется со строки 12. В этот момент свойство Name
диалогового окна содержит имя файла, выбранное пользователем (или строку
нулевой длины, если пользователь не выбрал имя файла). В строке 12 значе­
ние свойства Name диалогового окна сохраняется в fName.
В строках 15-19 оператор If оценивает возвращаемый методом Display
результат, который был сохранен в переменной IRetVal. Значение -1 указы­
вает, что диалоговое окно было закрыто щелчком на кнопке Открыть (или экви­
валентным действием, таким как двойной щелчок на имени файла). Если окно
не было закрыто щелчком на кнопке Открыть или ее эквиваленте, то отобража­
ется сообщение о том, что операция была отменена, иначе — выполнение кода
продолжается со строки 21.
В строке 21 выбранный файл открывается, а в строке 22 курсор помещается
в конец документа. Наконец, в строках 24-26 отображается сообщение об ус­
пешном завершении операции.

Использование Word-диалогового окна
Сохранение документа
В листинге 8.8 показана процедура, использующая Word-встроенное диало­
говое окно Сохранение документа (Save As) для получения имени файла докумен­
та от пользователя, предлагающее формат шаблона документа для файла, ко­
торый должен быть сохранен. Затем процедура сохраняет документ как
.dot-шаблон.
Листинг 8.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

Использование встроенных диалоговых окон Word для получения имен файлов

345

24 :
25:
If IRetVal -1 Then
26:
MsgBox prompt: ^'Преобразование отменено",
27:
Title:=iTitle
28:
Else
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 отображает диалоговое окно,
показанное на рис. 8.8. Заметьте, что это окно точно такое же, как Word-диалоговое окно Сохранение документа. Как только пользователь делает выбор
в окне Сохранение документа, возвращаемое значение метода Display сохраня­
ется в IRetVal и выполнение кода продолжается со строки 22, где выбранное
пользователем имя файла (из свойства Name диалогового окна) помещается
в переменную iName.
Рис. 8.8

Word-диалогов
ое окно,
отображаемое
оператором
в строке 21
листинга 8.8

346

Глава 8. Управление файлами с помощью УВА

В строках 29-30 документ сохраняется с использованием имени файла
(в iName) и формата файла (wdTypeTemplate).

Работа с дисками и папками
В этом разделе рассматривается, как использовать функции и операторы
VBA для нахождения текущего диска и папки, как изменять текущий диск
или папку и как создавать или удалять подпапки. Помните, текущий диск
(current drive) — это диск, который использует Word или Excel, когда не ука­
зывается определенная буквенная метка диска. Аналогично, текущая папка
(current folder) — это папка диска, которую Excel (или Word) использует, если
не указывается определенная папка.

Получение пути текущей папки и буквенной метки диска
Выборка текущего диска и пути папки довольно проста. Обе части инфор­
мации можно получить, используя функцию CurDir. Функция CurDir воз­
вращает строку, которая содержит полный путь текущей папки, включая бук­
венную метку диска. (CurDir является аббревиатурой слов current directory,
помните, что папка и каталог — это одно и то же.)
Функция CurDir имеет следующий синтаксис:

Синтаксис
CurDir[(drive) ]
Здесь drive представляет любое выражение типа String и указывает функции CurDir,
текущая папка какого диска необходима пользователю. Если аргумент drive опущен,
CurDir возвращает текущую папку текущего диска. Обычно drive содержит только
одну букву; если пользователь передает строку с несколькими символами, CurDir
использует первый символ строки как буквенную метку диска.

В листинге 8.9 показан пример использования функции CurDir.
Листинг 8.9. Использование функции CurDir для получения текущего

каталога и диска

1: Sub ShowCurDriveDir ()
2:
'отображает текущий драйвер и каталог
3:
4:
Dim DirName As String
'для имени каталога
5:
Dim DirLetter As String 'для буквы диска
6:
7:
DirName = CurDir()
'получить текущую папку диска
8:
9:
'взять первый символ из DirName - буква диска:
10:
DirLetter = Left(DirName, 1)
11:
12:
'вывод на экран:
13:
MsgBox "Текущий драйвер: " & DirLetter & _
14:
Chr(13) & "Текущий каталог: " & DirName
15:

Работа с дисками и папками

347

16:
'получить текущий каталог на драйвере С:
17:
DirName = CurDir ("С")
'
18:
MsgBox "Текущий каталог на драйвере С: " &
19:
DirName
20: End Sub

Наличие большого количества комментариев и простота синтаксиса функ­
ции CurDir, видимо, не требуют анализа данного листинга. В дополнение
можно предложить один из возможных результатов работы процедуры (на
рис. 8.9).
Рис. 8.9

Такие окна могут получиться в результате
работы кода из листинга 8.9

Изменение текущей папки
Если вам необходимо, чтобы процедура VBA изменила текущую папку на
какую-либо другую, используйте оператор ChDir. Если у вас есть опыт работы
с DOS, вы поймете, что ChDir в VBA выполняет ту же задачу, что DOS-коман­
ды CHDIR и CD. (ChDir — это аббревиатура слов change directory).
Оператор ChDir имеет следующий синтаксис:

Синтаксис
ChDir path
Аргумент path представляет любое выражение типа String, имеющее результатом
допустимый путь папки; path может (необязательно) содержать буквенную метку
диска. Если пользователь включает буквенную метку в аргумент path, ChDir изменя­
ет текущую папку диска на указанную в path без изменения текущего диска.

В листинге 8.10 показан пример использования оператора ChDir.
Листинг 8.10. Использование ChDir

1:
2:
3:
4:
5;
6:
7:
8:

Sub Test_ChDir()
'демонстрирует оператор ChDir

Dim oldDir As String

'для текущего каталога

MsgBox "Текущий каталог: " & CurDir ()

'сохранить текущий (старый) каталог:

348

Глава 8. Управление файлами с помощью УВА

9:
oldDir = CurDir ()
10:
11:
'изменить каталог:
12:
ChDir "\Мои документы"
13:
14:
'вывести на экран новый каталог:
15:
MsgBox "Новый каталог: " & CurDir()
16:
17:
'вернуться к старому каталогу
18:
ChDir oldDir
19:
MsgBox "Текущий каталог: " & CurDir()'
20:
21: End Sub

Эта процедура, по всей видимости, также не нуждается в комментариях.

Изменение текущего диска

Для изменения текущего диска необходимо использовать
ChDrive. (ChDrive — это аббревиатура слов change drive.)
Оператор ChDrive имеет следующий синтаксис:

оператор

Синтаксис
ChDrive drive
Аргумент drive — это любое выражение типа String, представляющее буквенную
метку диска. Если drive содержит более одного символа, ChDrive использует только
первый символ в строке для буквенной метки. Если для аргумента drive задается
пустая строка, то текущий диск не изменяется. Если задается символ, не являющий­
ся одной из букв от А до Z, VBA отображает runtime-ошибку. VBA отображает также
runtime-ошибку, если задается буквенная метка для диска, которого фактически нет
в данной компьютерной системе, хотя вы можете использовать буквенные метки
дисков, соединенных с вашим компьютером через сеть.

В листинге 8.11 демонстрируется использование оператора ChDrive.
Листинг 8.11. Использование ChDrive для изменения текущего диска

1:
Sub Test_ChDrive()
2:
Dim oldDir As String
3:
4:
'запомнить текущий (старый) каталог:
5:
oldDir = CurDir()
6:
7:
'выдать на экран текущий каталог:
8:
MsgBox "Текущий каталог: " & oldDir
9:
10:
'изменить драйвер на А:
11 :
ChDrive "D"
12 :
13:
'выдать на экран новый драйвер и каталог:
14 :
MsgBox "Новый драйвер и каталог: " & CurDir
15:
16:
'восстановить старый драйвер (используется

Работа с дисками и папками

349

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 не изменяет текущего диска или
папки.

В листинге 8.12 показан пример использования оператора MkDir, не тре­
бующий никакого анализа.
Листинг 8.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 "Текущий каталог драйвера А: " & _

350

17:
18: End Sub

Глава 8. Управление файлами с помощью УВА

CurDir("A")

Перед запуском этой процедуры убедитесь, что в дисководе А: имеется
диск, иначе VBA отобразит сообщение о runtime-ошибке.

Удаление дисковых папок

Вам может понадобиться также, чтобы одна из процедур удаляла дисковую
папку. Для удаления дисковой папки используйте оператор RmDir. Оператор
RmDir выполняет ту же задачу, что и DOS-команды RMDIR или RD; в Win­
dows используется команда File | Delete (Файл | Удалить) для удаления как фай­
лов, так и папок. (RmDir — это аббревиатура слов remove directory.)
Оператор RmDir имеет следующий синтаксис:

Синтаксис
RmDir path
Аргумент path представляет любое выражение String, имеющее результатом допус­
тимый путь папки; path может (необязательно) содержать буквенную метку диска.
Если буквенная метка не включена в аргумент path, RmDir удаляет папку на текущем
диске. Если path определяет папку, которая еще не существует, или включает недо­
пустимые символы имени файла, то VBA отображает сообщение о runtime-ошибке.

В листинге 8.13 показан простой пример использования оператора RmDir.
Листинг 8.13. Использование RmDir для удаления папки

1: Sub Test_RmDir()
2:
'демонстрирует оператор RmDir
3:
4:
Dim delDir As String
5:
6:
'имя удаляемой папки:
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

Предполагается, что была выполнена процедура в листинге 8.12 для созда­
ния папки Testi для диска А:. Если текущая папка диска А: является той же
папкой, которая должна быть удалена, то в строке 11 вызывается функция
ChDir для изменения текущей папки диска А: на корневую папку. Нельзя
удалять дисковую папку, если она является текущей или непустой.

Копирование и удаление файлов

351

Копирование и удаление файлов
Копирование и удаление файлов — это, вероятно, две наиболее часто вы­
полняемые операции по управлению файлами. В этом разделе описывается,
как можно копировать или удалять файлы под контролем процедур VBA.

Копирование файлов
Для копирования файла используйте оператор FileCopy. Этот оператор
VBA эквивалентен DOS-команде COPY или команде File | Сору (Файл | Копиро­
вать) в Windows.
Оператор FileCopy имеет следующий синтаксис:

Синтаксис
FileCopy source, destination
Как source, так и destination являются выражениями типа String, имеющие результа­
том допустимые имена файла. Они могут (необязательно) включать полный путь
папки и буквенную метку диска. При попытке копировать файл в самого себя VBA вы­
дает runtime-ошибку. VBA также выдает runtime-ошибку при попытке копировать
файл, когда нет достаточного дискового пространства для сохранения копируемого
файла.

В листинге 8.14 используется оператор FileCopy. Процедуру следует тес­
тировать в Excel, так как она использует методы GetOpenFilename и GetSaveAsFilename.
Листинг 8.14. Процедура, использующая оператор FileCopy

1: Sub Test_CopyFiles()
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:

352

Глава 8. Управление файлами с помощью УВА

24:
Loop
25:
26: End Sub

Эта процедура дает возможность пользователю выбирать файл-источник,
диск, папку и имя файла-приемника, в который будет осуществляться копиро­
вание (иногда такой файл называют целевым). В строках 5 и 6 объявляются
две переменные типа String для имен исходного и целевого файлов. В строке
8 начинается бесконечный цикл Do (цикл без детерминантного условия). Цикл
в строках 8—24 выполняется до тех пор, пока пользователь не отменит одно из
двух файловых диалоговых окон. В строке 9 начинается оператор With.
В строках 10-11 содержится один оператор, вызывающий метод GetOpenFilename для отображения диалогового окна открытия файла и присваиваю­
щий имя файла (результат метода) переменной sName.
В строке 13 оператор проверяет, отменил ли пользователь диалоговое
окно открытия файла. Если — да, процедура заканчивается. Иначе VBA вы­
полняет оператор в строках 15 и 16, который использует метод GetSaveAsFilename, чтобы дать возможность пользователю выбрать имя файла,
диск и папку для копируемого файла. В строке 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.

В листинге 8.15 показан пример оператора Kill.

Переименование или перемещение файлов

353

Листинг 8.15. Использование Kill для удаления файлов

1: Sub Test_KillFiles()
2:
'удаляет файлы, пока пользователь не отменит диалог
3:
4:
Dim fName As String
5:
Dim Ans As Integer
6:
7:
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. В строке 12 проверяется, отменил ли пользователь файловое диалого­
вое окно, и процедура завершается, если пользователь его отменил. В строках
14-16 содержится оператор MsgBox, запрашивающий пользователя подтвер­
дить удаление выбранного файла. Если пользователь подтверждает удаление,
VBA выполняет оператор Kill (в строке 19), который удаляет файл.
Не следует пытаться удалить файл открытой рабочей книги или документа,
в таком случае VBA выдает runtime-ошибку. Проверяйте атрибуты файла пе­
ред попыткой удалить его. При попытке удалить файл, имеющий какой-либо
из атрибутов Hidden, System или Read-Only VBA выдает runtime-ошибку.
Используйте функцию GetAttr для выборки атрибутов файла и оператор
SetAttr — для их изменения при необходимости удалять файлы с атрибутами
Hidden, System или Read-Only.

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

12 VBA. Эффективное использование

354

Глава 8. Управление файлами с помощью УВА

Оператор Name имеет следующий синтаксис:

Синтаксис

I

Name oldpathname As newpathame
Аргументы oldpathname и newpathname — это выражения типа String, имеющие
результатом допустимые имена файлов. Оба могут (необязательно) содержать пол­
ный путь папки, включая буквенную метку диска. Если пользователь включает бук­
венную метку, оба выражения oldpathname и newpathname должны включать одну
и ту же буквенную метку диска, иначе VBA выдает runtime-ошибку. Если oldpathname
и newpathname ссылаются на разные папки, VBA перемещает файл в новую папку
и изменяет его имя.

В листинге 8.16 показана процедура, использующая оператор Name для пе­
реименования файлов.

Листинг 8.16. Использование Name для переименования или перемещения
файлов
1: Sub Test_RenameOrMoveFile()
2:
1 переименовывает или перемещает файл
3:
4:
Const iTitle = "Переименовать или удалить - "
5:
Dim oldName As String
6:
Dim newName As String
7:
Dim oldDir As String
8:
9:
oldDir = CurDir()
10:
With Application
oldName = .GetOpenFilename(Title:-iTitle & "Источник")
11:
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
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 для объекта

Получение информации о файлах

355

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 и GetSaveAsFilename могут изменить текущий диск и пап­
ку.)

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

Получение времени и даты создания/модификации файла
Всякий раз, когда одна из программ приложения, такая как Word или
Excel, изменяет дисковый файл, файловая система Windows записывает дату
и время (в соответствии с часами данной компьютерной системы) с файлом,
чтобы можно было определить, когда этот файл был модифицирован послед­
ний раз. Чтобы сделать эту информацию доступной в процедурах VBA, ис­
пользуйте функцию FileDateTime. Эта функция возвращает информацию
о дате и времени из файла как VBA-значение типа Date.

356

Глава 8. Управление файлами с помощью УВА

Функция FileDateTime имеет следующий синтаксис:

Синтаксис
FiledateTime(pathname)
Аргумент pathname — это любое выражение типа String, имеющее результатом до­
пустимую спецификацию файла; pathname может необязательно включать буквен­
ную метку диска и полный путь папки, но не может содержать символы
универсального сопоставления (* или ?).

В листинге 8.17 в следующем разделе показан пример, использующий
функцию FileDateTime.

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

Синтаксис
FileLen(pathname)
Аргумент pathname — это выражение типа String, имеющее результатом допусти­
мую спецификацию имени файла; pathname может (необязательно) включать бук­
венную метку диска и полный путь папки, но не может включать символы
универсального сопоставления. Если pathname определяет открытый файл, FileLen
возвращает размер файла, каким он был, когда файл был сохранен надиске послед­
ний раз.

В листинге 8.17 показан пример, использующий функцию FileLen, а на
рис. 8.10 — один из возможных результатов работы кода этого листинга.
Листинг 8.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 Title:="Дата и размер файла",
17:
prompt:=sName & Chr(13) &

357

Получение информации о файлах

18:
msgl & Chr(13) & msg2
19: End Sub
20 :
21: Sub Test_ShowFDS()
22:
Dim sName As String
23:
24 :
Do
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

Рис. 8.10

Процедура ShowFDS использует функции
FileLen и FileDateTime для сбора информации
о размере файла и о том, когда он был
модифицирован последний раз

Дата и размер файла
I:yipoeKTbiUo^st2_exeU07_lZ_17_37.mcib
Размер: б 389 ТбОбайт.
Последняя модификация: 8 Декабрь 2006 г. в 18:59:22

Процедура ShowFDS использует функции FileLen и FileDateTime для
отображения окна сообщения, показывающего текущий размер файла и дату
и время, когда этот файл модифицировался последний раз. ShowFDS имеет
единственный аргумент fName типа String, используемый для указания про­
цедуре ShowFDS, информация о каком файле должна быть отображена.
В строках 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.

9

Элементы диалоговых
окон

До сих пор вы учились использовать диалоговые окна, которые встроены
в VBA, а именно, функции MsgBox и InputBox. Хотя MsgBox и InputBox при­
дают вашим программам гибкость, которой могут обладать только интерак­
тивные программы, их возможности в известной степени ограничены. При
разработке более сложных программ вы захотите выводить диалоговые окна,
которые дают возможность пользователям ваших программ задавать при по­
мощи одного диалогового окна сразу несколько опций, выбирать пункты из
списка или вводить в одном окне несколько значений подобно тому, как это
можно делать с помощью диалоговых окон, выводимых Word, Excel и други­
ми приложениями Windows. Часто у вас будет возникать необходимость вме­
сто встроенных окон, принадлежащих Word или Excel, использовать диалого­
вые окна, созданные специально для вашей программы.
VBA позволяет создавать и применять пользовательские1 диалоговые окна
в написанных вами программах и процедурах при помощи добавления в про­
ект объекта UserForm. Используя VBA-формы пользователя (VBA User
Forms), вы можете создавать диалоговые окна для вывода данных или получе­
ния значений от пользователя вашей программы именно в том виде, который
требуется вашей программе. Например, вы можете вывести на экран диалого­
вое окно со списком различных вариантов формата даты и предоставить поль­
зователю возможность выбрать из списка один из форматов.
Диалоговые окна позволяют вашей программе общаться с пользователем
наиболее удобным образом, обеспечивая гибкую форму ввода и вывода дан­
ных. Из этой главы вы узнаете об основных элементах диалоговых окон и их
свойствах, научитесь создавать простые диалоговые окна.

Формы пользователя
Диалоговое окно в VBA создается добавлением в проект объекта UserForm. Объ­
ект UserForm — это пустое диалоговое окно. Настройку диалогового окна можно
выполнить добавлением к объекту UserForm (обычно называют просто форма) эле­
ментов управления. Каждому объекту UserForm присущи определенные свойства,
методы и события, которые он наследует от класса объектов UserForm. Каждый
объект UserForm включает в себя также модуль класса, в который вы можете до­
бавлять собственные методы и свойства или код обработки событий формы.

1 В переводной литературе встречается термин «настраиваемые» (от англ, custom).

360

Глава 9. Элементы диалоговых окон

Первый шаг в создании пользовательского диалогового окна состоит в добав­
лении к проекту новой формы (объекта UserForm). Форма содержит рабочую об­
ласть, в которую вы можете поместить элементы, необходимые для выполнения
некоторого диалога пользователя с приложением. Поскольку объекты UserForm
хранятся в коллекции UserForms проекта, они являются частью проекта.
Для добавления к проекту новой формы используйте команду VB-редактора
Insert | UserForm (Вставка | UserForm). Редактор VB добавляет к текущему проек­
ту новую форму, присваивая ей по умолчанию имя UserFormN и используя ту
же систему нумерации, что и для модулей. Редактор VB выводит новую форму
в режиме разработки, как показано на рис. 9.1. [В режиме разработки вы мо­
жете добавлять (или удалять) элементы управления к форме, устанавливать
свойства формы или ее элементов управления и выполнять другие манипуля­
ции с внешним видом формы в интерактивном режиме. Когда форма выведена
и используется как часть выполняющейся программы, она находится в режи­
ме выполнения.}
На рис. 9.1 показана добавленная в проект форма UserForml. Заметим, что
широкая рамка вокруг формы указывает на то, что форма выделена. Обратите
внимание на сетку из точек на поверхности формы и Панель элементов
(Toolbox). Сетка из точек помогает выравнивать и контролировать размеры
элементов управления, помещаемых на форму, и появляется только в режиме
разработки. Панель элементов является «палитрой», с помощью которой вы мо­
жете выбирать элементы управления и добавлять их к форме. Панель, как
правило, появляется только в том случае, если выбрана форма или один из ее
элементов управления.
Рис. 9.1

Новая UserForm
в режиме разработки

Вы можете переименовать объект UserForm так же, как стандартный мо­
дуль или модуль класса. Для этого отредактируйте в Properties Window (окно
свойств) свойство Name этого объекта.

Формы пользователя

361

Не оставляйте вновь созданной форме имя, присвоенное ей по умолчанию,
например UserForml или UserForm2. Напротив, переименовывайте новую
форму сразу, как только ее создали.
Когда форма выводится на экран в режиме разработки, вы можете протес­
тировать ее поведение, используя команду Run | Run Sub/UserForm (Запуск | За­
пуск подпрограммы/UserForm). После этого редактор VB выведет форму в ре­
жиме выполнения и все ее элементы управления будут активными. Однако
следует помнить, что любой код, используемый формой, хранящийся не в мо­
дуле класса формы, не может быть инициализирован. При запуске формы
инициализируется только код, находящийся в модуле класса формы. Пере­
менные в стандартных модулях необязательно будут инициализироваться.
В результате этого, если форма не является полностью независимой, некото­
рые из программ связанных с ней, могут не выполняться, выдавая сообщения
о различных runtime-ошибках.

Свойства объекта UserForm
Форма как объект имеет некоторые встроенные свойства, и вы можете уста­
навливать эти свойства или программным образом, или в Properties Window
(окне свойств) редактора VB. Строго говоря, данные способы изменения
свойств форм не являются эквивалентными. Некоторые из свойств могут быть
установлены только посредством Properties Window. Программным способом
свойства форм устанавливаются таким же образом, как и свойства других объ­
ектов: путем присвоения свойству нового значения. В таблице 9.1 перечисле­
ны свойства UserForm, на которые вам, скорее всего, придется ссылаться или
изменять их.

Таблица 9.1. Наиболее часто используемые свойства
объектов UserForm
Свойство

Описание

ActiveControl

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

BackColor

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

Caption

Текст, выводимый в качестве заголовка формы. Запись/Чтение.

Controls

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

Cycle

Определяет, должно ли нажатие клавиши табуляции вызывать
последовательный выбор всех элементов управления во всех
группах и на каждой странице многостраничных элементов
управления или только в пределах текущей группы или страницы.
Может содержать одну из двух встроенных констант: fmCycleAIIForms |
или fmCycleCurrentForm. Чтение/Запись.

362

Глава 9. Элементы диалоговых окон

Свойство

Описание

Enabled

Содержит значение типа Boolean, указывающее, доступна ли
форма. Если его значение равно False, ни один из элементов
управления формы не доступен. Чтение/Запись.

Font

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

ForeColor

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

Методы объекта UserForm
Всякий раз создавая в проекте новый объект UserForm, вы создаете новый
подкласс объекта UserForm. Любые процедуры или функции, написанные
вами в разделе General (общий) модуля класса, относящегося к форме, стано­
вятся дополнительными методами для отдельного подкласса объекта. Вы
также можете создать для формы новые свойства, добавив в ее модуль класса
процедуры Property Get и Property Let. Вы можете создавать экземпляры
подкласса вашей UserForm с помощью оператора Dim и ключевого слова New.
Однако чаще всего вы будете манипулировать объектом формы при помощи
стандартных методов и свойств класса UserForm и при помощи собственных
процедур обработки событий для определенной вами формы и ее элементов
управления.
В табл. 9.2 перечислены наиболее часто используемые методы для объектов
UserForm, которыми вы можете воспользоваться, и кратко изложены их свой­
ства. Эти методы будут доступны для каждой формы, которую вы добавляете
в свой проект.

Таблица 9.2. Наиболее часто используемые методы
для объектов UserForm
Метод

Назначение

Сору

Копирует выделенный в элементе управления текст в буфер обмена
Windows.

Cut

Вырезает выделенный в элементе управления текст и помещает его
в буфер обмена Windows.

Hide

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

Paste

Вставляет содержимое буфера обмена Windows в текущий элемент
управления.

PrintForm

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

J

Формы пользователя

Метод

1 Repaint

Show

363

Назначение

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

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

В этой главе при написании примеров процедур обработки событий нам по­
надобится метод Show. Поэтому рассмотрим его подробнее.
Синтаксис метода Show:

Синтаксис
FormName.Show
В данной синтаксической конструкции FormName может быть любым объектом
UserForm текущего проекта. FormName — имя формы в том виде, как оно отобража­
ется в Project Explorer. Например, если у вас есть форма frmlnsertFigure, вывести
ее на экран можно с помощью оператора:

frmlnsertFigure.Show
Если форма в данный момент не загружена в память, метод Show загрузит ее и вы­
ведет на экран. Если форма уже загружена, метод Show просто выведет ее на экран.
В любом случае метод Show выводит форму и затем передает ей управление. Фор­
ма будет оставаться на экране до тех пор, пока не будет выполнен метод Hide объек­
та UserForm или форма не будет выгружена при помощи оператора Unload.

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

События и событийные процедуры
Событие (event) — это что-то, что может произойти с диалоговым окном
или элементом управления диалогового окна. Типичные примеры событий:
щелчок на кнопке, переключателе и т.д. Другие примеры событий: изменение
содержимого окна редактирования или выбор элемента списка. Щелчок мы­
шью, нажатие клавиши и действия внутренние для вашего компьютера, — все
они запускают или, иными словами, влекут за собой события.
Использование событий позволяет создавать действительно диалоговые
приложения. В таких приложениях все действия пользователя приводят к оп­
ределенной реакции приложения, если эти действия предусмотрены и не за­
блокированы. Если вы хотите, чтобы ваши пользователи чувствовали себя
комфортно при работе с вашими программами, начинайте создавать свои диа­
логовые окна с разработки событийных процедур.

364

Глава 9. Элементы диалоговых окон

Такие объекты, как формы и элементы управления приводят в действие, то
есть делают доступными, некоторые события. Вы можете написать собствен­
ные VBA-процедуры, реагирующие на события. Такие процедуры, называют­
ся событийными процедурами {event procedures) или процедурами обработки
событий.
Событийные процедуры следует записывать в модуль класса, который яв­
ляется частью UserForm. При этом такие процедуры должны иметь имена
в виде ObjectName_EventName, где ObjectNате — имя формы или элемента
управления, a EventName — имя события, с которым вы хотите работать. Та­
кой формат имени позволяет VBA сопоставлять заданному событию требуе­
мую процедуру.
Большая часть программы, которую вы записываете в модуль класса фор­
мы, будет связана с обработкой событий. В таблице 9.3 перечислены события,
для которых вы можете написать процедуры обработки.

Таблица 9.3. События объектов UserForm
Событие

Синтаксис заголовка
процедуры обработки
события

Описание

Activate

Private Sub
object_Activate ()

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

Click

Private Sub
object_Click(index As Long)

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

DbICIick

Private Sub
object_DblClick(index As
Long, ByVai Cancel As
MSForms.ReturnBoolean)

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

1 Deactivate Private Sub

object_Deactivate()

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

Initialize

Private Sub
object_Initialize()

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

Resize

Private Sub
UserForm_Resize()

Инициируется при изменении
размеров формы.

Формы пользователя

365

Событие

Синтаксис заголовка
процедуры обработки
события

Описание

Terminate

Private Sub
object_Terminate()

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

В дополнение к методам, свойствам и событиям, встроенным в объект
UserForm, VBA предоставляет два оператора, которые особенно полезны при
работе с объектами форм: Load и Unload. Вы можете использовать эти опера­
торы для того, чтобы загрузить форму в память или же удалить ее оттуда.

Синтаксис Load/Unload
Синтаксические конструкции для использования операторов Load и Un­
load выглядят следующим образом:

Синтаксис
Load Object
Unload Object
Здесь Object представляет любую допустимую ссылку на объект UserForm.

Оператор Load загружает в память объект UserForm и запускает метод фор­
мы Initialize, но не выводит форму на экран. Когда форма загружена, вы
можете использовать написанную на VBA программу для работы с объектом
UserForm. Оператор Unload удаляет из памяти UserForm, а также все пере­
менные формы. После того как форма выгружена, она перестает быть доступ­
ной для VBA-кода.

Примеры программ модуля класса формы
Рассмотрим несколько простых примеров использования свойств и методов
формы с помощью процедур обработки событий. Будем инициировать собы­
тия, описанные в табл. 9.3, а в ответ на них с помощью окна функции MsgBox
будем сообщать о типе события или менять видимые свойства формы. Начнем
с события Click, так как процедуру обработки этого события легче всего соз­
дать: достаточно дважды щелкнуть на форме (используем созданную в начале
главы форму) в режиме разработки, и вам будет предоставлен шаблон проце­
дуры в виде:
Private Sub UserForm_Click()

End Sub

Запишите после заголовка процедуры следующий оператор
MsgBox("Событие: Click")

366

Глава 9. Элементы диалоговых окон

Запустите форму на выполнение командой Run | Run Sub/UserForm. После по­
явления формы на экране щелкните на ней мышью, на экране отобразится со­
общение, подобное приведенному на рис. 9.2.
Рис. 9.2

Выполнение процедуры обработки события Click

Если даже вам не часто будет нужно использовать подобное событие для
формы, не забывайте о такой возможности. А еще лучше поступайте сле­
дующим образом. Всегда используйте это событие на случай, когда пользо­
ватель ваших форм при попытке щелкнуть на каком либо элементе управле­
ния не совсем точно позиционирует курсор мыши. Если при этом будет вы­
полняться процедура обработки события Click для формы с выводом
шутливого сообщения о недостаточной уверенности в действиях пользовате­
ля, с вашим приложением станет приятно работать. Вы также никогда не
забудете о возможности использовать это событие, когда для этого появятся
серьезные причины.
Продолжим рассмотрение событий и протестируем событие Activate. За­
пишите в модуле рассматриваемой формы следующую процедуру:
Private Sub UserForm_Activate()
MsgBox ("Событие: Activate")
End Sub

Снова запустите форму на выполнение командой Run | Run Sub/UserForm. По­
сле появления формы на экране вы увидите сообщение о том, что произошло
событие Activate (рис. 9.3).
Рис. 9.3

Сразу после загрузки формы произошло событие
Activate

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

Формы пользователя

367

бытия Deactivate необходимо, не выходя из приложения, сделать форму
UserForml неактивной. Это можно осуществить, если активной станет дру­
гая форма. И ее надо создать.
Создайте новую форму либо при помощи кнопки Insert UserForm, либо — ко­
мандой Insert | UserForm. Пусть она имеет имя, которое ей присваивается по
умолчанию: UserForm2. Помните, что следует всегда переименовывать формы
для удобства сопровождения разработки, но для нашего тестирования событий
мы этого делать не будем. Наметим план тестирования:
1. Загружаем форму UserForml.
2. Событие Click формы UserForml вызывает метод Show для загрузки
формы UserForm2.
3. Загрузка/выгрузка формы UserForm2 не сопровождается никакими со­
бытиями.
4. Форма UserForml имеет процедуры обработки событий: Click,
Activate, Deactivate, Terminate.
Для выполнения поставленной задачи в модуль формы UserForml необхо­
димо поместить код Листинга 9.1.
Листинг 9.1. Процедуры событий UserForml

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14 :
15:
16:
17:
18:
19:
20:
21:
22:
23:

'Обработчик события Click формы UserForml
Private Sub UserForm_Click()
'Вывод окна сообщения на экран:
MsgBox ("Событие: Click. Выводим UserForm2")
'Загрузка формы UserForm2:
UserForm2.Show
End Sub
'Обработчик события Activate формы UserForml
Private Sub UserForm_Activate()
'Вывод окна сообщения на экран:
MsgBox ("Событие: Activate для формы UserForml")
End Sub

Private Sub UserForm__Deactivate ()
'Вывод окна сообщения на экран:
MsgBox ("Событие: Deactivate для формы UserForml")
End Sub
Private Sub UserForm_Ter'minate ()
'Вывод окна сообщения на экран:
MsgBox ("Событие: Terminate для формы UserForml")
End Sub

Следует отметить, что после создания новой формы, вы не сразу можете
найти модуль формы UserForml. Ваш экран может быть похожим на тот, ко­
торый приведен на рис. 9.4.
Выберите команду Run | Run Sub/UserForm. Теперь вы имеете возможность
проследить за инициализацией всех четырех событий. Сразу после загрузки
UserForml выдается сообщение «Событие: Activate для формы UserForml»
(процедура UserForm_Activate). Щелчок на форме приводит к выводу сообще­
ния «Событие: Click. Выводим UserForm2» (процедура UserForm_Click), за­

368

Глава 9. Элементы диалоговых окон

грузке формы UserForm2 (процедура UserForm_Click) и выводу сообщения
«Событие: Deactivate для формы UserForml» (процедура UserForm_Deactivate) в результате того, что форма UserForml становится неактивной. Если бы
мы описали процедуру события Activate и для формы UserForm2, то один
щелчок мыши вызвал бы инициализацию трех событий. И, наконец, не за­
будьте обратить внимание на то, что при выгрузке из памяти формы User­
Forml на экран выдается сообщение процедуры UserForm_Terminate.
Рис. 9.4

После создания
новой формы
очень легко
«потерять»
предыдущую

Событие Initialize инициализируется при загрузке формы при помощи
оператора Load или метода Show. При выполнении команды Run | Run Sub/UserForm это событие не инициализируется. Это событие следует использовать при
первой загрузке формы для установки каких-либо свойств формы и ее элемен­
тов управления. В следующем примере (листинг 9.2) для этого события уста­
навливается свойство формы BackColor.
Листинг 9.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

Формы пользователя

369

12 :
13:
14:
15:

'Процедура обработки события Click
'При каждой инициализации меняет цвет формы
'При недопустимых значениях sRED, sGREEN, sBLUE выдает
ошибку времени исполнения
16: Private Sub UserForm_Click()
17:
Dim I
18 :
19:
'Меняем цвет формы:
20:
sRED = sRED +20
21:
sGREEN = sGREEN + 10
22:
sBLUE = sBLUE - 20
23:
i = RGB(sRED, sGREEN, sBLUE)
24:
UserForm2.BackColor = I
25:
26:
'Изменить заголовок формы:
27:
UserForm2.Caption = "Цвет: " & Str(i)
28: End Sub

Для загрузки формы UserForm2 используйте форму UserForml с програм­
мами обработки событий из листинга 9.1.
В листинге 9.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 — событие, которое инициализирует­
ся при изменении размеров формы.
Рассмотрим последнее событие, так как первое должно быть понятным
и в реализации похожим на ранее рассмотренные.
Размеры формы могут изменяться как во время диалога (если это преду­
смотрено разработчиком формы), так и программным способом. Для иллюст­

370

Глава 9. Элементы диалоговых окон

рации программы обработки события изменения формы удобнее использовать
программный способ. Листинг 9.3 содержит две процедуры: первая обрабаты­
вает событие Click (при этом изменяется свойство формы Width), вторая —
событие Resize.

Листинг 9.3. Обработка событий Click и Resize
1:
2:
3:
4:
5:
6:
7:
8:
9:

Private Sub UserForm_Click()
MsgBox ("Событие: Click")
'Меняем размер формы:
UserForml.Width = 400 ■
End Sub

'Можно UserForm_DblClick

Private Sub UserForm_Resize()
MsgBox ("Событие: Resize")
End Sub

Элементы управления
Объект UserForm может содержать те же элементы управления, что и нахо­
дящиеся в диалоговых окнах Word, Excel или других приложений Windows.
Элементы управления (controls) — это элементы диалогового окна, которые
дают возможность пользователю взаимодействовать с программой. Они вклю­
чают в себя кнопки-переключатели, текстовые поля, линейки прокрутки, ко­
мандные кнопки и так далее. В этом разделе вы познакомитесь со стандартны­
ми элементами управления, включенными в VBA, которые сможете добавлять
в свои формы.
Многие производители программного обеспечения разрабатывают пакеты,
расширяющие набор элементов управления. Вы можете добавлять элементы
управления (известные как объекты ActiveX и Automation) к панели Toolbox
(панели элементов), предварительно создавая ссылку из вашего проекта на
библиотеку, содержащую расширенный набор элементов управления. После
этого можно добавлять данные элементы управления на панель Toolbox.
Каждый элемент управления — это объект с определенными свойствами,
методами и событиями. Как и для формы, их содержащей, вы можете устанав­
ливать свойства элементов управления программным путем или посредством
Properties Window редактора VB. В программе вы можете присваивать или вос­
станавливать значения свойств элементов управления так же, как для любых
других объектов.
В табл. 9.4 перечислены стандартные элементы управления, включенные
в VBA, и описано назначение каждого элемента. Как видно из этой таблицы,
к стандартным относятся, практически, все элементы управления, которые
вам встречались в приложениях Windows. (В зависимости от host-приложения
VBA, в котором вы работаете, на панели Toolbox могут появляться дополни­
тельные элементы управления, не перечисленные в табл. 9.4. Эти дополни­
тельные элементы доступны посредством библиотек элементов управления,
поставляемых с каждым из host-приложений.)

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

371

Таблица 9.4. Стандартные элементы управления, включенные в VBA
Элемент
управления

Назначение

Label
(надпись, метка)

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

TextBox
(текстовое поле)

Окно редактируемого текста свободной формы для ввода
данных. Может быть одно- или многострочным.

ComboBox
(поле со списком)

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

ListBox
(список)

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

CheckBox
(флажок)

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

OptionButton
(переключатель)

Стандартная кнопка-переключатель (круглое окно, при выборе
в центре него находится черная точка). Используйте
OptionButton, когда пользователю необходимо сделать выбор
между «включено/выключено», «истина/ложь».
Кнопки-переключатели, как правило, объединяются вместе при
помощи рамки для создания группы переключателей.

I ToggleButton
' (выключатель)

Выключатели служат для той же цели, что и флажки, но
выводят установки в виде кнопки находящейся в «нажатом» или ।
«отжатом» состоянии.

Frame
(рамка)

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

CommandButton
(кнопка)

Используйте кнопки для выполнения таких действий, как
Cancel (Отмена), Save (Сохранить), ОК и так далее. Когда
пользователь щелкает по кнопке, выполняется VBA-процедура, i
закрепленная за данным элементом управления.

372

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

Глава 9. Элементы диалоговых окон

Назначение

TabStrip
(набор вкладок)

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

MultiPage
(набор страниц)

Этот элемент управления состоит из нескольких страниц. Вы
можете выбрать любую из них, щелкнув по соответствующей
вкладке. Используйте элемент управления MultiPage для
создания диалоговых окон с вкладками, такими, например, как
диалоговое окно, появляющееся при выборе команды Tools |
Options (панели инструментов | настройка).

ScrollBar
(полоса прокрутки)

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

1 SpinButton
(счетчик)

Image
(рисунок)

Элемент управления SpinButton является специальной
разновидностью текстового поля. Обычно счетчики
используются для того, чтобы ввести число, дату или
какие-либо иные последовательные величины, которые
заведомо находятся в определенном интервале значений.
Щелчок по указывающей вверх стрелке счетчика увеличивает
значение в окошке, а щелчок по стрелке, направленной вниз,
соответственно, уменьшает его.

Элемент управления Image позволяет вывести на форме
графическое изображение. Используйте Image для вывода
графических изображений в любом из следующих форматов:
*.bmp, *.cur, *.gif, *.ico, *.jpg, или *.wmf. Вы можете обрезать
и масштабировать графическое изображение, чтобы подобрать
размер элемента Image, но только не редактировать
графическое изображение. Можно даже написать специальную
VBA-процедуру, выполняющуюся, если пользователь щелкнет по
элементу управления Image.
J

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

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

373

Таблица 9.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,
ListBox

Массив типа Variant (одно- или многомерный),
представляет список содержащийся в элементе
управления. Используйте методы элемента
управления Additem и Removeitem для
добавления или удаления пунктов списка.

374

1 Свойство

Глава 9. Элементы диалоговых окон

Где
применяется

Описание

Мах

ScrollBar,
SpinButton

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

Min

ScrollBar,
SpinButton

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

Name

Все элементы
управления

Содержит имя элемента управления. Вы можете
установить данное свойство только с помощью
Properties Window.

RowSource

ComboBox,
ListBox

Задает источник, из которого ComboBox или
ListBox «берет» список объекта. В Excel VBA
RowSource обычно использует диапазон
рабочего листа.

Selected

ListBox

Возвращает массив значений типа Boolean для
списка, который допускает множественный
выбор.Каждый элемент массива содержит по
одному элементу, соответствующему каждому
пункту списка. Если значение элемента в массиве
Selected равно True, то соответствующий пункт
списка выбран.

Tabindex

Все элементы
управления

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

TabStop

Все элементы
управления

Значение типа Boolean, указывающее может ли
элемент управления быть выбран клавишей Tab.
Если значение TabStop равно False вы, тем не
менее, можете щелкнуть на элементе и таким
образом его выбрать.

Value

Все элементы
управления

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

Все элементы
управления

Значение типа Boolean, указывающее, является
ли элемент управления видимым. ______________ }

| Visible________

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

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

375

бытиям. В частности, для кнопок используется событие Click, а для того, что­
бы проверить данные или обновить другие элементы управления, — After­
Update или Change.

Таблица 9.6. Наиболее часто используемые события
объектов управления
i Событие

AddControl

Синтаксис процедуры
обработки

Описание

для элемента Frame:

Инициируется всякий раз, когда
к форме (или элементам Frame,
Page, MultiPage) добавляется
какой-либо элемент управления.

Private Sub
obj ect_AddControl ()
для элемента MultiPage:

Private Sub
object_AddControl(index As
Long, Ctrl As Control)
AfterUpdate

Private Sub
obj ect_AfterUpdate()

Инициируется после обновления
значения элемента управления.

BeforeUpdate

Private Sub
object_BeforeUpdate(ByVai
Cancel As
MSForms.ReturnBoolean)

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

Change

Private Sub object_Change()

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

Private Sub object_Click()

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

i Click

DbICIick

Инициируется всякий раз, когда
Private Sub
object_DblClick(ByVai Cancel по элементу управления дважды
щелкают мышью.
As MSForms.ReturnBoolean)

Enter

Private Sub object_Enter()

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

Private Sub
object_Exit(ByVai Cancel As
MSForms.ReturnBoolean)

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

Private Sub
object_Error(Index As Long,
ByVai Number As integer,
ByVai Description As
MSForms.Returnstring)

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


1
Error

Глава 9. Элементы диалоговых окон

376

Событие

Синтаксис процедуры
обработки

Описание

KeyDown

Private Sub
object_KeyDown(ByVai KeyCode
As MSForms.Returninteger,
ByVai Shift As fmShiftState)

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

KeyPress

Private Sub
object_KeyPress(ByVai
KeyANSI As
MSForms.Returninteger)

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

KeyUp

Private Sub
object_KeyUp(ByVai KeyCode
As MSForms.Returninteger,
ByVai Shift As fmShiftState)

Инициируется, когда
пользователь отпускает клавишу,

Private Sub object_Layout()

Инициируется, когда изменяются f
размеры элемента Frame (или

Layout

j

MultiPage).

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 Y As Single)

Инициируются при щелчке
мышью. MouseDown: когда
пользователь нажимает на
клавишу мыши; MouseUp: когда
пользователь отпускает клавишу
мыши.

'

для других элементов управления:

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)

-----



.

, ...

---

------

Использование Toolbox (панели элементов)

377

Событие

Синтаксис процедуры
обработки

Описание

MouseMove

для элементов MultiPage
и TabStrip:

Инициируется, когда
пользователь перемещает мышь.

Private Sub
object_MouseMove(index As
Long, ByVai Button As
fmButton, ByVai Shift As
fmShiftState, ByVai X As
Single, ByVai Y As Single)
для других элементов управления:

Private Sub
object_MouseMove(ByVai
Button As fmButton, ByVai
Shift As fmShiftState, ByVai
X As Single, ByVai Y As
Single)
SpinDown,
SpinUp

Private Sub
obj ect_SpinDown()
Private Sub object_SpinUp()

Событие SpinDown инициируется,
когда пользователь щелкает
стрелку «вниз» (или «влево»)
кнопки счетчика. Событие SpinUp
инициируется, когда пользователь
щелкает стрелку «вверх» (или
«вправо») кнопки счетчика.

Zoom

Private Sub
object_Zoom(index As Long,
Percent As Integer)

Инициируется при изменении
свойства Zoom.

Использование Toolbox (панели элементов)
Прежде чем мы рассмотрим примеры обработки событий, связанных с эле­
ментами управления, вам следует научиться помещать элементы управления
на форму и задавать им необходимые свойства.
Редактор VB в режиме разработки вместе с формой выводит на экран
Toolbox (панель элементов) (если вывод этой панели не отключен при помощи
меню View | Toolbox). На рис. 9.5 Toolbox показана в виде плавающего окна.
Кнопки на панели Toolbox активизируют различные инструменты, которые по­
зволяют помещать на форму элементы управления (на рис. 9.5 приведена па­
нель Excel).
Toolbox (подобно всем другим панелям инструментов) можно настраивать.
Если вы или другой пользователь установили дополнительные элементы
управления независимых производителей или произвели настройку панели,
она может выглядеть иначе, чем та, что показана на рис. 9.5. На рис. 9.5 при­
сутствуют только стандартные элементы управления, поставляемые вместе
с VBA.

378

Глава 9. Элементы диалоговых окон

2

4

6

8

10

12

14

16

16

Рис. 9.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 (рисунок), 16 — RefEdit, 17 — DataGrid (сетка данных),
18 — MSFIexGrid

Чтобы воспользоваться панелью Toolbox для добавления элементов управле­
ния к вашей форме, выполните следующие действия:
1. Щелкните на Toolbox по кнопке, соответствующей элементу управления,
который вы хотите добавить к форме. Указатель мыши изменит форму
на перекрестие, когда будет находиться на форме.
2. Установите перекрестие в то место формы, в котором хотите поместить
верхний левый угол нового элемента управления.
3. Нажмите и удерживайте левую кнопку мыши.
4. Перемещайте мышь вниз и вправо, пока элемент управления не примет
нужный размер, после чего отпустите кнопку мыши. Редактор VB вста­
вит в форму элемент управления, и указатель мыши вновь примет форму
стрелки.
Вы можете изменить размер самой формы. Щелкните по строке заголовка
формы для ее выделения и затем, перемещая один из маркеров изменения раз­
меров, увеличьте или уменьшите размер формы до желаемого. Маркеры изме­
нения размеров (sizing handles) — это маленькие квадратики, которые появля­
ются в углах и на серединах сторон графического объекта (наряду с толстой се­
рой границей) при выделении объекта.

Добавление к форме элементов управления
Когда вы создаете новую форму, редактор VB предоставляет чистую (без эле­
ментов управления) форму (смотри рис. 9.1). Вы можете добавить к форме эле­
менты управления с использованием различных инструментов панели Toolbox.
Чтобы добавить к форме элемент управления, используйте панель Toolbox,
как описано в предыдущем параграфе этой главы. В качестве примера добав­
ления к форме конкретного элемента добавьте на новую форму кнопку, выпол­
нив следующие действия:

Использование Toolbox (панели элементов)

379

1. Выберите команду Insert | UserForm (Вставка | UserForm). Редактор VB до­
бавит новую форму, отображая ее в режиме разработки, и, кроме того,
на экране появится Toolbox.
2. Щелкните на элементе CommandButton панели Toolbox. Кнопка перейдет
в «утопленное» состояние, указывая выбранный вами элемент.
3. Поместите курсор мыши на форму. Курсор при этом изменит свою фор­
му на перекрестие с прикрепленным к нему символом выбранного эле­
мента.
4. Поместите перекрестие в ту точку формы, в которой должен быть верх­
ний левый угол кнопки.
5. Переместите курсор мыши вниз и вправо, чтобы нарисовать элемент
управления CommandButton. В процессе перемещения курсора мыши ре­
дактор VB отображает прямоугольный контур, показывающий размер
кнопки.
6. Отпустите кнопку мыши, когда решите, что CommandButton имеет необхо­
димый размер. Редактор VB создаст элемент управления CommandButton
и поместит его на форму. На рис. 9.6 показано, как выглядит кнопка,
сразу же после того, как была помещена на форму.
Рис. 9.6
UserForml сразу же после добавления элемента
CommandButton

Добавив к форме кнопку, вы можете заметить, что верхний левый угол
кнопки (также как и сама граница кнопки) автоматически выравнивается по
шаблону сетки на форме. Это действие, называемое привязка к сетке (snap to
grid), поможет вам выровнять размещенные на форме элементы управления
и текст. Вы можете включать и отключать привязку к сетке, настраивать шаг
сетки или скрывать ее, изменяя установки в диалоговом окне Option (Парамет­
ры) редактора VB. Выберите Tools | Options (Сервис | Параметры) и щелкните по
вкладке General (общие), чтобы вывести Form Grid Settings (Параметры сетки
в форме). Выберите или сбросьте необходимые опции.
Все элементы управления формы должны иметь уникальные имена. Эти
имена следует использовать при ссылках на элемент управления в своей про­
грамме. Всякий раз, когда вы добавляете к форме новый элемент управления,
VBA присваивает ему имя по умолчанию, состоящее из имени типа элемента
и номера. Если кнопка, которую вы добавили в начале этого раздела, является
первой кнопкой, она получит имя CommandButtonl. Следующая добавленная
вами кнопка будет CommandButton2 и так далее. Если после этого вы добави­
те поле, оно получит имя TextBoxl.

380

Глава 9. Элементы диалоговых окон

Перед тем как продолжить работу с формами, давайте договоримся о не­
сложных правилах, которые помогут вам с первых шагов создавать диалого­
вые окна, почти похожие на профессиональные. Если вы до сих пор не обра­
щали внимания на то, что все окна «солидных» разработчиков имеют общие
черты, то сейчас как раз то время, когда это нужно сделать. На рис. 9.7 при­
ведена схема, которой можно придерживаться при разработке своих первых
форм.
Рис. 9.7

Схема типичного
диалогового
Windows-окна

Наименование окна, как вы уже знаете, задается свойством Caption фор­
мы. Кнопка закрытия окна, если ничего специально не предпринимать, по
умолчанию всегда будет в окне приложения. Если она вам не нужна, то лучше
от нее избавиться.
В «полезной» части окна помещаются функционально необходимые эле­
менты управления, которые определяются назначением окна. Здесь могут
быть, например, элементы для ввода некоторой информации или изменения
настроек приложения.
С кнопкой ОК обычно связывают событие, которое подводит некоторый
итог. Обычно в профессиональных приложениях все, что вводится в диалого­
вом окне, не сразу вступает в действие, а только после того, как пользователь
щелкнет кнопку ОК. Это дает возможность отказаться от недостаточно обду­
манных действий. Разработчику таких окон не очень трудно скопировать дан­
ные из диалогового окна в несколько переменных прежде, чем присвоить их
каким-либо свойствам элементов управления, а пользователю удобнее рабо­
тать с окном, из которого всегда можно выйти без последствий.
Из предыдущего абзаца, видимо, понятно назначение кнопки Отмена. До­
полнительной ее функцией является выход из процедуры обработки событий
формы. Кнопка же ОК может разрешить пользователю продолжить путешест­
вие «внутрь» приложения, которое открылось данным окном (иногда говорят
«панелью» или «диалогом»).
Кнопка Справка знакома всем «с детства». К сожалению, не так просто орга­
низовать помощь, подобную обычной Windows-справке, но можно сначала ис­
пользовать эту кнопку для простых подсказок, которые создаются помещени­
ем на пустую форму элемента Label с текстом подсказки. В дальнейшем, изу­

Использование Toolbox (панели элементов)

381

чив способы построения сложных систем подсказок, можно создавать почти
профессиональные диалоговые окна.
Этих нехитрых правил, конечно же, вам хватит при проектировании не­
сложных форм. При создании «хороших» форм следует ознакомиться с реко­
мендациями фирмы Microsoft. Эти рекомендации имеют отношение к следую­
щим аспектам:
□ Размещение элементов управления на форме (в том числе и установка ин­
тервалов между элементами).
□ Выравнивание меток (метки должны быть хорошими путеводителями
формы).
□ Использование стандартных шрифтов (часто пользователи собирают по
«всему свету» интересные шрифты и забывают о том, что такие шрифты
могут отсутствовать у других).
□ Использование цвета.
При размещении на форме нескольких элементов управления, которые
можно условно разделить на отдельные группы, следует использовать элемент
frame (рамка). При этом желательно пользоваться свойством, определяющим
заголовок рамки.
Для более легкого чтения полей, расположенных друг под другом, необхо­
димо выравнивать их по левому краю.
Для всех элементов управления используйте в качестве шрифта нормаль­
ный Sans Serif 8-пунктов. Конечно, следует учитывать и запросы потенци­
ального пользователя вашего продукта, но при подготовке тестового вариан­
та для обсуждения сначала необходимо придерживаться рекомендаций
Microsoft.
Самые обычные серые цвета, которые вы можете видеть во всех известных
продуктах Windows, рекомендуются и для ваших приложений. Хотя в вашем
распоряжении имеется большое количество цветов, все равно без особой нуж­
ды не следует изменять цвета по умолчанию. Если же вы можете предоставить
пользователю работающего приложения самому изменять цвета формы и эле­
ментов управления на ней, это будет опимальным вариантом.
Итак, если вы согласны с предлагаемыми правилами, создайте свою первую
форму в соответствии со схемой рис. 9.7, как это показано на рис. 9.8.
В следующей таблице приведены значения свойств элементов управления,
которые были изменены. Для своих приложений в качестве документации вы
тоже можете создавать такие таблицы для облегчения сопровождения своего
программного продукта.
Тип элемента

Свойство,
которое
изменено

Значение

Примечание

UserForm

Name

Frmfirst

Имя формы, на которое можно
ссылаться в коде.

Caption

Тестирован Заголовок окна (формы) в верхней части.
ие кнопок



CommandButton Name

CmdOK

Имя кнопки, на которое можно
ссылаться в коде.

382

Глава 9. Элементы диалоговых окон

Тип элемента

Свойство,
которое
изменено

Значение

Примечание

Caption

OK

Текст на кнопке.

Default

True

При нажатии на клавишу Enter
инициируется событие Click кнопки.

CmdCancel

Имя кнопки, на которое можно
ссылаться в коде.

Caption

Отмена

Текст на кнопке.

Cancel

True

При нажатии на клавишу Esc
инициируется событие Click кнопки.

CmdHelp

Имя кнопки, на которое можно
ссылаться в коде.

Справка

Текст на кнопке.

CommandButton Name



CommandButton Name
Caption

J

Рис. 9.8

Форма с самыми
необходимыми
кнопками

В VBA (как и в Microsoft Visual Basic) кнопки (элементы CommandButton)
имеют специальное свойство Cancel, которое определяет кнопку Отмена (неза­
висимо от того, называется ли эта кнопка Отмена). Только одна кнопка формы
может иметь свойство Cancel, установленное равным True. Если задать это

Использование Toolbox (панели элементов)

383

свойство для одной из кнопок, аналогичное свойство для всех остальных кно­
пок формы будет установлено равным False. Если форма содержит кнопку
с установленным свойством Cancel, то нажатие клавиши Esc приводит к тому
же результату, что и щелчок по кнопке.
Если вы запустите форму на выполнение (командой Run | Run Sub/UserForm),
то ни щелчок на кнопке, ни нажатие клавиши Esc не приведут ни к какому ре­
зультату, так как с кнопкой не связано никакого события. Но диалоговое окно
появится на экране в режиме выполнения и будет создавать впечатление че­
го-то работающего (рис. 9.9).
Рис. 9.9

Такое окно тоже «имеет право» называться
«диалоговым»

Если вы будете щелкать кнопки этого окна, то убедитесь в том, что окно со­
вершенно «нечувствительно» к вашим манипуляциям. Единственная кнопка,
которая будет реагировать на ваши действия, находится вверху справа (с изо­
бражением перекрестия). Эта кнопка закроет окно.
Чтобы кнопки, помещенные вами на диалоговой панели, «ожили», необхо­
димо для каждой из них написать процедуры обработки событий Click (щелчок
на кнопке). Начнем с кнопки Отмена, чтобы всегда иметь возможность выйти из
приложения. Свяжем с щелчком на кнопке Отмена программу, которая выгру­
зит форму, что приведет к окончанию работы с диалоговым окном. Для созда­
ния процедуры обработки события дважды щелкните на кнопке Отмена в режи­
ме разработки и в появившемся шаблоне процедуры обработки события введите
оператор выгрузки формы, как это представлено в листинге 9.4.
Листинг 9.4. Процедура обработки события — щелчок на кнопке Отмена

1: Private Sub CmdCancel _Click()
2:
Unload Me
'Выгружаем форму, заканчивая приложение
3: End Sub

Снова запустите форму на выполнение. Вы увидите то же диалоговое окно,
что и на рис. 9.9, но теперь это окно — «настоящее» диалоговое, потому что
при щелчке на кнопке Отмена выполняется программа обработки события
и окно закрывается. Более того, при нажатии на клавишу Esc вы получаете
точно тот же результат! Понятно, что процедура обработки события Click
(именно это событие и связано с кнопкой) может выполнить и более серьезную
работу, чем простая выгрузка формы. Чтобы это было действительно понятно,
добавим к процедуре вывод сообщения о том, что возможен выход из диалога
(см. листинг 9.5).

384

Глава 9. Элементы диалоговых окон

Листинг 9.5. Более «продвинутая» процедура обработки события —

щелчок на кнопке Отмена

1:
Private Sub CmdCancel Click()
2:
'объявление переменных
3:
Dim Msg, Title, Response As String
4:
5:
'выдаваемое в окне MsgBox сообщение
6:
Msg = "Хотите закончить работу?"
7:
8:
'состав кнопок и тип значка
9:
Style = vbYesNo + vbCritical + vbDefaultButton2
10:
11:
'заголовок окна
12:
Title = "Выход из программы"
13:
14:
'вызов функции MsgBox- с возвращаемым значением
15:
Response = MsgBox(Msg, Style,
16:
Title)
17:
'анализ возвращаемого значения
18:
If Response = vbYes Then
19:
Unload Me
'выгрузка формы
20:
End If
21:
22: End Sub

Если вы запустите форму с такой процедурой обработки события Click
и щелкните на кнопке Отмена или нажмете клавишу Esc, то на экран будет вы­
дано сообщение, подобное приведенному на рис. 9.10. Эта процедура стала бо­
лее дружественной, поскольку не сразу заканчивает работу окна диалога. Слу­
чайный щелчок на кнопке Отмена или нажатие на клавишу Esc не приведут
к немедленному окончанию работы с диалогом.
Рис. 9.10

1

кнопок

X\

Процедура обработки сообщения от кнопки
Отмена стала более дружественной

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

Использование Toolbox (панели элементов)

385

с элементом Label, свойством Caption которого будет также длинное сообще­
ние о полезности приложения. Далее будет рассмотрено создание и вызов до­
полнительного диалогового окна приложения.
Очень полезной может оказаться процедура обработки события Change —
при любом изменении свойств элементов управления (в конечном итоге, все,
что происходит в диалоговом окне — это изменение тех или иных свойств)
можно выполнять некоторые проверки на допустимость изменений и сообщать
пользователю о возможных проблемах. Можно также использовать событие
Change для подсказки пользователю о происходящих изменениях со свойства­
ми элементов управления. В качестве примера создайте форму UserForml так,
чтобы она была похожа на представленную на рис. 9.11. Чтобы соответствую­
щее форме диалоговое окно позволило продолжить работу с приложением,
в этом окне необходимо в одном из текстовых полей ввести либо фамилию,
либо имя пользователя. При изменении содержимого любого поля (свойство
Text) инициируется процедура обработки события Change, в которой свойству
Enable кнопки OK_button (с заголовком ОК) присваивается значение True.
Кнопка OK_button предназначена для изменения свойства Caption формы
UserForm2 и вывода этой формы на экран. Кнопка с заголовком Отмена все­
гда доступна и предназначена для выхода из программы. Свойство Cancel
этой кнопки имеет значение True.
Рис. 9.11

Форма для тестирования события
Change для TextBox

Для создания такой формы выполните следующее:
1. Создайте новую форму с именем по умолчанию UserForml. В Properties
Window измените свойство Caption этого элемента на Тестирование со­
бытия Change.
2. Поместите на форму UserForml элемент Frame. По умолчанию его имя
будет Frame 1. Измените свойство Caption этого элемента на Данные
о пользователе. (Размеры элемента не важны.)
3. Поместите на форму в область Framel элемент TextBox (с именем по
умолчанию TextBoxl) и элемент Label с заголовком (свойство Caption)
Фамилия. Имя метки для данного случая не имеет значения.
4. Поместите на форму в область Framel элемент TextBox (с именем по
умолчанию TextBox2) и элемент Label с заголовком Имя.
5. Поместите на форму (см. рис. 9.10) элемент CommandButton и измените
его свойство Name на Cancel_button, а свойство Caption на Отмена. Уста­
новите свойство Cancel в True, чтобы при нажатии на клавишу Esc про­
грамма выполняла ту же процедуру, что и при щелчке на кнопке Отмена.
13 VBA. Эффективное использование

386

Глава 9. Элементы диалоговых окон

6. Поместите на форму элемент CommandButton и измените его свойство
Name на OK_button, а свойство Caption — на ОК. Измените свойство
Enabled этой кнопки на False. Этим вы сделаете кнопку ОК недоступ­
ной для пользователя после выдачи диалогового окна на экран в режиме
выполнения. Чтобы кнопка стала доступной и приложение могло выпол­
нить какую-либо работу с использованием кнопки ОК, пользователь дол­
жен будет изменить содержимое одного из текстовых окон.
7. Откройте модуль класса формы UserForml и запишите в него код, пред­
ставленный в листинге 9.6.
8. Создайте форму UserForm2 (без элементов управления) и запишите в мо­
дуль класса этой формы код, например, из листинга 9.2.
Тип элемента

Свойство,
которое
изменено

Значение

Примечание

UserForm

Name

UserForml

Имя главной формы, на которое
можно ссылаться в коде.

Caption

Тестирование
события Change

Заголовок окна (формы) в верхней
части.

Name

Framel

Имя, на которое можно ссылаться
в коде.

Caption

Данные
о пользователе

TextBox

Name

TextBoxI

Label

Name

Label 1

Caption

Фамилия

Заголовок для текстового окна
TextBoxI.

TextBox

Name

TextBox2

Имя, на которое можно ссылаться
в коде.

Label

Name

Label 2

Caption

Имя

Заголовок для текстового окна
TextBox2.

Name

Cancel-button

Имя кнопки, на которое можно
ссылаться в коде.

Caption

Отмена

Текст на кнопке: кнопка для
окончания работы приложения.

Name

OK_button

Caption

OK

Текст на кнопке: кнопка для
продолжения работы приложения.

Enabled

False

Кнопка недоступна для
пользователя сразу после выдачи
диалогового окна на экран.

Name

UserForm2

Имя формы, загружаемой из
главной при щелчке на кнопке ОК.

Frame

CommandButton

CommandButton

UserForm

Имя, на которое можно ссылаться
в коде.



Использование Toolbox (панели элементов)

387

Выполните команду Run | Run Sub/UserForm. Если вы не будете редактировать
(изменять) содержимое текстовых окон, вам будет доступна только кнопка Вы­
ход. Как только вы измените содержимое какого-либо текстового окна (Фами­
лия или Имя), инициируется событие Change и свойству Enabled кнопки ОК
будет присвоено значение True (строка 17 листинга 9.6). Так как с кнопкой ОК
связана процедура обработки события Click, которая загружает форму
UserForm2, пользователь получает возможность дальнейшей работы. При
этом свойству Caption формы присваивается сумма содержимого полей
TextBoxl и TextBox2.
Листинг 9.6. Обработка события Change

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16;
17:
18:
19:
20:
21:
22:
23:

'Обработка события Click кнопки Выход
Private Sub Cancel_button_Click ()
MsgBox ("Заканчиваем программу!")
Unload Me
End Sub
'Обработка события Click кнопки OK
Private Sub OK_button_Click()
'Изменить заголовок диалогового окна UserForm2
UserForm2.Caption = TextBoxl.Text + TextBox2.Text
UserForm2.Show
'загрузка окна UserForm2
End Sub

'Обработка события Change текстового окна с меткой Фамилия
Private Sub TextBoxl_Change ()
Next_button.Enabled = True
End Sub
'Обработка события Change текстового окна с меткой Имя
Private Sub TextBox2_Change()
Next—button.Enabled = True
End Sub

Редактирование элементов управления на форме
Поместив на форму элемент управления, вы имеете возможность изменять
его размеры, двигать, копировать, удалять, форматировать (изменять размер,
стиль, гарнитуру шрифта) или изменять его свойства (такие как имя, заголо­
вок и так далее).

Выбор элементов управления

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

388

Глава 9. Элементы диалоговых окон

гарнитуры. Выбор нескольких элементов управления может также оказаться
полезным, если вы хотите переместить эти элементы одновременно.
Вы можете временно сгруппировать несколько элементов управления, вос­
пользовавшись командой Format | Group (Формат | Группировать). Если элемен­
ты управления сгруппированы, они ведут себя как один объект, когда вы их
выбираете, перемещаете, копируете или редактируете. Элементы управления
остаются сгруппированными до тех пор, пока вы не примените к выделенной
группе команду Format | Ungroup (Формат | Разделить).

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

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

Копирование, вставка и удаление элементов управления
Один из самых простых способов создать несколько одинаковых элементов
управления, таких как несколько флажков или кнопок, состоит в том, чтобы
сначала создать один элемент управления, скопировать его, после чего помес­
тить скопированный элемент в форму столько раз, сколько необходимо. Чтобы
скопировать элемент управления, просто выберите его и затем воспользуйтесь
командой Edit | Сору (Правка | Копировать) или нажмите Ctrl+C.
После того как элемент управления скопирован, вы можете вставить его
в ту же или другую форму, используя команду Edit | Paste (Правка | Вставить)
или нажав Ctrl+V. После выполнения операции вставки переместите элемент
управления в предназначенное для него место.
Чтобы удалить элемент(ы) управления, выделите его (их), после чего на­
жмите клавишу Delete. Редактор VB удалит выделенный(-ные) элемент(-ы)
управления.

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

Использование Toolbox (панели элементов)

389

вать текст, используя любые стандартные команды редактирования текста
Windows, с которыми вы уже знакомы. Однако для того, чтобы изменить гар­
нитуру, стиль или размер шрифта, необходимо вывести для соответствующего
элемента управления Properties Window (окно свойств) и изменить свойство
Font.
Чтобы отредактировать текст заголовка формы, отредактируйте свойство
формы Caption в Properties Window. А для форматирования текста заголовка
формы воспользуйтесь свойством формы Font.
Некоторые элементы управления, такие как поля (TextBox), списки
(ListBox) и поля со списком (ComboBox) не имеют встроенной надписи (или
заголовка). Чтобы пометить такие элементы на форме, используйте элемент
Label.

Управление последовательностью перехода
В активном состоянии ваша форма будет вести себя подобно другим диало­
говым окнам Windows. Пользователь вашего диалогового окна может перехо­
дить от одного элемента управления к другому вперед и назад, используя соот­
ветственно клавиши Tab или Shift+Tab. Порядок, в котором будут активизи­
роваться элементы управления в ответ на нажатие пользователем клавиш Tab
или Shif+Tab, называется последовательностью перехода (tab order) элемен­
тов управления. Обычно последовательность перехода для элементов управле­
ния выбирают так, чтобы она соответствовала (приблизительно) перемещению
слева направо и сверху вниз. Вообще говоря, вы должны постараться так рас­
положить элементы управления, чтобы последовательность перехода обеспе­
чивала логическое перемещение от одного элемента управления диалогового
окна к другому. Например, если пользователь вводит некоторые данные с ис­
пользованием клавиатуры, то ему удобнее не прибегать к помощи мыши для
перехода к следующим окнам ввода. В этом случае логичный для данного диа­
логового окна переход к различным элементам управления будет очень кста­
ти.
Редактор VB по умолчанию устанавливает для элементов управления по­
следовательность перехода, определяемую порядком, в котором они были до­
бавлены на форму. Очень часто, после того, как вы разместили на форме все
элементы управления и несколько раз их передвинули, чтобы добиться прием­
лемого вида формы, установленная по умолчанию последовательность перехо­
да уже больше не обеспечивает логической последовательности перемещения
по элементам управления диалогового окна.
Для изменения последовательности перехода, выполните следующие дей­
ствия:
1. Выберите команду View | Tab Order (Вид | Последовательность перехода);
редактор VB отображает диалоговое окно Tab Order (Последовательность
перехода), показанное на рис. 9.12. Список Tab Order выводит все элемен­
ты управления формы в существующей на данный момент последова­
тельности.
2. В списке Tab Order выберите элементы, положение которых хотите изме­
нить. (На рис. 9.12 выбран элемент управления с именем TextBoxl.)

390

Глава 9. Элементы диалоговых окон

Рис. 9.12

Использование диалогового окна Tab Order
для изменения последовательности перехода
к элементам управления формы

3. Используя кнопки Move Up (вверх) и Move Down (вниз), измените положе­
ние выбранного элемента управления в последовательности перехода.
Щелчок по кнопке 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.

Использование Toolbox (панели элементов)

391

Вы также можете задать значение по умолчанию для поля, введя текст не­
посредственно в элемент управления TextBox на форме. После этого каждый
раз при выводе формы поле будет содержать введенный вами текст.
Некоторые свойства элементов управления, например, Enabled (доступ­
ность) или Visible (видимость на форме) удобно устанавливать в процессе вы­
полнения кода. Если, например, в некоторое текстовое окно не введено имя
файла, данные из которого необходимо считать, то кнопка для начала считы­
вания вряд ли должна давать возможность запустить код для считывания, т.е.
ее свойство Enabled должно иметь значение False, а не True. Или, например,
нет смысла в кнопке с заголовком (свойство Caption) Удалить, если имя фай­
ла, который следует удалить, еще не введено в диалоговое окно.
Некоторые элементы управления вообще незачем отображать (свойство
Visible должно быть равным False) до того момента, как они действительно
станут необходимы.
В некоторых случаях бывает удобным одни и те же элементы управления
использовать для разных целей, меняя, например, их свойство Caption. Если
вы имеете кнопку с заголовком Редактировать и уже щелкнули на ней, будет
вполне логично, если на этой кнопке появится заголовок Сохранить и код, со­
ответствующий этой кнопке, с кода подготовки для редактирования (и измене­
ния заголовка на Сохранить) изменится на код сохранения результатов редак­
тирования (и изменения заголовка Редактировать).
В режиме разработки свойства формы или элемента управления устанавли­
ваются в Properties Window, где перечислены все свойства объекта, которые вы
можете установить в этом режиме. Конкретные свойства, появляющиеся
в этом окне, зависят от выбранного вами элемента управления. На рис. 9.13
показано Properties Window для кнопки с именем (свойством Name) CmdOK и за­
головком (Caption) Вычислить для некоторой формы.
Properties Window имеет две страницы (вкладки). Первая — показана на
рис. 9.13 и содержит список свойств объекта в алфавитном порядке. Вторая
страница, показанная на рис. 9.14, содержит список свойств, разделенных на
категории. Заметьте, что различные категории выделены в Properties Window
жирным шрифтом: Appearance (Вид), Behavior (Поведение), Font (Шрифт) и так
далее. Вы можете свернуть или развернуть список свойств конкретной катего­
рии, щелкнув по квадратику слева от заголовка каждой из категорий.
Рис. 9.13
Properties Window для кнопки, показывающее

список свойств в алфавитном порядке

392

Рис. 9.14
Properties Window для кнопки, показывающее

список свойств по категориям

Глава 9. Элементы диалоговых окон

izi

Properties - I'rndGK
CmdOK CommandButton
Alphabetic [WSSS li

s Appearance
(Name)
BackColor
BackStyle

*
•CmdOK.....................................g

nSeooqoqoS".
1 - fmBackStyleOpaque

I Вычислить
ControiTipText
ForeColor

И &H80000012&

Visible

[True

H Behavior
AutoSize

False

Cancel

False

Default

False

Enabled

True

iLocked

False

HakeFocusOnClick True
Wordwrap

False

Чтобы задать свойство формы или элемента управления, щелкните в поле,
соответствующем свойству, которое хотите изменить. Для большинства
свойств появится раскрывающийся список. Щелкните по кнопке списка и вы­
берите из списка нужное значение свойства. Другие свойства (такие как Name
и Caption) дают возможность ввести любой необходимый текст. Некоторые
свойства при их выборе выводят кнопку с многоточием (...). Щелчок по такой
кнопке открывает дополнительные диалоговые окна, помогающие задать это
свойство.
Чтобы изменить свойства формы или элемента управления, выполните сле­
дующие действия:
1. Выберите элемент управления, свойства которого хотите изменить. Что­
бы выделить форму, щелкните где-нибудь на поверхности формы, не за­
нятой элементами управления.
2. Выберите команду View | Properties Window (Вид | Окно свойств) для отобра­
жения Properties Window. (Вы можете сделать это и щелчком на кнопке
Properties Window на панели инструментов редактора VB или, нажав

F4.)
3. Установите необходимое свойство для выбранного элемента управления.
4. Щелкните по кнопке Close (закрыть) в верхнем левом углу окна Properties
Window, чтобы его закрыть.
Итак, вы познакомились с основными положениями создания и управле­
ния диалоговыми окнами и их элементами. Более полную информацию о каж­
дом элементе управления можно получить из справочной системы VBA.

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

393

Использование Toolbox (панели элементов)

Многие элементы управления по умолчанию не помещаются на Toolbox.
Этот «недостаток» легко исправить, воспользовавшись диалоговым окном,
которое «отвечает» за то, какие именно элементы управления должны нахо­
диться на Toolbox. Но прежде чем «отправляться на поиски» дополнительных
элементов управления, подготовьте себе место на Toolbox для этих дополни­
тельных элементов. Если этого не сделать, то дополнительные элементы бу­
дут размещаться на вкладке Controls панели Toolbox. Вы, конечно, могли этого
и не заметить, но Toolbox, действительно, содержит вкладку и позволяет вам
добавлять и удалять свои вкладки для размещения на них элементов управ­
ления.
Добавить вкладку на Toolbox очень просто: правым щелчком на пустом мес­
те панели Toolbox вызовите контекстное меню (рис. 9.15) и выберите команду
New Page. В результате выполнения этой команды к Toolbox будет добавлена
вкладка с именем по умолчанию (рис. 9.16).
Рис. 9.15

Для добавления вкладки к Toolbox
правым щелчком на пустом месте
этой панели вызовите контекстное
меню и выберите команду New Page

Import Page,,,

Export Page,..

Рис. 9.16

В результате выполнения команды
New Page к Toolbox будет

добавлена вкладка с именем
по умолчанию

Рис. 9.17

Rename

В этом окне можно переименовать любую вкладку
Caption:

[Сетки

Control Tip Тext f

|

Рис. 9.18

Вкладка имеет наименование Сетки

OK

|

Cancel

J

394

Глава 9. Элементы диалоговых окон

При помощи того же контекстного меню можно переименовать любую
вкладку в окне Rename (рис. 9.17). Например, на рис. 9.18 вкладка имеет на­
именование Сетки.
Для добавления элементов управления на текущую вкладку следует вы­
брать команды Tools | Additional Controls и в появившемся окне Additional Controls
(рис. 9.19) указать группу необходимых элементов управления (фактически,
DLL-файл). На рис. 9.20 вкладка Сетки панели Toolbox содержит элементы
DataGrid и MSFlexGrid, которые выбраны при помощи флажков Microsoft
DataGrig Control 6.0 и Microsoft FlexGrig Control, version 6.0, соответственно.
Рис. 9.19

В окне Additional Controls следует
указать группу необходимых
элементов управления

Рис. 9.20

Вкладка Сетки панели Toolbox
содержит элементы DataGrid
и MSFlexGrid, которые выбраны
при помощи флажков Microsoft
DataGrig Control 6.0 и Microsoft
FlexGrig Control, version6.0,
соответственно

Замечание
Наименование окна Additional Controls, вообще-то, не означает, что оно управляет
наличием на панели Toolbox только дополнительных (additional) элементов. Открой­
те окно Additional Controls для вкладки Controls и можете увидеть список всех вы­
деленных флажков для элементов управления, помещенных на эту вкладку по
умолчанию.

На рис 9.21 показана форма с элементом управления MSFlexGrigd, запол­
ненным данными из рабочего листа. Код модуля формы приведен в листинге
9.7. Код является довольно простым: сначала в строках (6-9) описываются
свойства сетки (элемента MSFlexGrigd) — количество строк и колонок, шири­
на и расположение данных первой колонки.

Использование Toolbox (панели элементов)

е» - . 9

Рис. 9.21

Форма с элементом
управления

пшсж

Главнай i Berm» ; Рйзнаткз crp

MSFIexGrigd,

395

. Дзпиие . Рец«кзирова 8ца i:Разработчик:; '■& -

я®

X ■

LkeiFoiinI

заполненным
данными из
рабочего листа

■ i I er
2 15.11.07
3 I

is.ii,07

TRUCK С71:

DESCRIPTIONS

qty

(DK) Дои.кинот.РК 3640X

PCS CTN
180

180?

(DVD) Player DV 31 lSI+дб

336

42

(DVD) Player РУ31351+Д6

512?
240j

64

(DVD) Player DV 51 lSI-i-д

470

94

(DVD) Player РУ825Х6/Д

192

64

192

192

(DVD) Player DV 51151*д500

5 j DESCRIPTIONS
(TV) LCD телевизор LT42145
■ 6 (DK) Дом.кинот.ОК 364( /№1Лки*и Гй
j 7 (DVD) Player DV 311SI+/
(DVD) Player DV 313SI+Jw"
8
240:
9 (DVD} Player DV 51151+Д500
470j
ID: (DVD) Player DV 51151+д
11) (DVD} Player DV 825X б/д
192?
? 12 i (TV) LCD телевизор LT4214S

13 ;(DL) Player DL377SI
■ 14j (ACM) Микрофон BBK DM-100

48

т

“М-ЭЧ

48
94

5[
5(

54

3?
11

192?

192

1612:
3240?

403
81

m ,:

4|

40

Л5*

14,20
14,20
13,40

§81,60 498*
1334,80 498*
857,50 499*|

27,50

5299,20 1118

12,50
5037,50 516*
15,701352,70 410*1

..... ....„
............................!xtaua.
M < » M j Wtl t Лист2 /
ГСГЮЗО

В строках 12-20 при помощи двух циклов (один из которых вложен в дру­
гой) выполняется считывание данных из листа с именем Лист1 текущей рабо­
чей книги и заполнение сетки.
Листинг 9.7. Заполнение сетки данными из рабочего листа

1: Private Sub UserForm_Initialize () 2: ' код заполнения сетки данными из рабочего листа
3:
4:
'размеры сетки:
6:
MSFlexGridl.Rows = 20'
'кол-во строк
7:
MSFlexGridl.Cols = 7
'кол-во столбцов
8:
MSFlexGridl.ColWidth(0) =2600
'ширина первого столбца
9:
MSFlexGridl.ColAlignment(0) '=Left
'выравнивание данных
10:
11:
'заполнение сетки данными:
12:
For j = 0 То MSFlexGridl.Rows - 1
13:
MSFlexGridl.Row = j
'текущая строка
14:
For I = 1 To MSFlexGridl.Cols
15:
MSFlexGridl.Col =1-1
'текущий столбец
16:
'содержимое ячейки сетки:
17:
MSFlexGridl.Text =
18:
Worksheets("Лист1") .Cells (j + 1, I) .Value
19:
Next
20:
Next
21:
22: End Sub

10

Управление
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.

Возвращение объекта Workbook
В Excel каждая книга является объектом Workbook, a Workbooks — кол­
лекцией всех открытых книг в текущем рабочем сеансе Excel. Для ссылок на
конкретную книгу следует использовать коллекцию Workbooks объекта
Application:

398

Глава 10. Управление host-приложениями УВА

Синтаксис
Workbooks(Index)
Index может быть:
□ численным выражением, представляющим книгу, которую необходимо использо­
вать (число 1 означает первую книгу, открытую в текущем рабочем сеансе, 2 —
вторую и так далее);
□ строковым выражением, представляющим имя открытой книги, которую вы хоти­
те использовать.

Более распространенный и обычно наиболее удобочитаемый способ — ис­
пользование в качестве Index текстовой строки. Листинг 10.1 содержит соот­
ветствующий пример.
Листинг 10.1. Использование коллекции Workbooks

1:
2:
3:
4:
5:
6:
7:

Sub SetWorkbookProtection()
'Установка защиты книги

Workbooks("Книга8.xlsx").Protect Structure:=True, Windows:=True
MsgBox "Защита для файла Книга8.х1зх установлена", ,
"Установка защиты книги"
End Sub

Выражение в строке 4, Workbooks("KHHra8.xlsx"), возвращает объектную
ссылку на объект Workbook с именем Книга8.х1ях. Метод Protect устанавли­
вает защиту книги. Оператор MsgBox (в строках 5-6) выводит сообщение, ин­
формирующее о том, что для данной книги была установлена защита (рис.
10.1). (Предполагается, что книга с именем KmiraS.xlsx в данный момент от­
крыта. Если это — не так, то вы получите сообщение о runtime-ошибке.)
Рис. 10.1

Сообщение о результате выполнения
кода листинга 10.1

Как открыть книгу
Если необходимая вам книга еще не открыта, воспользуйтесь методом Open
для загрузки ее в память:

Синтаксис
Workbooks.Open(Filename)
Аргумент Filename — текстовая строка, представляющая полный путь к книге: диск,
папка и имя файла. Если вы не зададите имя диска или папку, Excel будет искать
файл на текущем диске и в той папке, которая открыта в данный момент.

Работа с Excel

399

Пример использования метода Open представлен в листинге 10.2.
Листинг 10.2. Применение метода Open для открытия книги

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

Sub OpenWorkbook()
'Предлагает открыть и затем открывает ее

Dim Workbookname As String

Workbookname =
InputBox("Введите полный путь к книге:")
If Workbookname о "" Then
Workbooks.Open FileName:=Workbookname
End If
End Sub

В этой процедуре переменная 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, xlWBATExcel4MacroSheet или xlWBATExce!4IntlMacroSheet.
Листинг 10.3 демонстрирует пример процедуры, создающей новую книгу.

400

Глава 10. Управление host-приложениями УВА

Листинг 10.3. Использование метода Add для создания новой книги

1: Sub CreateMonthlyReport ()
2: 'Создание новой книги на основе файла-шаблона
3:
4:
Dim FilePath As String, FileName As String
5:
6:
FilePath = "H:ХПрограммирование на VBA 2007\VBA_BookVentura\3"
7:
8:
FileName = FilePath & "\Книга8.xlsm"
9:
Workbooks.Add Template:=FileName
10:
With ActiveWorkbook
11:
.Title = "Отчет компании"
12:
.Subject = "Отчет за ДЕКАБРЬ 2003"
13:
.Author = "Иван Петров"
14:
End With
15: End Sub

Код листинга 10.3 создает новую книгу (строка 9) на базе шаблона
Bookl5Template.xls — обычный Excel-файл, который был предварительно
создан и обработан. Любая новая книга автоматически становится активной
книгой. В строках с 10 по 14 для добавления в файл новой книги некоторой об­
щей информации — Title, Subject и Author — используется объект
ActiveWorkbook. Для просмотра результатов работы кода строк 9-13 исполь­
зуйте или вплывающую Explorer-подсказку (см. рис. 10.2), или вкладку
Summary диалогового окна Properties для данного файла.
Рис. 10.2

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

Книгам

Тип: Лист Microsoft Office Excel с поддержкой макросов
Автор: Иван Петров
Заголовок: Отчет компании
Тема: Отчет за ноябрь 2007
Размер: 23,4 КБ
Изменен: 24.11.2007 15:45

Как сделать книгу активной

Если ваша VBA-программа работает с несколькими одновременно открыты­
ми книгами, вам может понадобиться переключаться из одной книги в другую
для вывода на экран, например, отчета или введенных данных.
Чтобы сделать открытый документ активным, используйте метод Activate:

Синтаксис
Object.Activate
В данном случае Object представляет любую допустимую объектную ссылку на лист,
который необходимо сделать активным.

В листинге 10.4 — пример процедуры, использующей метод Activate.

Работа с Excel

401

Листинг 10.4. Использование метода Activate для переключения к книге

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:

Sub ActivateTest()
'Изменение активной книги без вывода на экран
Dim SaveBook As String
SaveBook = ActiveWorkbook.Name
Application.Screenupdating = False
Workbooks("Балансовый отчет 1207.XLSX").Activate

' код, выполняющий
' . . .

заполнение файла Балансовый отчет 1202.XLS

Workbooks(SaveBook).Activate
Application.Screenupdating = True
End Sub

Эта простая процедура демонстрирует два принципа хорошего программи­
рования. Во-первых, по возможности следует скрывать от пользователя проме­
жуточные операции, выполняемые вашей программой. Например, если проце­
дура содержит операторы, форматирующие диапазоны ячеек и введенные дан­
ные, выполняйте данные действия «за кулисами». Выводите для пользователя
на экран лишь конечный результат. Сделать это можно, присваивая свойству
Screenupdating объекта Application значение False.
Во-вторых, если вы устанавливаете книгу активной, потому что это требует­
ся вашей программе, а не для того, чтобы пользователь мог увидеть другой
файл, ваша процедура должна по завершении «возвращать» пользователя в то
же самое место, где он находился при ее старте. Особенно это относится к мало­
опытным пользователям, которые приходят в замешательство, обнаружив, что
по выполнении процедуры они оказываются совсем в другой книге, не имея,
при этом, никаких разумных предположений для объяснения этого факта.
Назначение представленной в листинге 10.4 процедуры — переключиться
из текущей книги в другую книгу (Балансовый отчет 1202.XLS), произвести
в ней программным образом некоторые изменения, а затем вернуться к перво­
начальной книге. Сначала (в строке 6) имя текущей активной книги сохраня­
ется в строковой переменной SaveBook. Далее, чтобы избавить пользователя
от наблюдения за деталями выполнения процедуры, в строке 8 свойству
Screenupdating присваивается значение False. В строке 9 книга Балансо­
вый отчет 1202.XLS устанавливается активной. Строки, следующие далее,
должны выполнять действия в книге Балансовый отчет 1202.XLS. Реальная
программа, которая вносит изменения в Балансовый отчет 1202.XLS, в дан­
ном примере опущена. Для того чтобы «вернуть» пользователя в то же место,
в котором он находился перед запуском процедуры, в строке 14 активной ста­
новится первоначальная книга. В строке 15 свойству Screenupdating при­
сваивается значение True.

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

402

Глава 10. Управление host-приложениями УВА

ку Сохранить на панель инструментов программы, если программа имеет
меню или панели инструментов.
Возможны случаи, когда у вас возникнет потребность сохранить книгу под
управлением процедуры. Например, вы захотите создать собственную версию
команды Файл | Сохранить. Более того, вы, возможно, попытаетесь предостеречь
начинающего пользователя от выполнения неудачной последовательности ко­
манд, таких как закрытие книги, выход из программы или из Excel без сохра­
нения результатов работы.
Для сохранения книги следует пользоваться методом Save:

Синтаксис
Object.Save
В данном случае, Object — это объектная ссылка на открытый объект Workbook, кбторый следует сохранить.

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

Синтаксис
Object.SaveCopyAs(Filename)
Object — это объектная ссылка на объект Workbook, который будет сохранен,
a Filename — строковое выражение для имени, которое следует использовать при
сохранении копии книги.

В листинге 10.5 приведен код, использующий методы Save и SaveCopyAs.
Листинг 10.5. Использование методов Save и SaveCopyAs

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Sub BackUpToZIP()
'Сохраняет активную книгу и делает ее копию на ZIP-диске Н:

Const SaveDrv - "Н:"

With ActiveWorkbook
If Not .Saved Then .Save
.SaveCopyAs Filename:=SaveDrv & "\Copy of " & .Name
End With
End Sub

Эта процедура сохраняет активную книгу и создает резервную копию на ло­
гическом диске Н (рис.10.3). Процедура начинается с объявления единствен­
ной константы с именем диска. Оператор With выполняет несколько команд
для объекта ActiveWorkbook.

Работа с Excel

403

Рис. 10.3

Копия активной книги на диске
Н — дополнительная гарантия
сохранения результатов вашей
работы

Тест If. . . Then (строка 7) проверяет свойство Saved книги. Если оно равно
False, в книге имеются изменения, которые еще не были сохранены, поэтому
процедура вызывает метод Save.
Имя резервной копии файла создается конкатенацией значения константы
SaveDrv, литеральной константы "\Copy of "и свойства 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-ти символов), которая используется
в качестве пароля при открытии файла.
ReadOnlyRecommended (тип Variant) — аргумент, который при значении, равном
True, приводит.к появлению диалогового окна с рекомендацией открывать файл
только на чтение.
CreateBackup (тип Variant) — аргумент, который при значении, равном True, приво­
дит к созданию резервной копии сохраняемой книги.
AccessMode — значение одной из следующих констант:
□ xlExclusive (монопольный доступ);

Глава 10. Управление host-приложениями УВА

404

□ xINoChange (не менять режим доступа, действует по умолчанию);
□ xIShared (многопользовательский доступ).

При использовании константы xIExclusive файл может быть открыт для записи толь­
ко одним пользователем. Другой пользователь получит в диалоговом окне сообще­
ние о том, что файл уже открыт. С другой стороны, константа xIShared дает
возможность сразу нескольким пользователям работать с одним файлом.
При одновременной работе нескольких пользователей с одним файлом в любой мо­
мент времени любой пользователь может сохранять свои изменения в файле. При
этом, если какой-либо другой пользователь уже сохранял данные на диске, эти дан­
ные попадают в файл того, кто делает в данный момент сохранение своих данных.
Однако при такой совместной работе с одним файлом не всегда можно просто со­
хранить свои данные в файле на диске. Если вы, например, пытаетесь одновременно
с другим пользователем изменить содержимое одной и той же ячейки, можете полу­
чить сообщение о конфликте доступа.
ConflictResolution — одна из следующих констант:
□ xlUserResolution (отображать диалоговое окно разрешения конфликтов);
□ xILocalSessionChanges (автоматически принимать пользовательские изменения);
□ xIOtherSessionChanges (принимать другие изменения вместо локальных поль­

зовательских).
AddToMru (тип Variant) — аргумент, который (при равенстве значению True) указы­
вает на то, что файл добавляется в список недавно используемых файлов. По умол­
чанию этот аргумент имеет значение False.
Метод SaveAs имеет и другие параметры, о которых вы можете узнать из
справочной системы.

Как закрыть книгу
После завершения работы с книгой, следует ее закрыть, чтобы освободить
память и избежать «засорения» экрана. Закрыть книгу можно, воспользовав­
шись одной из форм метода Close:

Синтаксис
Workbooks.Close
Object.Close(SaveChanges)
При использовании первой синтаксической формы можно просто закрыть все от­
крытые книги. Excel предлагает сохранить изменения в книгах перед тем, как их за­
крыть, если это необходимо. Вторая синтаксическая форма позволяет закрыть
конкретную книгу, на которую указывает Object. Аргумент SaveChanges использует­
ся следующим образом:
□ Если SaveChanges равен True, Excel сохраняет книгу автоматически, перед тем
как ее закрыть.
□ Если SaveChanges равен False, Excel закрывает книгу без сохранения изменений.
□ Если вы опустите аргумент SaveChanges, Excel предложит (в случае необходимо­
сти) выполнить сохранение.

Листинг 10.6 демонстрирует использование метода Close.

Работа с Excel

405

Листинг 10.6. Использование метода Close

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:

Sub CloseAll()
'Закрывает все открытые книги и предлагает сохранить сделанные
'в них изменения
Const qButtons = vbYesNo + vbQuestion

Dim Book As Workbook
Dim Ans As Integer
Dim MsgPrompt As String

For Each Book In Workbooks
If Not (Book.Name = ThisWorkbook.Name) Then
If Not Book.Saved Then
MsgPrompt = "Сохранить изменения в " & Book.Name & "?"
Ans = MsgBox(prompt:=MsgPrompt, Buttons:=qButtons)
If Ans = vbYes Then
Book.Close SaveChanges:=True
Else
Book.Close SaveChanges:=False
End If
Else
Book.Close
End If
End If
Next Book
End Sub

Данная процедура закрывает все открытые книги (за исключением книги,
содержащей процедуру) и предлагает пользователю сохранить изменения для
каждой книги, имеющей несохраненные изменения. Используйте процедуру,
подобную этой, вместо метода Workbooks. Close, когда вам необходимо, что­
бы пользователь не отменял операцию сохранения. Встроенная в Excel коман­
да Сохранить имеет кнопку Отмена. После объявления константы и нескольких
переменных (строки с 4 по 8) процедура начинает цикл For Each для обработ­
ки всех книг в коллекции Workbooks.
Поскольку закрытие книги, содержащей выполняемую в данный момент
процедуру, приведет к ее остановке, строка 11 содержит оператор If...Then,
который проверяет, не имеет ли книга, обрабатываемая в данный момент, то
же самое имя, что и книга, содержащая процедуру CloseAll. Если — да, то
часть кода, выполняющая закрытие книги пропускается; строки с 12 по 22
выполняются только в том случае, если книга не содержит процедуры
CloseAll. (Свойство ThisWorkbook возвращает ссылку на книгу, содержащую
выполняемый в данный момент код.)
Если книга содержит изменения, которые не были сохранены (строка 12),
функция MsgBox (строка 13) запрашивает пользователя, необходимо ли сохра­
нять изменения. Если пользователь выбирает Yes (то есть переменная Ans по­
лучит значение vbYes), процедура запускает метод Close с аргументом
SaveChanges, равным значению True (строка 16). В противном случае проце­
дура закрывает книгу с SaveChanges, равным значению False (строка 18).
Если в книге отсутствуют несохраненные изменения, процедура запустит ме­
тод Close без аргументов (строка 21).

Глава 10. Управление host-приложениями УВА

406

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

Возвращение значения объекта Worksheet
Каждый лист является объектом Worksheet, а все листы данной книги об­
разуют коллекцию Worksheets. Для ссылок на заданный лист используйте
коллекцию Worksheets объекта Workbook:

Синтаксис
Object.Worksheets(Index)
Object представляет ссылку на объект Workbook, содержащий лист. Index может
быть:
□ Числом, представляющим лист, который следует использовать. Число 1 означает
первый лист в книге, 2 — второй лист и так далее.
□ Имя листа, который следует использовать, в виде строки. Это имя, которое появ­
ляется на вкладке листа.

Листинг 10.7 представляет пример наиболее частого способа использования
метода Worksheets — когда лист идентифицируется строкой текста.
Листинг 10.7. Использование коллекции Worksheets

1:
2:
3:
4:
5:
6:
7:

Sub SetWorksheetProtection()
'Активизирует защиту листа

Workbooks("Балансовый отчет 1207.xlsx").Worksheets("Расходы").Protect _
Contents:=True, Scenarios:=True
MsgBox "Защита листа 'Расхода' активизирована."
End Sub

Объект Workbooks( "Балансовый отчет 1207.XLSX").Worksheets("Pacxoды") возвращает ссылку на лист с именем Расходы в книге Балансовый отчет
12O7.xlsx. Метод Protect задает защиту для содержимого и сценария. Процеду­
ра MsgBox информирует пользователя о том, что защита листа активизирована.
Для работы рассматриваемой программы необходимо, чтобы в коллекции
Workbook имелась та книга, на которую выполняется ссылка -= Балансовый
отчет 12O2.xlsx. Если это — не так, VBA выдаст сообщение об runtime-ошиб­
ке 9 «Subscript out of range», которое вряд ли поможет вам сразу понять при­
чину ошибки.
Хорошим правилом при программировании является проверка наличия
объекта в коллекции перед попыткой его использования. В следующем лис­
тинге защита листа книги Балансовый отчет 12O2.xlsx выполняется в том
случае, если эта книга находится в коллекции Workbooks. Наличие самого
листа в книге не проверяется, хотя можно было бы проверить и это.

Работа с Excel

407

Листинг 10.8. Использование коллекции Worksheets

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14 :
15:
16:
17:
18:
19:

Sub SetWorksheetProtection()
' Активизирует защиту листа с проверкой
' наличия книги в коллекции Workbooks
Dim ProtYes As Boolean
ProtYes = False
For Each Book In Workbooks
If (Book.Name = "Балансовый отчет 1207.xlsx") Then
Book.Worksheets("Расходы").Protect
Contents:=True, Scenarios:=True
MsgBox "Защита листа 'Расходы' активизирована "
ProtYes = True
Exit For
End If
Next Book

f
If Not ProtYes Then MsgBox "Книга не найдена!"

End Sub

В строках 4 и 5 объявляется и инициализируется переменная ProtYes, ко­
торая используется в качестве индикатора наличия необходимой книги в кол­
лекции Workbooks. В цикле For Each (строки 7-15) для каждой книги прове­
ряется свойство Name. При совпадении этого свойства со строкой "Балансо­
вый отчет 12O2.xlsx" выполняется защита листа Расходы (строка 9),
переменной ProtYes присваивается значение True (книга найдена), происхо­
дит выход из цикла при помощи оператора Exit For. В строке 17 выдается со­
общение об отсутствии необходимой книги в коллекции Workbooks, если пере­
менная ProtYes содержит значение False.
Если вам необходимо сослаться на активный лист, используйте свойство
книги ActiveSheet. Если вам нужно сослаться на все страницы книги (или
вы не уверены, какой тип листа необходимо выбрать), используйте вместо кол­
лекции Worksheets коллекцию Sheets. Коллекция Sheets содержит не толь­
ко листы, но и диаграммы.

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

Синтаксис
Object.Activate

Object представляет ссылку на объект Worksheet, который следует сделать активным.

Листинг 10.9 содержит пример использования метода Activate.

408

Глава 10. Управление host-приложениями УВА

Листинг 10.9. Использование метода Activate для перехода на заданный лист

1:
Sub DisplaySheet()
2:
' Устанавливает активным лист "Расходы"
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("Балансовый отчет 1203.xlsx").Worksheets("Расходы").Activate
12:
End If
13: End Sub

В данной процедуре пользователю задается вопрос, хочет ли он просмотреть
определенный лист, в данном случае — Расходы (строки 7-9 программы).
Если пользователь выбирает кнопку Yes, то лист с именем Расходы становится
активным (строка 11).
Для выбора листа используйте метод Select:
Object.Select
Данный метод полезен для создания трехмерных ссылок и определения
листов, которые следует вывести на печать. Трехмерная ссылка (threedimensional reference) — это ссылка на диапазон ячеек более чем одного листа.
Не следует без необходимости делать лист активным. Для большинства
свойств и методов объекта Worksheet вы можете просто воспользоваться мето­
дом Worksheets для ссылок на лист, который нужно использовать. Напри­
мер, следующий оператор возвращает стандартную ширину листа График ба­
ланса, не делая этот лист активным:
StdWidth = Worksheets("График баланса").Standardwidth

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

Синтаксис
Object.Worksheets.Add([Before]

[, Count]

[, Type])

Object представляет ссылку на объект Workbook, в который добавляется новый
лист. Аргумент Before задает лист, перед которым добавляется новый лист, а аргу­
мент After — лист, после которого добавится новый лист. (Нельзя использовать аргу­
менты Before и After одновременно в одном и том же операторе.) Если опустить оба
аргумента: как Before, так и After, VBA добавит новый лист перед активным листом.
Count — количество вновь добавляемых листов. (Если опустить Count, метод Add
добавит один лист.) Туре — тип добавляемого листа. Существуют следующие воз­
можные варианты аргумента Туре (определенные в классе XISheetType):
xlWorksheet (устанавливается по умолчанию), xlChart, xlExce!4MacroSheet или
xlExce!4lntlMacroSheet.

409

Работа с Excel

Как переименовать лист
Имя листа — это текст, который появляется на ярлычке листа. В случае не­
обходимости переименовать лист следует изменить свойство Name листа:

Синтаксис
Object.Name
Object — это лист, который будет переименован.

Копирование и перемещение листа
Если вам необходимо расположить листы книги в определенном порядке,
используйте методы Сору и Move. Оба метода имеют одинаковый синтаксис:

Синтаксис
Object.Сору([Before]
Object .Move ( [Before]

[, After])
[', After])

Object — объектная ссылка на лист, который необходимо скопировать или перемес­
тить. Before задает лист перед которым, a After — лист после которого будет поме­
щен копируемый или перемещаемый лист. (Нельзя использовать аргументы Before
и After одновременно в одном операторе.) Если опустить как Before, так и After, VBA
создаст для копируемого или перемещаемого листа новую книгу.

Листинг 10.10 содержит процедуру, использующую метод Move.
Листинг 10.10. Использование метода Move для перемещения листа

1:
2:
3:
4:
5:
б:
7:
8:
9:
10:
11:
12:
13:
14:

Sub CreateWorksheet()
'Создание нового листа и перемещение
'его в конец книги

Dim NewSheet As String

Worksheets.Add before:=Worksheets(Worksheets.Count)
NewSheet = ActiveSheet.Name
With Worksheets(NewSheet)
.Move after:=Worksheets(Worksheets.Count)
.Activate
End With
End Sub

С помощью метода Add в книгу добавляется лист (строка 7). В данном слу­
чае метод Add вызывается с необязательным аргументом Before для того, что­
бы добавить новый лист непосредственно перед последним листом книги. Но­
мер последнего листа книги определяется в строке 7 с помощью свойства
Count, которое возвращает количество листов в книге. После чего новое назва­
ние листа сохраняется в переменной NewSheet.

410

Глава 10. Управление host-приложениями УВА

В строке 10 с помощью метода Move, новый лист помещается за последним
листом книги. (Для того чтобы получить количество листов в книге, вновь ис­
пользуется свойство Count.) После этого новый лист устанавливается актив­
ным (строка 11).
Если вы разрабатываете приложение, в котором часто приходится созда­
вать и перемещать листы, будет неплохой практикой устанавливать перед эти­
ми операциями команды отключения обновления экрана (Application. ScreenUpdating = False). При этом следует не забывать включать обновление экра­
на, если ваша процедура его отключала (Application.ScreenUpdating = True).
Помните, что вы можете добавить лист и после любого заданного листа.
Процедура в листинге 10.10 добавляет лист перед последним листом и затем
перемещает его, поскольку Excel не позволяет добавлять листы в конец кни­
ги. Использование аргумента After, совместно с методом Add позволяет доба­
вить новый лист после любого существующего листа, за исключением по­
следнего.
Как удалить лист
В целях поддержания управляемости книгами и экономии места на диске
ненужные листы следует удалять. Это особенно актуально в случаях, когда
созданные вами приложения используют для хранения промежуточных ре­
зультатов временные листы. Для удаления листа используйте метод Delete:

Синтаксис
Object.Delete
Object — ссылка на лист, который следует удалить.
Листинг 10.11 демонстрирует пример использования метода Delete.
Листинг 10.11. Использование метода Delete для удаления листа

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:

Sub DeleteTemporarySheets()
'Удаление всех временных листов
Dim Sheet As Worksheet

Application.DisplayAlerts = False
For Each Sheet In Workbooks("Балансовый отчет 1207.xlsx").Worksheets
If InStr(1, Sheet.Name, "Временный") Then
Sheet.Delete
End If
Next Sheet

Application.DisplayAlerts = True
End Sub

Эта процедура проверяет каждый лист книги и удаляет все ранее созданные
временные листы. Процедура «полагает», что временные листы должны назы­
ваться Временный!, Временный2 и так далее.

Работа с Excel

411

Процедура объявляет объектную переменную Sheet (типа Worksheet) и за­
дает свойство DisplayAlerts объекта Application, равным значению False
(строка 6). Таким образом подавляется обычное диалоговое Excel-окно под­
тверждения, которое появляется всякий раз, когда вы пытаетесь удалить
лист. В строке 8 начинается цикл For Each, перебирающий все листы книги
Балансовый отчет 12O2.xlsx. Функция InStr проверяет каждый лист на на­
личие в названии листа строки «Временный». Если такая строка обнаружива­
ется, то (в строке 10 кода) этот лист удаляется. Когда данный процесс заверша­
ется, свойство DisplayAlerts вновь получает значение True (строка 14).
Процедура в листинге 10.11 будет работать правильно, если Option
Compare Text является текущей глобальной установкой сравнения.

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

Использование Range метода
Наиболее легкий и прямой способ задать ячейку или диапазон ячеек состо­
ит в использовании метода Range:

Синтаксис
Object.Range(Warne)
Object — ссылка на объект Worksheet, который содержит диапазон ячеек. Если
вы опустите Object, VBA будет «считать», что метод применяется к объекту
ActiveSheet. Аргумент Name — ссылка на диапазон ячеек или имя диапазона,
введенное как текст. Метод Range работает также с именованными диапазонами
ячеек.

Код листинга 10.12 демонстрирует пример использования метода Range.
Листинг 10.12. Использование метода Range

1:
2:
3:
4:
5:
6:
7:

Sub FormatRangeFont()
'С помощью метода Range задается шрифт для диапазона ячеек
»
With' Worksheets("Лист1")
.Range("Al:L1").Font.Size = 24
.Range("Al:LI").Font.Bold = True
.Range("Al:L1").Font.Name = "Times New Roman"

Глава 10. Управление host-приложениями УВА

412

8:
9:

End With

End Sub

В этом примере все три оператора (строки с 5 по 7) возвращают диапазон
ячеек А1:Ы листа Лист1. (Обратите внимание на то, что диапазон ячеек сле­
дует заключать в кавычки.)
Процедура листинга 10.12 устанавливает некоторые атрибуты шрифта для
заданного диапазона ячеек. Font — свойство объекта Range. Font возвращает
ссылку на объект Font, связанный с заданным диапазоном значений. Свойства
объекта Font — те же самые, что и атрибуты шрифта, которые можно задать
при помощи диалогового окна Шрифт: полужирный, курсив, подчеркнутый
и другие. Ниже в качестве примера представлено несколько1 свойств объекта
Font (во всех случаях Object — объект типа Range):
□ Object.Font.Bold: Устанавливает (или отменяет) полужирный стиль
шрифта (True или False).
□ Object. Font. Italic: Устанавливает (или отменяет) курсив (True или
False).
□ Object.Font.Underline: Устанавливает эффект подчеркивания вклю­
ченным или выключенным. Значение свойства Underline может быть
равно одной из встроенных констант, определенных в классе XlUnderlineStyle: xlUnderlineStyleNone, xlUnderlineStyleSingle, xlUnderlineStyleDouble, xlUnderlineStyleSingleAccounting или xlUnderlineStyleDoubleAccounting.
□ Object.Font.Name: Устанавливает наименование шрифта. Значение
свойства Name определяется, например, в виде строки "Arial".
□ Object.Font.Size: Устанавливает размер шрифта (в пунктах).
В Excel имеется альтернативная синтаксическая конструкция для метода
Range, применение которой требует двух аргументов:

Синтаксис
Object.Range(Celli, Се112)
Как обычно, Object — является объектом типа Worksheet, содержащим диапазон
значений ячеек. Аргумент Celli определяет верхний левый угол диапазона, а Се112 —
правый нижний угол. Каждый аргумент может быть текстовым адресом ячейки, объ­
ектом Range, состоящим из одной ячейки, или же целым столбцом или строкой.

Преимущество использования данной синтаксической конструкции заклю­
чается в разделении угловых значений в различных аргументах, что позволяет
независимо изменять значение для каждого из «углов» под управлением про­
цедуры. Например, вы можете задавать имена переменных, таких как
UpperLeft и LowerRight, и возвращать объекты Range различных размеров
в виде
Range(UpperLeft, LowerRight)

1 Для того чтобы просмотреть полный список свойств Font, используйте инструмент
Object Browser.

Работа с Excel

413

Не следует использовать в методе Range координаты диапазонов, если дос­
тупны их имена. Имена диапазонов облегчают восприятие и отладку програм­
мы.

Использо йание метода Cells
Хотя для того чтобы выполнить ссылку на одну ячейку, можно воспользо­
ваться методом Range, такую же возможность дает и метод Cells, который
является более гибким:

Синтаксис
Object.Cells(Rowindex, Columnlndex)
Object— ссылка или на Worksheet, или на объект Range, содержащий ячейку, с кото­
рой необходимо работать. Если Object опущен, метод применяется к объекту
ActiveSheet.

Rowindex — номер строки, в которой находится ячейка. Если Object — лист, то
Rowindex, равный 1, ссылается на строку 1 листа. Если Object — диапазон значений,
то Rowindex, равный 1, ссылается на первую строку диапазона.
Columnindex — номер столбца, в котором расположена ячейка. Вы можете ввести или
букву (как буквенную константу или как строковую переменную), или число, задающее
столбец. Если Object — лист, то Columnindex, равный "А" или 1, ссылается на столбец
А листа. Если Object — диапазон значений, то Columnindex, равный "А" или 1, ссыла­
ется на первый столбец диапазона.

В листинге 10.13 приведен пример использования метода Cells.
Листинг 10.13. Использование метода Cells

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:

Sub CmdWrite_Click()
'Ввод данных из диалогового окна формы пользователя в лист

Dim I As Integer
Dim DBNewRow As Integer
Dim NewRange As String

With Range("База_данных")
'находится новая строка данных
DBNewRow = .Row + .Rows.Count

'ввод данных из диалогового окна в ячейки новой строки
For I = 1 То .Columns.Count
Cells(DBNewRow, (I + .Column) - 1).Value = _
UserForml.Controls("TextBox" & CStr(I)).Text
Next I
'расширение диапазона базы данных
NewRange = "=" & .Parent.Name & "1"
NewRange = NewRange & Cells(.Row, .Column).Address & ":"
NewRange = NewRange &
Cells(DBNewRow, (.Column + .Columns.Count) - 1).Address
Names("База_данных").RefersTo = NewRange
End With
End Sub

414

Глава 10. Управление host-приложениями VBA

Эта процедура — часть приложения поддержки базы данных. Пользователь
вводит в «базу данных» информацию при помощи диалогового окна (подобно­
го тому, что показано на рис. 10.4). Процедура CmdWrite_Click вызывается
при нажатии кнопки Запись диалогового окна. Процедура CmdWrite_Click
записывает новые данные в лист в конец диапазона ячеек базы данных и уве­
личивает диапазон ячеек базы данных для включения новой строки.
Рис. 10.4

Диалоговое окно (в режиме разработки)
для ввода данных

Описание элементов управления, на которые ссылается код процедуры лис­
тинга 10.13, приведено в следующей таблице:
Примечание

Тип элемента

Свойство Значение

UserForm

Name

UserForm 1

Имя формы, на которое можно
ссылаться в коде.

Caption

Запись данных

Заголовок окна (формы) в верхней
части.

Name

CmdWrite

Имя кнопки, на которое можно
ссылаться в коде.

Caption

Запись

Текст на кнопке.

Default

True

При нажатии на клавишу Enter
инициируется событие Click кнопки.

Name

CmdExit

Имя кнопки, на которое можно
ссылаться в коде.

Caption

Выход

Текст на кнопке.

Cancel

True

При нажатии на клавишу Esc
инициируется событие Click кнопки.

Name

Label 1

Имя метки, на которое можно
ссылаться в коде.

Caption

Фамилия

Текст на метке.

Name

Label2

Имя метки, на которое можно
ссылаться в коде.

Caption

Имя

Текст на метке.

Name

Label3

Имя метки, на которое можно
ссылаться в коде.

Caption

Отчество

Текст на метке.

CommandButton

CommandButton

Label

Label

; Label

Работа с Excel

415

Примечание

Тип элемента

Свойство Значение

TextBox

Name

TextBoxI

Имя поля, на которое можно
ссылаться в коде.

TextBox

Name

TextBox2

Имя поля, на которое можно
ссылаться в коде.

TextBox

Name

TextBox3

Имя поля, на которое можно
ссылаться в коде.

_ ।

Пример работающего окна для ввода данных при помощи кода листин­
га 10.13 приведен на рис. 10.5.
Рис. 10.5

Процедура CmdWrite_Click листинга 10.13
работает с данными, вводимыми
с использованием диалогового окна,
подобного этому

В строках с 4 по 6 объявляются переменные, используемые в процедуре.
Строка 8 начинается оператором With, задающим диапазон ячеек, на которые
ссылается имя База_данных. В строке 10 переменной DBNewRow присваива­
ется значение, соответствующее строке, расположенной сразу же за диапазо­
ном ячеек базы данных — это строка, в которой должны быть сохранены но­
вые данные.
Цикл For. . .Next (в строках с 13 по 16) записывает значения из диалогового
окна формы пользователя в лист. Счетчик цикла (I) «пробегает» значения от 1
до числа столбцов диапазона ячеек, полученного при нахождении свойства
Count коллекции Columns для объекта Range. (Коллекция Columns содержит
все столбцы объекта Range, а его свойство Count возвращает число столбцов.)
Внутри цикла метод Cells (строка 14) возвращает каждую ячейку в новой
строке и свойство Value ячейки устанавливается в значение, равное соответст­
вующему тексту в элементе управления окна редактирования. Предполагает­
ся, что каждый элемент управления окна редактирования в форме пользовате­
ля имеет имя (по умолчанию) TextBoxJV, где N — номер текстового окна в по­
следовательности помещения его на форму и соответствующего столбца
в диапазоне ячеек базы данных. Таким образом, в строке 15 собирается имя
элемента управления окна редактирования, из которого будет преобразовано
значение данных посредством конкатенации строки, эквивалентной перемен­
ной текущего счетчика цикла, с буквенной константой "TextBox". (Вместо не­
скольких имен текстовых окон можно использовать один массив таких окон
с одним именем и разными индексами.)
Чтобы включить новую строку в «базу данных», необходимо изменить диа­
пазон ячеек «базы данных». Переопределить диапазон, на который ссылается
конкретное имя, можно, изменив свойство RefersTo этого имени. (Именован­
ные диапазоны ячеек листа, являются объектами типа Name и доступны по­
средством коллекции Names листа.) Свойство RefersTo должно содержать

416

Глава 10. Управление host-приложениями УВА

строку вида "=sheet\reference", где 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, который смещен относительно заданного диапазона ячеек на заданное
количество строк и столбцов.
Синтаксис

Object.Offset([RowOffset]

[,Columnoffset])

Object является ссылкой на исходный объект Range. RowOffset — число строк, на ко­
торое смещается Object. Вы можете использовать положительное число (для сме­
щения вниз), отрицательное число (для смещения вверх) или 0 (для использования
той же строки). Если вы опустите RowOffset, будет использовано значение по умол­
чанию — 0.

Листинг 10.14 демонстрирует процедуру, использующую метод Offset.
Листинг 10.14. Использование метода Offset для ссылки на диапазон ячеек

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:

Sub SelectDataO
'Выделяется область данных диапазона базы данных

Dim DBRows As Integer
Worksheets("Sheetl").Select
With Range("База_данных")
DBRows = .Rows.Count
.Offset(l, 0).Resize(DBRows - 1,
End With
End Sub

.Columns.Count).Select

417

Работа с Excel

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

данные (без заголовков столбцов), опуская для этого из текущего выбора пер­
вую строку именованного диапазона. Выполнение данной процедуры полезно,
если необходимо выполнить над данными в таблице глобальные операции, та­
кие как сортировка или форматирование.
В строке 6 выбирается лист с именем Sheetl, а оператор With в строке 7 за­
дает для этого листа объект Range с именем База_данных. В строке 8 с помо­
щью свойства Rows . Count объект Range получает число строк диапазона яче­
ек, которое сохраняется в переменной DBRows.
В строке 9 метод Offset (с аргументами 1 и 0) возвращает диапазон, кото­
рый является смещением диапазона База_цанных на одну строку вниз. По­
скольку этот диапазон включает (предположительно) пустую строку, находя­
щуюся за диапазоном База_данных, вы должны эту дополнительную строку
удалить. Чтобы выполнить данную операцию, можете воспользоваться свойст­
вом Resize, изменяющим размер диапазона:

Синтаксис
Object.Resize([RowSize]

[,ColumnSize])

Object — объектная ссылка на диапазон, размер которого изменяется. RowSize —
число строк в возвращаемом диапазоне. ColumnSize — число столбцов в возвра­
щаемом диапазоне.

В строке 9 при помощи выражения Resize(DBRows—1, .Columns.Count)
удаляется ненужная нижняя строка смещенного диапазона.
Метод Select (в строке 9) выделяет новый диапазон ячеек.

Другие методы и свойства, возвращающие диапазоны ячеек
Методы Range, Cells и Offset являются наиболее часто используемыми
методами для возвращения объектов Range, но они далеко не единственные.
На примере кода листинга 10.14 вы познакомились с тем, как с помощью ме­
тода Resize можно возвратить диапазон заданного размера. Вот лишь некото­
рые методы и свойства, возвращающие объекты типа Range:
□ [cellRef]. Вы можете возвратить одну ячейку, поместив ссылку на нее
в квадратные скобки. Например, [Al].Font.Size=16 устанавливает раз­
мер шрифта ячейки А1 в значение 16. Обратите внимание на то, что
в данном случае для ссылки на ячейку не используется никаких кавы­
чек.
□ Object.Rows (Index). Данный метод возвращает строку листа или диа­
пазона ячеек, заданных при помощи Object. Если вы опустите Object,
VBA использует ActiveSheet. Index — номер строки. Если Object явля­
ется листом, Index, равный 1, ссылается на строку 1 листа. Если же
Object является диапазоном, то Index, равный 1, ссылается на первую
строку диапазона.
□ Object .EntireRow. Данное свойство возвращает целую строку или стро­
ки, содержащие диапазон ячеек, заданных при помощи Object.
14 VBA. Эффективное использование

418

Глава 10. Управление host-приложениями УВА

□ Object.Columns (Index). Данный метод возвращает столбец листа или
диапазона ячеек, заданных при помощи Object. Если вы опускаете Object,
VBA использует Active Sheet. 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, который выделяется.

Листинг 10.15 демонстрирует пример использования данного метода.
Листинг 10.15. Использование метода Select для выделения диапазона

ячеек

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Sub CreateChart()
'Создается диаграмма на основе данных диапазона Продажа

With Workbooks("Отчеты.xlsx").Worksheets("Лист2")
.Activate
.Range("Продажа").Select
End With
Charts.Add
End Sub

Данная процедура создает из выбранного диапазона ячеек новую диаграмму.
строке 5 активизируется лист Workbooks("OT4eTbi.XLS ").Worksheе1в(Лист2). В строке 6 на листе выделяется диапазон ячеек с именем Продажа.
В строке 9 для создания диаграммы выполняется метод Add объекта Charts.

В

Работа с Excel

419

Свойства Value и Formula
Если вам необходимо получить содержимое ячейки или ввести данные
в диапазон ячеек, VBA предлагает два свойства объекта Range: Value
и Formula. Синтаксис для использования этих свойств следующий:

Синтаксис
Object.Value
Object.Formula
Object — объектная ссылка на объект типа Range, с которым необходимо работать.
Для того чтобы получить содержимое ячейки, руководствуйтесь следующими прави­
лами:
□ Если вам необходимо значение, содержащееся в ячейке, используйте свойство
Value. Например, если ячейка А1 содержит формулу =2*2, то выражение Range("A1").Value возвращает значение 4.
□ Если вам необходима формула, содержащаяся в ячейке, используйте свойство
Formula. Например, если ячейка А1 содержит формулу =2*2, то выражение
Range("A1”).Formula возвращает текстовую строку ”=2*2".

Для того чтобы ввести данные в ячейку или диапазон ячеек, вы можете
применять как Value, так и Formula. Листинг 10.16 демонстрирует несколь­
ко примеров такого использования.
Листинг 10.16. Использование методов Value и Formula для ввода данных

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:

Sub CreateCalculator()
'Выплаты по ссуде в листе с именем ЛистЗ

Worksheets("ЛистЗ").Select

With Range("Al")
'введение заголовков:
.Value = "Расчет выплат по ссуде"
.Font.Bold = True
.Font.Italic = True
.Font.Size =16
.Offset(1).Value = "Тариф"
.Offset(2).Value = "Период"
.Offset(3).Value = "Количество"
.Offset(5).Value = "Платеж"
'ввод формата чисел и формулы:
•Offset(l, 1).NumberFormat = "0.00%"
.Offset(3, 1).NumberFormat =
##0_);($#, ##0)"
.Offset(5, 1).NumberFormat = "$#,##0.00_);[Red] ($#,##0.00)"
.Offset(5, 1).Formula = "=PMT($B$2/12, $B$3*12, $B$4)"
End With

End Sub

420

Глава 10. Управление host-приложениями УВА

Данная процедура помещает на ЛистЗ активной книги простой калькуля­
тор для расчета выплат по ссуде. Оператор With использует ячейку А1 как на­
чальную. Свойство Value этой ячейки устанавливается содержащим текст
"Расчет выплат по ссуде" (строка 8); кроме того, устанавливаются некоторые
параметры шрифта (строки 9-11). В следующих четырех строках (12-15) ис­
пользуется свойство Value ячеек А2, АЗ, А4 и Аб для ввода заголовков. Обра­
тите внимание на использование метода Offset. Код строк 18-20 задает фор­
мат ячеек В2, В4 и Вб. Выполняется данная операция при помощи свойства
NumberFormat для диапазона ячеек, на который существует ссылка:
Object.NumberFormat = Formatstring
Object — является объектной ссылкой на ячейку или диапазон, которые не­
обходимо отформатировать, FormatString — текстовая строка, определяющая
форматирование.
Наконец, код строки 21 использует свойство Formula для введения в ячей­
ку Вб формулы платежа.

Определение имени диапазона ячеек

Имена диапазонов ячеек в VBA являются Name-объектами. Для того чтобы
их задать, необходимо использовать метод Add коллекции Names, которая
обычно является коллекцией имен, определенных в книге. Ниже представле­
на сокращенная синтаксическая конструкция использования метода Add кол­
лекции Names. Всего данный метод имеет одиннадцать аргументов — все не­
обязательные. Полный синтаксис метода следует смотреть в справочной систе­
ме, а легче всего получить доступ к нужному разделу справочной системы при
помощи Object Browser.

Синтаксис
Names.Add([Name] [, RefersTo][, RefersToRlCl])
Аргумент Name — любое строковое выражение, задающее имя, которое вы хотите
использовать для нового именованного диапазона. RefersTo и RefersToRlCl — аргу­
менты, описывающие диапазон, на который ссылается имя. Аргументы используют­
ся следующим образом:
□ RefersTo: Используйте данный аргумент для ввода диапазона ячеек, описываемо­
го в А1-стиле, например: "=Sales!$A$1 :$С$6".
□ RefersToRlCl: Используйте данный аргумент, когда диапазон ячеек описывается
или в стиле R1C1, например, "=Sales!R1C1 :R6C3", или когда описание диапазо­
на является методом или свойством, возвращающим диапазон, например,
Range("A1 :С6”) или Selection.

Листинг 10.17 демонстрирует применение метода Add коллекции Names.
Листинг 10.17. Задание имени диапазона при помощи метода Add
коллекции Names

1: Sub CreateNameRange()
2: 'создает именованный диапазон ячеек по координатам,
3: 'вводимым пользователем
4:

Работа с Excel

421

5:
Const strTaskName = "Имя диапазона"
6:
7:
Dim strTopLeft As String
8:
Dim strBottomRight As String
9:
Dim RngName As String
10: ' Dim strRefersToRlCl As String
11:
12:
Worksheets("Лист1").Select
13:
14:
'ввести диапазон и имя:
15:
strTopLeft = InputBox(prompt:-"Верхний левый угол •" &
16:
"в формате R1C1:", _
17:
Title:=strTaskName)
18:
strBottomRight = InputBox(prompt:="Нижний правый угол " &
19:
"в формате R1C1:",
20:
Title:=strTaskName)
21:
RngName = InputBox(prompt:="Имя нового диапазона:", _
22:
Title:=strTaskName)
23:
24:
'создать имя диапазона ячеек:
25:
strRefersToRlCl = "=Лист!" & strTopLeft &
& strBottomRight
26:
Names.Add Name:=RngName, RefersToRlCl:=strRefersToRlCl
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 с аргумен­
том назначения или без него или воспользоваться любым из следующих мето­
дов:

422

Глава 10. Управление host-приложениями УВА

Синтаксис
Object.Clear
Object.ClearContents
Object.ClearFormats
Object.ClearNotes
В каждом случае Object является объектной ссылкой на диапазон ячеек, который
следует очистить. Метод Clear очищает все — содержимое, форматирование и при­
мечания. ClearContents очищает содержимое Object, ClearFormats — форматиро­
вание Object, ClearNotes удаляет из Object примечания.

Листинг 10.18 демонстрирует пример применения методов Cut, Сору
и Clear.
Листинг 10.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:
Range("Al", 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:
.RangeC'Al", LastCell).Cut Destination:=Range("Al")
39:
End With

423

Работа с объектами Word

40:
41:
42:
43:
44:

Sheets(oldSheet).Select
Application.Screenupdating = True
End Sub

Код состоит из двух процедур: CopyToTemp (строки 1-23) и RestoreFromTemp (строки 26-44). Процедура CopyToTemp добавляет лист с именем Вре­
менный и выбирает лист с именем Лист1. Далее она копирует все данные из
активного листа и сохраняет их в листе Временный. Для возврата последней

ячейки активного листа и сохранения объектной ссылки результирующего
объекта Range в переменной LastCell данная процедура использует метод
SpecialCells с аргументом xlLastCell (строка 14). Затем с использованием опе­
ратора With над листом Временный выполняются два действия: код строки 16
использует метод Clear для очистки всего листа (метод Cells без аргументов
возвращает все ячейки листа), код строки 17 использует метод Сору для копи­
рования диапазона, заданного с помощью А1 (верхний левый угол) и LastCell
(нижний правый угол); «получателем» является ячейка А1 листа Временный.
Вторая процедура, 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.

424

Глава 10. Управление host-приложениями УВА

Работа с объектами Document
В Word используется формат документа, в котором объекты и события пол­
ностью доступны VBA, что дает возможность управлять документом и его объ­
ектами при помощи VBA-кода. Такой формат документа Word позволяет вы­
полнять наиболее распространенные задачи обработки текста быстрее и легче.
В следующих нескольких разделах рассмотрены наиболее часто используемые
объекты, методы и свойства Word.
Доступ к объекту Document

В Word каждый документ является объектом типа Document, а все откры­
тые документы текущей сессии Word образуют коллекцию Documents. Для
ссылок на конкретный документ следует использовать коллекцию Documents
объекта Application.

Синтаксис
Documents(Index)
Index может быть:

□ Численным выражением, представляющим документ, который необходимо ис­
пользовать. Число 1 означает первый документ, открытый в ходе текущей рабочей
сессии, 2 — второй открытый документ и так далее.
□ Строковым выражением, представляющим имя открытого документа, который
нужно использовать.
Наиболее распространенным и в большинстве случаев наиболее удобным способом
использования Index является текстовая строка.

Листинг 10.19 демонстрирует пример использования коллекции Documents.
Листинг 10.19. Использование коллекции Documents для возвращения

документа

1
2
3
4
5
6
7

Sub SetDocumentActivate ()
'Делает (открытый) документ активным
Documents("Н:\Документ10_1.docm").Activate
MsgBox "Н:\Документ10_1.docm становится активным!"

End Sub

Выражение в строке 4, Documents("C:\F.DOC"), возвращает объектную
ссылку на документ C:\F.DOC. Метод Activate делает указанный документ
активным. Оператор MsgBox в строке 5 выводит об этом сообщение. (Документ
C:\F.DOC в момент выполнения процедуры должен быть открыт, в противном
случае вы получите сообщение о runtime-ошибке.)

Работа с объектами Word

425

Для ссылок на активный документ нужно применять Application-свойство
ActiveDocument. Свойство ThisDocument следует использовать для ссылок на
документ, содержащий выполняемую в данный момент процедуру, особенно если
вы намереваетесь преобразовать свою программу в Word-надстройку (add-in)1.

Как открыть документ

Если необходимый вам документ не открыт, для загрузки его в память ис­
пользуйте метод Open:

Синтаксис
Documents.Open{Filename)

Аргумент Filename является текстовой строкой, представляющей полный путь к до­
кументу: логический диск, папка и имя файла. Если вы не задали диск или имя папки,
Word будет искать документ на текущем диске или в текущей папке.
Листинг 10.20 демонстрирует действие метода Open.
Листинг 10.20. Использование метода Open для открытия документа

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

Sub OpenTest()
'Предлагает открыть документ и затем его открывает
Dim DocumentName As String
DocumentName =
InputBox("Введите полный путь к документу")
If DocumentName О "" Then
Documents.Open FileName:=DocumentName
End If

End Sub

В данной процедуре переменная DocumentName объявляется как String
(строка 4), а функция InputBox предлагает пользователю ввести имя докумен­
та (строки 6 и 7). Оператор If. . .Then (в строке 8) проверяет, не отменил ли
пользователь диалог ввода. Если — нет (другими словами, если переменная
DocumentName не пуста), метод Open использует ее для того, чтобы открыть
заданный документ (строка 9).
Чтобы избежать ошибок при открытии существующего на диске файла
(пользователь вряд ли введет в диалоговом окне функции InputBox правиль­
ное имя файла), следует использовать встроенное в Word диалоговое окно
Open. Вы можете использовать встроенное в Word диалоговое окно Open при
помощи коллекции Dialogs, как показано ниже (Dialogs содержит все диа­
логовые окна, встроенные в Word):
Application.Dialogs(wdDialogFileOpen).Show

1 До появления локализованной версии Office 97 использовался термин «надстройка»,
в Office 97 появился термин «дополнение», тем не менее Microsoft Press пользуется
привычным русским пользователям термином «надстройка».

426

Глава 10. Управление host-приложениями УВА

Как создать новый документ
Если вашей процедуре необходимо создать новый документ, используйте
метод Add коллекции Documents, имеющий следующий синтаксис:

Синтаксис
Documents.Add([Template],

[NewTemplate])

Оба аргумента метода Documents.Add не являются обязательными. Template пред­
ставляет строковое выражение, задающее имя шаблона документа, на котором дол­
жен основываться новый документ. Аргумент Template наряду с именем файла
может включать имя диска и путь к папке. Включать полный путь необходимо, если
шаблон документа расположен в папке, отличной от той, в которой по умолчанию
хранятся шаблоны Word. Если вы опустите аргумент Template, Word создаст новый
документ, основываясь на шаблоне Normal.dot.
Аргумент NewTemplate может быть любым выражением типа Boolean. Если он равен
значению True, Word создает новый документ в виде шаблона. По умолчанию значе­
ние этого аргумента равно значению False.

Листинг 10.21 демонстрирует пример процедуры, создающей новый доку­
мент.
Листинг 10.21. Использование метода Add для создания нового документа

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:

Sub CreateNewLetter()
'Создает документ на базе шаблона Professional Letter

Dim dPath As String

dPath = "G:\Program Files\Microsoft Office\Templates\1049\"
Documents.Add Template:=dPath & "OriginLetter"
With ActiveDocument
.BuiltlnDocumentProperties("Title") =
"Письмо из России"
.BuiltlnDocumentProperties("Subject") =
Str(Date)
.BuiltlnDocumentProperties ("Author") =
Application.UserName
End With
End Sub

Код листинга 10.21 создает новый документ на основании шаблона OriginLetter, поставляемого вместе с Word и Microsoft Office. Любой новый доку­
мент автоматически становится активным. В строках с 8 по 15 используется
объект ActiveDocument для добавления некоторой общей информации, отно­
сящейся к новому документу. Свойства документа Title, Subject и Author
хранятся в коллекции BuiltlnDocumentProperties объекта Document. В ре­
зультате на экране появляется заготовка письма (рис. 10.6). Свойства активно­
го документа, устанавливаемые в строках кода 8-15, можно увидеть в диало­
говом окне Свойства.

Работа с объектами Word

427

Рис. 10.6

В результате работы
кода процедуры
CreateNewLetter
на экране
появляется
заготовка письма

Как сделать документ активным
Если ваша VBA-программа хранит несколько документов, открытых одно­
временно, вам может понадобиться переключаться с одного документа на дру­
гой. Для того чтобы сделать какой-либо из открытых документов активным,
используйте метод Activate:

Синтаксис
Object.Activate

Object представляет собой ссылку на документ, который следует сделать активным.

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

к документу

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

Sub ActivateTest ()
'Активизирует два документа без изменения вывода на экран

Dim SaveDoc As String
SaveDoc = ActiveDocument.Name

Application.Screenupdating = False
Documents("TestData.XML").Activate

'не обновлять экран

'действие, выполненное над TestData.doom
With Selection
. .TypeText Text:="Документ данных установлен активным"
.TypeParagraph

428

15:
16:
17:
18:
19:
20:

Глава 10. Управление host-приложениями УВА

End With
Documents(SaveDoc).Activate
Application.Screenupdating = True 'обновлять экран

End Sub

Процедура листинга 10.22 демонстрирует два принципа хорошего стиля
программирования: скрывать от пользователя промежуточные операции
и всегда «возвращать пользователя» в то место, из которого он запустил про­
грамму. Назначение процедуры листинга 10.22 — переключиться из текущего
документа в другой документ (TestData.xml), произвести в нем (программно)
определенные изменения и затем вернуться к исходному документу. В первую
очередь, имя текущего активного документа сохраняется в строковой перемен­
ной SaveDoc (в строке 6). Далее, чтобы избавить пользователя от наблюдения
за подробностями выполнения процедуры, в строке 8 свойство ScreenUpdating устанавливается в значение False. В строке 9 активизируется документ
TestData.doc. Строки с 12 по 15 представляют действия, выполняемые над до­
кументом TestData.docm. Данный фрагмент программы просто добавляет
в документ некоторый текст. Чтобы «вернуть пользователя» обратно в исход­
ный документ, в строке 17 документ вновь устанавливается активным. А
в строке 18 свойство Screenupdating вновь получает значение True.
Не следует без особой необходимости активизировать документ. Как прави­
ло, вы можете выполнить изменения или получить информацию о документе,
просто ссылаясь на соответствующий объект Document. Например, чтобы вы­
яснить, какой шаблон присоединен (если вообще какой-нибудь присоединен)
к TestData.XML, вы можете использовать следующий оператор (не делая до­
кумент активным):
DocTemplate = Document("TestData.XML").AttachedTemplate

Как сохранить документ

Если ваш VBA-код изменяет содержимое документа, вы должны быть уве­
рены, что дадите пользователю возможность сохранить эти изменения, или
обеспечить их сохранение с помощью вашей программы. Хотя вы можете
включить встроенную в Word команду Save в меню и панели инструментов,
вы, возможно, захотите сохранять документ под управлением процедуры, осо­
бенно если нужно не дать пользователю возможность отказаться от измене­
ний, произведенных вашим VBA-кодом.
Для сохранения документа используйте метод Save объекта Document:

Синтаксис
Object.Save
Object представляет ссылку на открытый объект типа Document, который необходи­
мо сохранить.

Можно воспользоваться и родственным методом SaveAs. Данный метод со­
храняет документ под новым именем и изменяет имя документа. (Метод имеет

429

Работа с объектами Word

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

Синтаксис
[Fi1 eFormat])

Object.SaveAs([FileName] ,

Object — любая допустимая ссылка на открытый документ типа Document. Необяза­
тельный аргумент FileName — строковое выражение, указывающее новое имя, под
которым должен быть сохранен документ. FileName может включать полный путь
(включая диск и папку). Если опустить полный путь, документ сохраняется в текущей
папке на текущем диске. Если вы полностью опустите аргумент FileName, документ
сохранится под текущим именем, если документ с подобным именем уже существу­
ет, он будет переписан без предупреждения.
Необязательный аргумент FileFormat определяет формат, в котором будет сохранен
документ. Аргумент FileFormat может быть любой из встроенных констант (опреде­
ленных в классе WdSaveFormat):

..

...

wdFormatDocument

Документ сохраняется как «обычный Microsoft
Word-документ» (используется по умолчанию).

wdFormatDOSText

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

wdFormatDOSTextLineBreaks

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

wdFormatEncodedText

Документ сохраняется как кодированный текстовый
файл (для указания кодовой страницы используется
аргумент Encoding).

wdFormatFilteredHTML

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

,! wdFormatHTML

wdFormatRTF

Все форматирование сохраняется.

wdFormatTemplate

Документ сохраняется как Word-шаблон.

wdFormatText

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

. .

430

Глава 10. Управление host-приложениями УВА

wdFormatTextLineBreaks

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

wdFormatUnicodeText

Документ сохраняется как Unicode-текстовый файл.

wdFormatWebArchive

Текст, рисунки и форматирование сохраняются как
однофайловая Web-страница.

J WdFormatXML

Текст и форматирование сохраняются
с использованием Extensible Markup Language (XML)
Word XML-схемы.

Листинг 10.23 демонстрирует пример процедуры, использующей как Save,
так и SaveAs.
Листинг 10.23. Применение методов Save и SaveAs

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

Sub CreateTemplate()
'На базе активного документа создается новый шаблон документа
Dim NewName As String

With ActiveDocument
If Not .Saved Then .Save
NewName = Left(.Name, Len(.Name) - 3) & "dot"
.SaveAs FileName:=NewName, FileFormat:=wdFormatTemplate
End With

End Sub

Процедура этого листинга сохраняет активный документ, а затем сохраня­
ет копию активного документа как шаблон. Начинается код с объявления пе­
ременной, предназначенной для сохранения имени файла нового шаблона. ,
Оператор With в строках с 6 по 10 содержит операторы, связанные с объектом
ActiveDocument.
Оператор If. . .Then (строка 7) проверяет свойство Saved документа. Если
оно равно значению False, документ содержит изменения, которые еще не
были сохранены, поэтому процедура вызывает метод Save.
Имя файла шаблона создается в строке 8 конкатенацией полного имени до­
кумента, за исключением последних трех символов, со стандартным расшире­
нием для имени файла шаблона "dot". (Имя документа получается из его свой­
ства Name.) Результат используется в качестве аргумента для метода SaveAs
(строка 9), который сохраняет копию документа в виде файла шаблона. Обра­
тите внимание на использование аргумента FileFormat, имеющего значение
wdFormatTemplate — данное значение аргумента сообщает Word о том, что
необходимо сохранить документ как шаблон.

431

Работа с объектами Word

Для проверки того, был ли документ когда-либо сохранен, следует исполь­
зовать свойство Path объекта Document. Если Path возвращает пустую строку
(""), то документ никогда прежде не сохранялся.
Как закрыть документ
Завершив работу с документом, вы должны закрыть его для освобождения
памяти и других системных ресурсов. Закрыть документ можно, используя
одну из следующих форм метода Close:

Синтаксис
Documents.Close
Object.Close([SaveChanges] [, OriginalFormat ]

[,

RouteDocument ])
Первая синтаксическая форма просто закрывает все открытые документы. Word
предлагает перед закрытием документа (если это необходимо) сохранить сделан­
ные в нем изменения.
Вторая синтаксическая форма закрывает конкретный документ, на который указыва­
ет Object. Аргумент SaveChanges может быть равен одной из перечисленных ниже
встроенных констант (определенных в классе WdSaveOptions): wdDoNotSaveChanges (документ закрывается без сохранения изменений), wdPromptToSaveChanges (Word запрашивает, нужно ли сохранять изменения), wdSaveChanges
(изменения сохраняются). Аргумент OriginalFormat определяет формат сохранения
для документа и может быть одной из следующих WdOriginalFormat-констант:
wdOriginalDocumentFormat, wdPromptUser или wdWordDocument. Аргумент Rou­
teDocument определяет необходимость передачи документа следующему получате­
лю.

В листинге 10.24 приведен код с использованием метода Close.
Листинг 10.24. Применение метода Close

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:

Sub CloseAll()
'Закрывает все документы и предлагает сохранить изменения
Const qButtons = vbYesNo + vbQuestion
Dim Doc As Document
Dim Ans As Integer
Dim MsgPrompt As String

For Each Doc In Documents
If Not (Doc.Name = ThisDocument.Name) Then
If Not Doc.Saved Then
MsgPrompt = "Сохранить изменения в " & Doc.Name & "?"
Ans = MsgBox(prompt:=MsgPrompt, Buttons:=qButtons)
If Ans = vbYes Then
Doc.Close SaveChanges:=wdSaveChanges
Else
Doc.Close SaveChanges:=wdDoNotSaveChanges
End If
Else
Doc.Close

432

22:
23:
24:
25:
26:

Глава 10. Управление host-приложениями УВА

End If
End If
Next Doc
End Sub

Процедура листинга 10.24 закрывает все открытые документы (за исключе­
нием документа, содержащего саму процедуру) и спрашивает у пользователя,
нужно ли выполнять сохранение внесенных изменений для каждого из доку­
ментов, имеющих несохраненные изменения. Используйте подобную процеду­
ру вместо метода 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. Поэтому для добавления
к ней нового шаблона нужно создать этот шаблон, сначала создав объект Do­
cument. Вы можете создать новый шаблон документа одним из следующих
способов:

Работа с объектами Word

433

□ Использовать метод Documents .Add с аргументом NewTemplate, равным
True, для одновременного создания нового документа и преобразования
его в объект Template.
□ Использовать метод SaveAs объекта Document с аргументом FileFormat,
заданным как wdFormatTemplate, для сохранения документа в виде
шаблона (в листинге 10.23 это уже использовалось).

Как загружать и выгружать общие шаблоны
Как вы уже можете знать, единственный способ сделать код в проекте VBA
Word доступным всем открытым документам — это сохранить его в шаблоне
документа, загруженном как общий. По этой причине вам, возможно, захочет­
ся поместить процедуру текущего документа в шаблон, загруженный как об­
щий, делая таким образом процедуры и другие ресурсы данного шаблона дос­
тупными всем открытым документам.
Коллекция Templates не имеет метода Open. Вместо этого следует загру­
жать шаблон документа как общий посредством коллекции Addins объекта
Applications Word. (Addins — коллекция всех доступных в Word надстро­
ек, независимо от того, были они установлены или нет.) Поскольку они явля­
ются общими ресурсами для программ, панелей команд, стилей и других эле­
ментов, Word рассматривает общие шаблоны как разновидность надстройки.
Если вы знаете, что ваша программа больше не нуждается в ресурсах кон­
кретного шаблона, то можете выгрузить общий шаблон для освобождения сис­
темных ресурсов компьютера.
Чтобы загрузить шаблон как общий, используйте метод Add коллекции
Addins в следующей синтаксической форме:

Синтаксис
Object.Add(FileName

[,

Install])

Object представляет ссылку на объект Addins. Аргумент FileName является обяза­
тельным. Это строковое выражение, содержащее имя файла шаблона, включая пол­
ный путь.
Аргумент Install (необязательный) управляет установкой надстройки: при равенстве
значению True (значение по умолчанию) надстройка устанавливается, при False —
добавляется в список надстроек, но не устанавливается.

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

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

Листинг 10.25 содержит две демонстрационные процедуры: одна — загру­
жает шаблон как общий, а другая — выгружает общий шаблон.

434

Глава 10. Управление host-приложениями УВА

Листинг 10.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:="3агружается общий шаблон")

If Trim(strName) = "" Then Exit Sub
Addins.Add FileName:=strName

End Sub

Sub UnloadGlobalTeplate()
'Выгружает шаблон, заданный как общий
Dim strName As String
strName = InputBox(prompt:="Введите имя шаблона:",
Title:="Выгрузка общего шаблона")
If Trim (strName) = "" Then Exit Sub
Addins(strName).Delete

End Sub

Как присоединить шаблон
Если вам необходимо задать присоединенный к документу шаблон, исполь­
зуйте свойство AttachedTemplate объекта Document в следующей синтакси­
ческой форме:

Синтаксис
Object.AttachedTemplate = Template
Здесь Object — любая допустимая ссылка на объект типа Document. Template может
быть как объектной ссылкой на уже открытый Template-объект, так и строковым вы­
ражением, задающим имя файла шаблона, который необходимо присоединить.
Свойство AttachedTemplate всегда возвращает объектную ссылку на объект типа
Template. Если документ не содержит присоединенного шаблона, свойство
AttachedTemplate возвращает ссылку на Normal.dot.

Следующий фрагмент программы присоединяет шаблон к активному доку­
менту (предполагается, что переменная TestTemplate содержит строку, вклю­
чающую полный путь к файлу шаблона):
ActiveDocument.AttachedTemplate = TestMyTemplate

Работа с объектами Word

435

Для отключения от активного документа всех шаблонов достаточно исполь­
зовать следующий код:
ActiveDocument.AttachedTemplate = ""

Компоненты объекта Document
Документ в Word представляет собой конструкцию довольно свободной
формы: он состоит из символов, слов, предложений и абзацев. Документ мо­
жет содержать колонтитулы, сноски и прочие элементы. Как следствие, число
и тип объектов, используемых для управления содержимым документа, мо­
жет сначала вызвать замешательство.
Каждый документ состоит из нескольких областей (stories). Каждая область
документа соответствует конкретному разделу документа, такому как колонти­
тул, сноска основной текст документа, примечания и так далее. Многие методы
объекта Document позволяют выбрать конкретную область. Многие объекты так­
же обладают свойствами, из которых можно извлечь значение, указывающее, ка­
кая область объекта документа в нем содержится. VBA Word предоставляет не­
сколько внутренних констант (определенных в классе WdStoryType), которые
вы можете использовать для задания конкретной области документа:
wdMainTextStory, wdPrimaryFooterStory, wdPrimaryHeaderStory и другие.
Текст внутри области документа может рассматриваться как коллекция
символов, слов, предложений и абзацев. Word предоставляет коллекцию объ­
ектов для каждого из этих представлений: Characters, Words, Sentences
и Paragraphs. Ниже дана краткая характеристика этих коллекций:
□ Characters. Коллекция символов. В зависимости от того, из какого объ­
екта вы получили доступ к коллекции, она может содержать некоторые
или все символы области документа. Объект для одного символа отсутст­
вует. Каждый элемент коллекции Characters является объектом типа
Range, включающим только один символ. (Объекты Range Word будут
рассмотрены далее в этом разделе.)
□ Words. Коллекция слов. В зависимости от того, из какого объекта вы по­
лучили доступ к коллекции Words, она может содержать некоторые или
все слова области документа. В Word отсутствует объект «слово». Каж­
дый элемент коллекции Words является объектом типа Range, включаю­
щим только одно слово. (Слово — это группа символов, отделенная пробе­
лами или знаками пунктуации.)
□ Sentences. Коллекция предложений. В зависимости от того, из какого
объекта вы получили доступ к коллекции Sentences, она может содержать
некоторые или все предложения области документа. Подобно коллекциям
Characters и Words объект «одно предложение отсутствует». Каждый эле­
мент коллекции Sentences является объектом типа Range (который будет
описан далее в этой главе), включающим единственное предложение.
□ Paragraphs. Коллекция абзацев. В зависимости от того, Paragraphsколлекция какого именно объекта используется, может содержать неко­
торые или все абзацы области документа. Каждый элемент коллекции
Paragraphs является объектом типа Paragraph. Вы можете использо­
вать свойства и методы объекта Paragraph для изменения стиля, увели­
чения или уменьшения интерлиньяжа и других, связанных с абзацем за­
дач. Каждый объект типа Paragraph, в свою очередь, содержит объект
типа Range, который содержит текст параграфа.

436

Глава 10. Управление host-приложениями УВА

Представленный обзор коллекций показывает, что доступ к тексту для ка­
ждой из этих коллекций, в конечном счете, осуществляется с помощью объек­
та Range. Объект Range является одним из основных объектов Word и появля­
ется в виде свойства во многих других объектах Word.
Каждый объект Range представляет непрерывную часть области докумен­
та, определяемую положениями начального и' конечного символов. Объект
Range может не содержать ни одного, содержать один или много символов
и может представлять весь документ или любую его часть. Используя методы
и свойства объекта Range, можно добавлять текст, форматировать его, добав­
лять поля или выполнятьлюбые другие действия. Объект Range также пре­
доставляет методы, позволяющие задавать или изменять диапазон символов,
на который ссылается конкретный объект Range, и определять, в каком тек­
стовом блоке документа находится диапазон.
Другим основным объектом Word является объект Selection. Объект
Selection представляет курсор вставки в окне, отображающем определенную
часть документа. В каждом окне документа может находиться только один
объект Selection, и только один объект Selection может быть активным
в любой конкретный момент времени. Объект Selection используется для
того, чтобы добавлять текст в то место, на которое указывает курсор вставки,
применять форматирование, выделять текст для копирования или вырезания
или любой другой задачи, которую можно выполнить интерактивно с помо­
щью курсора вставки, вводя текст, щелкая, или перетаскивая его. Объект
Selection может быть как непрерывной областью документа, так и сжатым
до курсора вставки. В следующем разделе обсуждается, как с помощью
свойств и методов объекта Selection выполнять основные операции с доку­
ментом.
В дополнение к только что описанным основным компонентам документа
каждый объект Document также содержит несколько других коллекций, та­
ких как Fields (коллекция полей, включая поля для простановки почтовых
реквизитов в документе), TablesOfContents и другие.

Как задать диапазон
Прежде чем вы сможете работать с объектом Range, следует задать в доку­
менте диапазон текста, с которым необходимо работать. Объект Range может
являться курсором вставки, не содержащим ни одного символа, или быть не­
прерывной областью документа. Вы можете создать в документе более одного
объекта Range.
Как получить ссылку на объект
Существует несколько различных способов сослаться на конкретный диапа­
зон документа. Можно задать диапазон непосредственно или получить его при
помощи одной из коллекций документа: Paragraphs, Sentences или Words.
Для того чтобы задать диапазон в области основного текста документа непо­
средственно, воспользуйтесь методом Range, применив следующую синтакси­
ческую конструкцию:

Работа с объектами Word

437

Синтаксис
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)

Код листинга 10.26 демонстрирует пример процедуры, использующей раз­
личные диапазоны.
Листинг 10.26. Использование объектов Range

1:
2:
3:
4:
5:
6:
7:
8:
9:

Sub TestRange()
'В активном документе первое слово каждого
'абзаца, имеющего стиль "Основной" и длину не менее
'трех слов, выделяется курсивом

Dim mParagraph As Paragraph
For Each mParagraph In ActiveDocument.Paragraphs
With mParagraph

438

10:
11:
12:
13:
14:
15:
16:
17 :
18:

Глава 10. Управление host-приложениями УВА

If .Style = "Основной" Then
If .Range.Words.Count >= 3 Then
.Range.Words(1).Italic = True
End If
End If
End With
Next mParagraph

End Sub

Процедура TestRange выделяет курсивом первое слово каждого абзаца
в главной области документа, если он содержит три или более слов и если
стиль данного абзаца — Основной.
В строке 8 начинается цикл For Each, который перебирает все абзацы кол­
лекции Paragraphs документа. Строка 9 начинается с оператора With, вклю­
чающего несколько операторов, ссылающихся на свойства и методы текущего
объекта Paragraph. В строке 10 используется оператор If для определения
того, действительно ли абзац имеет стиль Основной текст. Текущий стиль аб­
заца определяется при помощи свойства Style.
В строке 11 используется оператор If для определения того, содержит ли
абзац более двух слов. Поскольку символ конца абзаца считается словом, для
любого абзаца, содержащего как минимум два слова, не считая символа конца
абзаца, выражение в строке 11 будет равно значению True.
В строке 12 первое слово абзаца выделяется курсивом (рис. 10.7). Сначала
при помощи свойства Range объекта Paragraph возвращается диапазон, на
который ссылается данный абзац. В свою очередь, коллекция Words использу­
ется для того, чтобы возвратить объект типа Range, ссылающийся на первое
слово в диапазоне абзаца. Чтобы выделить слово курсивом, свойству Italic
объекта Range присваивается значение True.
cm) ••fctanKoft W'

Рис. 10.7

В результате
работы кода
процедуры

И *

.iaSbCd АаВЬС АаВЬС .

«:т»»вгв
' 7

%

Нкианы:

TestRange

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

Подходят ли резервные базы данных для вашей стратегии
готовности?
Скотт Дайэл
При использовании любых решений высокой доступности (high availability, НА), важно

хорошо понимать их для того, чтобы вы могли релизовать наилучшую стратегию для
ваших условий. В журнале за март 2007 года в статье «Защита данных с помощью Data
Guard Broker» (“Protect your data from disaster with Data Guard Broker”) мы обсуждали, как
резервные базы даннх (или Data Guard, как называют эту возможность со времени выхода
версии 9i) могут помочь защитить ваши данные. Рассмотрим теперь, как резервные базы
данных могут согласоваться со всей стратегией готовности.
Резервные базы данных не обязательно являются быстрым решением для сохранения баз
данных до 99.999% времени. Если вам требуется такой уровень готовности, мы
рекомендуем вам OPS (Oracle Parallel Server) или его земену, RAC (Real Application
Clusters). Резервные базы данных полезны, если происходит нечто катастрофическое с
вашим центром данных. Недавно я разговаривал с одним специалистом в области
информационных технологий, который потерял много серверов в результате ущерба,
причиненного наводнением. Это прекрасный пример того, когда следует использовать
t

ЧназгликШ

..............

Работа с объектами Word

439

Как выполнить ссылку на диапазон

Размер области, на которую ссылается конкретный объект 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
Вместо переопределения диапазона напрямую вы можете расширить или умень­
шить диапазон до заданного размера или «свернуть» его полностью.

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

Синтаксис
Object.MoveEnd([Unit] , [Count])
Object.MoveStart([Unit] , [Count])
В данном синтаксическом выражении Object — любая допустимая ссылка на объект
Range. Как для метода MoveEnd, так и для метода MoveStart аргументы Unit
и Count являются необязательными. Аргумент Unit задает элемент, для которого бу­
дет изменяться начало или конец диапазона. Unit может быть одной из констант
WdUnits, перечисленных в таблице 10.1. Если вы опустите аргумент Unit, методы
MoveStart и MoveEnd по умолчанию будут использовать wdCharacter.
Аргумент Count — число элементов (units), на которое должна быть сдвинута конеч­
ная точка. Если вы используете для аргумента Count положительное число, конечная
точка перемещается в документе вперед, если вы используете для аргумента Count
отрицательное число, конечная точка перемещается назад.

440

Глава 10. Управление host-приложениями УВА

Ниже приведены операторы, демонстрирующие применение методов Mo­
vestart и MoveEnd (AnyRange является объектной переменной, содержащей
ссылку на объект Range):
AnyRange.MoveStart Unit:=wdParagraph, Count:= -1
AnyRange.MoveEnd Unit:=wdWord, Count:=-2
AnyRange.MoveEnd Count:=6
AnyRange.MoveStart Count:=8

Таблица 10.1 Встроенные константы WdUnits
Константа

Описание

wdCell

Ячейка таблицы.

wdCharacter

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

wdColumn

Столбец таблицы.

wdLine

Строка текста. Вы можете использовать данную константу только
для аргумента Unit, если используемый метод применяется
к объекту Selection.

wdParagraph

Абзац. Абзац ограничивается символом конец абзаца (1|). Символ
конца абзаца не отображается на экране пока вы не щелкните кнопку
Показать все символы (Show АП) панели инструментов Word.

wdRow

Строка таблицы.

wdSection

Раздел документа.

wdSentence

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

wdStory

Область документа.

wdTable

Таблица.

wdWord

Слово. Слово ограничено пробелами и символами пунктуации.

j

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

Синтаксис
Object.Expand([Unit])
Здесь Object — представляет любую допустимую ссылку на объект Range или
Selection. Необязательный аргумент Unit определяет элемент, до которого расши­
ряется диапазон, и может быть равен одной из констант WdUnits, перечисленных
в таблице 10.1. Если вы опустите аргумент Unit, метод Expand использует по умол­
чанию значение константы wdWord.

Работа с объектами Word

441

Ниже представлен фрагмент кода, выделяющий десятое предложение доку­
мента и затем расширяющий диапазон для включения в него всего абзаца,
в котором находится десятое предложение (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.

Как переместить или «свернуть» объекты Selection и Range
Вы уже знаете, как определить или переопределить диапазоны и как свя­
зать текущий выделенный фрагмент с конкретным диапазоном. Объекты
Range и Selection имеют несколько методов, позволяющих перемещать диа­
пазон или выделенный фрагмент. Чаще всего эти методы используются для
перемещения объекта Selection перед добавлением и выделением текста.
В действительности, существует пара методов, которые доступны исключи­
тельно в объекте Selection, они не имеют аналогов в объекте Range.
Чтобы поместить объект Selection в начале или в конце текущей строки
текста, столбца таблицы, строки таблицы или области документа и при жела­
нии выделить данную строку текста, столбец или строку таблицы или же об­
ласть, можно использовать методы НотеКеу или EndKey в следующей синтак­
сической форме:

442

Глава 10. Управление host-приложениями УВА

Синтаксис
Object.НотеКеу([Unit], [Extend])
Object.EndKey([Unit], [Extend])
В обоих случаях Object представляет собой допустимую ссылку на объект Selection. В за­
висимости от конкретного значения используемого аргумента метод НотеКеу оказывает
на выделенный фрагмент такое же действие, как и нажатие клавиш Home, Shift+Home,
Ctri+Home или Ctrl+Shift+Home. Аналогично метод EndKey оказывает на выделенный
фрагмент такое же действие, что и нажатие в различных комбинациях клавиши End.
Необязательный аргумент Unit задает элемент, в конце которого должен помещаться вы­
деленный фрагмент (в конце строки, столбца и т.д.). Unit может быть значением одной из
следующих констант WdUnits: wdStory, wdLine, wdColumn или wdRow. Если аргумент
Unit опустить, то как НотеКеу, так и EndKey используют по умолчанию значение кон­
станты wdLine (в конце строки).
Необязательный аргумент Extend определяет, должен ли выделенный фрагмент быть
расширен или должен ли курсор вставки быть перемещен. В качестве Extend можно ис­
пользовать значение одной из встроенных констант WdMovementType: wdMove или
wdExtend. Использование wdMove приведет к «сворачиванию» выделенного фрагмента
до курсора вставки, после чего курсор вставки переместится на начало или конец задан­
ного элемента документа, определяемого аргументом Unit. Использование wdExtend
оказывает такое же действие, как нажатие на клавиши Ноте или End при удерживаемой
нажатой клавише Shift. Использование wdExtend приведет к тому, что выделенный
фрагмент будет расширен до конца заданного элемента. Если вы опустите аргумент
Extend, в качестве значения по умолчанию будет использована константа wdMove.

В представленном ниже примере каждый из двух операторов использует
один из только что описанных методов. Выполнение первого оператора «свора­
чивает» выделенный фрагмент до курсора вставки и затем перемещает курсор
вставки в начало текущей строки. Выполнение второго оператора расширяет
выделенный фрагмент до конца текущей строки.
Selection.НотеКеу
Selection.EndKey Extend:=wbExtend

Хотя объекты Range и Selection имеют много различных методов для вы­
полнения перемещений, возможно, наиболее мощным из них является метод
GoTo. Метод GoTo позволяет помещать объекты Range и Selection в любое
место в пределах текущей области и перемещать Selection' или Range по до­
кументу вперед или назад на заданное количество символов, слов или абзацев.
Для перемещения объектов Selection или Range используйте метод GoTo
в следующей синтаксической форме:

Синтаксис
Object. GoTo ([ IVbat] ,

[IWiich],

[Count],

[Name])

Здесь Object — любая допустимая ссылка на объекты Selection, Range или
Document. Если Object ссылается на Selection, то метод GoTo возвращает объект
Range, представляющий новое положение выделенного фрагмента после его «сво­
рачивания» до курсора вставки и перемещения в позицию символа, расположенного
непосредственно перед заданным положением. Если Object ссылается на Range
или Document, метод GoTo просто возвращает объект Range, представляющий на­
чальное положение для заданной области.

Работа с объектами Word

443

Все аргументы метода GoTo являются необязательными. Аргумент What задает тип
элемента, в который должен быть перемещен выделенный фрагмент, и может быть
любой из встроенных констант WdGoToltem. В таблице 10.2 перечислены некото­
рые из констант WdGoToltem. Для того чтобы просмотреть полный список констант,
доступных в классе WdGoToltem, используйте Object Browser.
Аргумент Which указывает, в какой элемент должен быть перемещен выделенный
фрагмент. Which может быть равен любой из встроенных констант класса
WdGoToDirection: wdGoToAbsolute, wdGoToFirst, wdGoToLast, wdGoToNext,
wdGoToPrevious, wdGoToRelative.

Аргумент Count задает число элементов документа, на которое должен быть переме­
щен выделенный фрагмент. По умолчанию значение аргумента Count равно 1. Ис­
пользование аргумента Count подразумевает использование аргумента What,
указывающего, куда необходимо выполнить перемещение, и аргумента Which, за­
дающего, какой тип перемещения необходимо выполнить.
Последний аргумент Name определяет имя области, в которую должен быть переме­
щен выделенный фрагмент. Вы можете использовать аргумент Name только в том
случае, если аргумент What также используется и равен при этом значению одной из
следующих констант: wdGoToBookmark, wdGoToComment, wdGoToField или
wdGoToObject.

В результате выполнения приведенного ниже оператора выделенный фраг­
мент перемещается на следующую страницу:
Selection.GoTo What:=wgGoToPage

Результатом выполнения следующего оператора будет перемещение выде­
ленного фрагмента на последнюю страницу документа:
Selection.GoTo What:=wgGoToPage, Which:=wdGoToLast

В результате выполнения приведенного ниже оператора выделенный фраг­
мент перемещается на две строки вниз относительно текущего местоположения:
Selection.GoTo What:=wgGoToLine, Which:=wdGoToNext, Count:=2

Таблица 10.2 Встроенные константы WdGoToltem
— .

Константа

...

.

Описание

wdGoToBookmark Закладка.
wdGoToField

Поле, например поле даты или номера страницы.

wdGoToHeading

Заголовок, то есть текст, отформатированный с помощью одного
из стилей заголовка: Заголовок!, Заголовок2 и так далее.

wdGoToLine

Строка документа.

wdGoToPage

Страница документа.

wdGoToPercent

Местоположение в документе, выраженное в процентах от длины
документа.

444

Глава 10. Управление host-приложениями УВА

В дополнение к изменению положения выделенного фрагмента вы можете
«свернуть» выделенный фрагмент (или диапазон) до курсора вставки. Для это­
го используйте метод Collapse в следующей синтаксической форме:

Синтаксис
Object.Collapse([Direction] )
Здесь Object — любая допустимая ссылка на объекты Selection или Range. Необя­
зательный аргумент Direction задает направление, в котором диапазон или выделен­
ный фрагмент должны быть «свернуты». Он может быть равен одной из констант
класса WdCollapseDirection: wdCollapseEnd или wdCollapseStart. По умолчанию
используется значение константы wdCollapseStart.

Следующие операторы демонстрируют применение метода Collapse:
ActiveDocument.Paragraphs(3).Range.Select
Selection.Collapse Direction:=wdCollapseEnd

Первый оператор выделяет третий абзац активного документа. Второй опе­
ратор «сворачивает» выделенный фрагмент до курсора вставки, помещенного
в конец предыдущего выделенного фрагмента.

Добавление текста
Основным назначением программ подготовки текста является хранение
,и обработка текста. Одной из основных задач, выполняемых при интерактив­
ной работе с Word, является ввод текста в документ. Точно также, одна из
наиболее распространенных задач, которую вам придется выполнять под
управлением VBA-кода, будет заключаться в том, чтобы добавлять текст. Объ­
екты Selection и Range имеют несколько методов, предоставляющих воз­
можность добавлять текст. В первую очередь рассмотрим методы добавления
текста объекта Selection, поскольку вам чаще всего придется иметь дело
именно с этим объектом.
Простейший способ добавить текст в документ состоит в использовании ме­
тода TypeText объекта Selection, сделать это можно при помощи следующей
синтаксической конструкции:

Синтаксис
Object.TypeText([Text])
Object — любая ссылка на объект Selection. Аргумент Text является обязательным,
он может быть любым строковым выражением, и это именно тот текст, который до­
бавляется в документ. Метод TypeText помещает текст в то место, где расположен
курсор вставки, как если бы вы ввели его с клавиатуры. Если Selection содержит
диапазон и свойство ReplaceSelection равно значению True, то добавляемый текст
заменяет выделенный фрагмент. В противном случае текст помещается перед кур­
сором вставки объекта Selection. При установке Word свойство ReplaceSelection
по умолчанию принимает значение True.

Работа с объектами Word

445

Свойство ReplaceSelection соответствует флажку заменять выделенный
фрагмент (Typing Replace Selection) на вкладке Правка диалогового Word-окна
Параметры, которое можно открыть при помощи команды Сервис | Параметры.
Можно также задать это свойство при помощи объекта Options.
Если метод TypeText добавляет текст так, как будто вы ввели его с клавиа­
туры, то, очевидно, что объекту Selection необходим метод, эквивалентный
нажатию клавиши Enter, для того, чтобы можно было добавлять новый аб­
зац. Этот метод так и называется TypeParagraph. Синтаксическая конструк­
ция этого метода выглядит следующим образом:

Синтаксис
Object.TypeParagraph
Object — ссылка на объект Selection. Метод TypeParagraph помещает в документ
новый абзац аналогично тому, как это происходит при нажатии на клавишу Enter.
Если объект Selection — диапазон, содержимое диапазона заменяется новым абза­
цем. Если Selection — курсор вставки, добавляется новый абзац, а курсор вставки
перемещается в документе вперед.

Чтобы случайно не заменить выделенный фрагмент, используйте метод
Collapse для «сворачивания» выделенного фрагмента в курсор вставки.
Возможно, вам понадобится добавлять текст в диапазон, который не явля­
ется выделенным. В этом случае следует использовать методы InsertAfter,
InsertBefore, InsertParagraphAfter и InsertParagraphBefore. Все эти
методы применимы как к объектам Selection, так и к объектам Range.
Для добавления текста в начало или конец диапазона используйте методы
InsertBefore или InsertAfter со следующим синтаксисом:

Синтаксис
Object.InsertBefore(Text)
Object.InsertAfter(Text)
Здесь Object — ссылка на объект Selection или Range. Text — строковое выражение
для текста, который необходимо добавить. Аргумент Text обязателен для каждого из
методов. Заданный текст помещается в диапазон, и диапазон расширяется, включая
в себя добавленный текст. Оправдывая свое имя, метод InsertBefore помещает
текст в начало диапазона или выделенного фрагмента, a InsertAfter помещает текст
соответственно в конец диапазона или выделенного фрагмента.
Применение метода InsertAfter имеет некоторые особенности, требующие допол­
нительных пояснений. Если выделенный фрагмент или диапазон включает целый аб­
зац, метод InsertAfter вставляет текст как новый абзац. Так происходит потому, что
выделенный фрагмент, включающий целый абзац, также включает и символ конца
абзаца. Чтобы вставить текст в конец абзаца, необходимо или «свернуть» диапазон
до курсора вставки в позиции перед символом конца абзаца, или таким образом из­
менить конечную точку диапазона, чтобы он содержал на один символ меньше.

446

Глава 10. Управление host-приложениями УВА

Замечание
Для всех методов, добавляющих текст — TypeText, InsertAfter и InsertBefore, —
можно использовать функцию Chr и встроенные константы VBA (vbCr, vbLf, vbCrLf,
vbTab) как часть строки аргумента Text для добавления символов, которые нельзя
набрать на клавиатуре, или символов, которые имеют в VBA специальное значение
(например, кавычки).

Так же, как метод TypeText имеет сопутствующий ему метод ТуреРагаgraph, который можно использовать для добавления нового абзаца, методы
InsertBefore и InsertAfter имеют сопутствующие методы для добавления
нового абзаца перед областью или после области, на которую ссылается опре­
деленный диапазон:

Синтаксис
Object.InsertParagraphBefore
Object.InsertParagraphAfter
В каждой синтаксической конструкции Object — ссылка на объект Selection или на
объект Range. Метод InsertParagraphBefore добавляет символ конца абзаца пе­
ред диапазоном или выделенным фрагментом, в то время как метод InsertParag­
raphAfter добавляет символ конца абзаца в конец диапазона или выделенного
фрагмента. Ни тот, ни другой метод не имеет аргументов. Как и в случае с другими
методами Insert..., диапазон или выделенный фрагмент расширяется для включе­
ния добавленного символа конца абзаца.

Листинг 10.27 демонстрирует использование методов InsertBefore, In­
sertAfter и InsertParagraphAfter.
Листинг 10.27. Применение методов InsertAfter, InsertBefore,
InsertParagraphAfter

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:

Sub InsertDocumentlnformation()
'Помещает в начало документа два абзаца
'Первый абзац содержит имя файла, в котором хранится документ
'Второй абзац содержит имя файла-шаблона документа
Dim aRange As Range
Set aRange = ActiveDocument.Range(Start:=0, End:=0)

With aRange
.InsertBefore Text:="Имя файла документа: " &
ActiveDocument.FullName
.InsertParagraphAfter
.InsertAfter Text^"Присоединенный к документу шаблон: " &
ActiveDocument.AttachedTemplate.FullName
.InsertParagraphAfter
End With
End Sub

Работа с объектами Word

447

Рис. 10.8. Код процедуры InsertDocument-Information помещает в начало
текущего документа два абзаца: первый абзац содержит имя файла, в котором
хранится документ, второй абзац содержит имя файла-шаблона документа

Как вырезать, скопировать, вставить и удалить текст
Вам обязательно понадобится не только вводить, но и вырезать, копиро­
вать, вставлять или удалять текст в документе. Для выполнения этих задач,
как объекты Selection, так и объекты Range имеют соответствующие мето­
ды.
Чтобы вырезать, скопировать или вставить выделенный фрагмент в или из
буфера обмена Windows, можно использовать один из следующих методов:

Синтаксис
Object.Cut
Object.Copy
Object.Paste
Для каждого из этих методов Object — любая ссылка на объект Selection или Range.
При использовании вами метода Cut содержимое диапазона или выделенного фраг­
мента вырезается из документа и помещается в буфер обмена Windows. Объекты
Selection или Range остаются в документе, «сворачиваясь» до курсора вставки. Ме­
тод Сору копирует содержимое диапазона или выделенного фрагмента в буфер об­
мена Windows. Объекты Selection или Range при этом не изменяются.
Метод Paste вставляет содержимое буфера обмена Windows в заданный диапазон
или выделенный фрагмент. Если диапазон или выделенный фрагмент не является
курсором вставки, то текст, вставляемый из буфера обмена, заменяет содержимое
заданного диапазона или выделенного фрагмента. Когда вы используете метод
Paste с объектом Range, диапазон расширяется, включая в себя содержимое встав­
ленного из буфера обмена текста. При использовании же вами метода Paste с объ­
ектом Selection выделенный фрагмент располагается после вставленного из
буфера обмена текста; выделенный фрагмент не расширяется.

448

Глава 10. Управление host-приложениями VBA

Листинг 10.28 содержит процедуру, которая при помощи методов Cut
и Paste объекта Selection меняет местами два абзаца документа. Код лис­
тинга 10.29 при помощи методов Cut и Paste объекта Range меняет местами
два слова в документе.
Листинг 10.28. Использование методов Cut и Paste совместно с объектом
Selection

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

Sub TransposeParagrahs()
'Меняет местами текущий абзац и абзац, следующий за ним.
'Используется объект Selection.

With Selection
.Expand Unit:=wdParagraph
. Cut
.Move Unit:=wdParagraph
.Paste
End With
End Sub

Листинг 10.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. Синтаксиче­
ская конструкция для его использования следующая:

Синтаксис
Object.Delete([Unit],

[Count])

Object — любая ссылка на объекты Selection или Range. Оба аргумента Unit и Count
являются необязательными. Аргумент Unit может быть равен значению wdCharacter
или wdWord: По умолчанию значение Unit равно wdCharacter. Аргумент Count зада­
ет количество символов или слов (в зависимости от значения аргумента Unit), кото­
рые должны быть удалены. Если объекты Range или Selection ссылаются на
диапазон текста, метод Delete удаляет содержимое данного диапазона.

Работа с объектами Word

449

Если вы используете Delete как функцию, она возвращает значение, ука­
зывающее число удаленных элементов текста, или — 0, если операция удале­
ния не удалась.
Для удаления заданного числа символов или слов до или после диапазона
или выделенного фрагмента сначала его необходимо «свернуть» до курсора
вставки. Для того чтобы удалить элементы текста после курсора вставки, сле­
дует использовать в качестве аргумента Count положительное число, а чтобы
удалить элементы текста до курсора вставки — отрицательное. На рис. 10.9
приведена часть документа до применения процедуры TransposeParagrahs,
а на рис. 10.10 — после ее применения.
Дскуш-щУГ’.Фэоц - Mrrosnft Word

Times Hew Rsms«

’ IB '

* -IB

................. .... J ..

AaBbCcDf

AaBbCcDt

.

выделение

* Боинге...

:■

-

71
CMW’

<

Фнксапия-транзанщи-кажется-такой-простой-задачей.-Когда-вы-хоппе-сохранить-изГ
просто-вводите-сопитГ-и-точку-с-запятой£^И'нажимаетё-ЕпТег.-Или-добавляете-эту-к|
сохранения-изменений-данных.-выполненных-в-этой-процедуре.-Одаако.-несмотря-на
может-стать-причиной-серьезных-1фоблем,-особенно-когда-вы-вставляете-новые-стрс1
Проблема-заключается-в-целостностп-данных. -Может ■понадобшъся.чгобыкаждаясй
вставленав-несколько-таблиц—особенно-в-ситуашш-хранилгшкм-данньи.-Если-тош®
какой-либовнешний-ключ,-Огас1е-не-сообщитвам-о-том,-что-вы-забьыи-какую-либо-£
; Страниц* г ms 1

Цмслй ««я Ш .

адский

*3

Рис. 10.9, Код процедуры TransposeParagrahs меняет местами текущий абзац
и абзац, следующий за ним (документ до применения процедуры TransposeParagrahs)

db ‘ *

n

-J

ji

Times HewRoman

AWfcWMiWxtocm

' 10



v

. ж < 1 • 0
GoSub MyRoutinel
Case Is < 0
GoSub MyRoutine2
End Select

Debug.Print
Exit Sub
MyRoutinel:
Debug.Print
Num = Num /
Return
MyRoutine2:
Debug.Print
Num = 100 +
Num = Num /
Return
End Sub

Num

"значение/2:"
2

" (100+значение)/2"
Num
2

GoTo
Приводит к безусловной передаче управления выполнением программы на ука­
занную строку внутри процедуры.
Синтаксис
GoTo line

Обязательный аргумент line может быть любой строковой или числовой мет­
кой.
Оператор GoTo передает управление только на строку в процедуре, в которой
этот оператор описан. С точки зрения структурного программирования этот опера­
тор является «вредным», наносящим ущерб читабельности, создающим опреде­
ленные трудности для отладки и сопровождения программного кода. Практика
программирования показывает, что без этого оператора можно вполне обходиться.
Чаще всего в VB этот оператор используется в программах обработки ошибок.
If...Then...Else

Выполняет группу операторов в зависимости от значения некоторого условия.

Синтаксис 1
If condition Then [statements]

[Else elsestatements]

500

Приложение А. Операторы в УВА

Синтаксис 2
If condition Then
[statementsl]
[Elself condition-n Then

[elseifstatements]

...

[Else

[elsestatements2]]
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"

Если необходимо выполнить более одного оператора в однострочной структуре,
можно записать их все в одной строке, используя в качестве разделителя символ
двоеточия.
Блочная структура обеспечивает большую гибкость, чем однострочная форма, и
обычно легче читается и отлаживается. Следующие строки эквиваленты предыду­
щей строке кода:
If а > d Then
MsgBox "а больше, чем d"
End If

Пример

В этой процедуре обработки события — выбор кнопки-переключателя —
Public-переменной пр присваивается тип подразделения. Далее вызывается функ­
ция загрузки наименований подразделений выбранного типа, например, в окно
списка.
Private Sub OptionCklad_Click()
If OptionCklad.Value Then
np = 2
'тип подразделения -- СКЛАД
Else

Implements

501

'тип подразделения — ОПТОВЫЙ МАГАЗИН

пр = 4
End If

t = ListBoxlLoad(пр)
End Sub

Implements

Определяет интерфейс (interface) или класс (class), внедряемый в модуль клас­
са, в котором используется этот оператор.
Синтаксис
Implements [InterfaceName | Class]

Обязательный аргумент InterfaceName или Class — имя интерфейса или класса
в библиотеке типов (type library), методы которого будут внедряться соответст­
вующими методами в VB-классе.
Интерфейс — коллекция прототипов, представляющая те члены (методы и
свойства), которые инкапсулирует интерфейс; это означает, что он содержит толь­
ко объявления для процедур-членов (member procedures). Класс обеспечивает реа­
лизацию (implementation) всех методов и свойств одного или более интерфейсов.
Классы обеспечивают код, используемый при вызове любой функции контролле­
ром (controller) класса. В Visual Basic любой член, который не является явно чле­
ном внедренного (implemented) интерфейса, — неявно член интерфейса по умолча­
нию.

Input #
Считывает данные из открытого' файла последовательного доступа и присваива­
ет их переменным.
Синтаксис
Input # filenumber, varlist

Синтаксис оператора Input # состоит из следующих эелементов:

filenumber

Обязательный. Любой допустимый файловый номер.

varlist

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

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

значение, назначаемое переменной

■ I

Ограничивающая запятая Empty
или пустая строка

#NULL#
#TRUE# или #FALSE#

Null
True или False

_________

502

Приложение А. Операторы в УВА

данные

значение, назначаемое переменной

#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)
Inpvt #1, StrMy, NumberMy
MsgBox StrMy & " : " & NumberMy
Loop
Close #1
'закрыть файл
End sub

'открыть файл
'цикл до конца файла
'считать данные в две переменные
'результат -> на экран

Kill
Оператор Kill удаляет файлы с диска.
Синтаксис

Kill pathname

Обязательный аргумент pathname — строковое выражение, которое определяет
одно или более файловых имен для удаления. Аргумент pathname может включать
каталог (или папку) и имя драйвера.
В Microsoft Windows оператор Kill поддерживает использование символов мно­
жественной подстановки * или ?.
Пример

Kill "TestFile.TXT"
Kill "*.ВАК"

Let
Присваивает значение выражения переменной или свойству.
Синтаксис

[Let] varname = expression

Синтаксис оператора Let состоит из следующих элементов:
Let

Необязательный. Явное использование ключевого слова Let — это
оригинальный стиль, который обычно не применяется.

varname

Обязательный. Имя переменной или свойства; должен соответствовать
стандарным соглашениям об именовании переменных.

expression

Обязательный. Значение, присваиваемое переменной или свойству.

503

Line Input #

Значение выражения может быть присвоено переменной или свойству, если
только оно имеет тип данных, совместимый с типом переменной. Нельзя присво­
ить строковое выражение (string expression) числовой переменной (numeric
variable); нельзя присвоить числовое выражение строковой переменной.
Переменные типа Variant могут присваиваться строчным или числовым пере­
менным. Однако обратное не всегда верно. Строковой переменной может быть при­
своена любая Variant-переменная, кроме Null, но числовой переменной может
быть присвоена только та Variant-переменная, значение которой может интерпре­
тироваться как число. Для определения того, может ли Variant-переменная быть
преобразована в число, можно использовать функцию IsNumeric.

Пример
Dim StrMy, IntMy
Let StrMy = "Опять — весна..."
Let IntMy = 25

Line Input #
Считывает одну строку из файла последовательного доступа и присваивает эту
строку String-переменной.
Синтаксис
Line Input Ifilenumber, varname

Синтаксис оператора Line Input # состоит из следующих элементов:

filenumber

Обязательный. Допустимый файловый номер.

varname

Обязательный. Допустимое имя переменной типа Variant или String.

Данные, считываемые оператором Line Input #, обычно записываются в файл
оператором Print #.
Оператор Line Input # считывает из файла по одному символу, пока не встретит
символ «возврата каретки» (Chr(13)) или последовательность «возврат каретки» —
«перевод строки» (Chr(13) + Chr(lO)). Последовательность «возврат каретки» —
«перевод строки» (carriage return-linefeed) не добавляется к считываемой сим­
вольной строке.
Пример

В качестве примера приведены две процедуры: для записи данных в файл
(TestPrint) и для чтения данных из файла (Testinput). Запустите на выполнение
первую процедуру. Затем откройте в Редакторе VB окно Immediate и выполните
вторую процедуру для просмотра содержимого тестового файла.
Sub TestPrint ()
'запись данных в файл TESTFILE
Dim TextLine
Open "TESTFILE" For Output As #1
Print #1, "Желал я дущу освежить,"
Print #1, ."Бывалой жизнию пожить"
Print #1, "В забвенье сладком близ друзей"
Print #1, "Минувшей юности моей"
Print #1,

Print #1, Tab (10); "А.С. Пушкин"
Close #1
End Sub

504

Приложение А: Операторы в УВА

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
Lock, Unlock

Управляет доступом ко всему или части файла, открытого с использованием
оператора Open.
Синтаксис
Lock [#]filenumber[, recordrange]
Unlock [#] filenumber[, recordrange]

Синтаксис оператора Lock (и Unlock) состоит из следующих элементов:

filenumber

Обязательный. Любой допустимый файловый номер.

recordrange

Необязательный. Диапазон записей для открытия (закрытия)
доступа.

Аргумент recordrange имеет следующий синтаксис:
recnumber | [start] То end

recnumber

Номер записи (файл в режиме Random) или номер байта (файл в
режиме Binary), на который устанавливается или отменяется доступ.

start

Номер первой записи (или байта) для открытия или закрытия доступа.

end

Номер последней записи (или байта) для открытия или закрытия
доступа.

LSet

505

Операторы 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 = "