Программный код большинства примеров данной лекции можно найти в проектах, доступных для просмотра: DocOne7, DocTwo7.
Большая часть материала этой и последующих лекций носит справочный характер. Для программистов, хорошо знакомых с VBA по предыдущим версиям, вполне достаточно беглого просмотра их содержания. Они будут обращаться к этим лекциям по мере необходимости. Конечно, для тех, кто впервые знакомится с этим языком, чтение этой и последующих лекций не только полезно, но и может предшествовать чтению предыдущих лекций, предполагающих хорошее знание основ языка VBA.
VBA - операторный язык. Это значит, что его программы (модули) представляют последовательности операторов. Набор операторов VBA весьма обширен и не уступает в этом "большим" языкам вроде Паскаля и С. Группу декларативных операторов VBA, служащих для описания объектов, с которыми работает программа (типов, переменных, констант, объектов приложений и др.), мы уже рассмотрели. Операторы другой группы обеспечивают присвоение и изменение значений этих объектов, операторы третьей группы управляют ходом вычислений, четвертой - работой с каталогами и файлами и т.д. Часть операторов досталась VBA в наследство от предыдущих версий Бейсика и без них вполне можно обойтись при написании новых программ.
При записи текста программ для упрощения чтения, отладки и модификации программы удобней каждый оператор располагать в отдельной строке текста. Следуйте правилу: "Один оператор - одна строка". Но, разрешается размещать на строке и несколько операторов, в отличие от общепринятого символа разделения операторов "точки с запятой", в VBA символом разделения двух операторов в одной строке служит двоеточие. Заметьте, некоторые операторы, например оператор If, могут стоять лишь на первом месте в строке. И по этой причине каждый оператор, как правило, следует начинать с новой строки, лишь иногда, разумно, группу операторов присваивания размещать в одной строке. Чаще возникает другая ситуация, - оператор слишком длинный и его текст не виден полностью на экране дисплея, что затрудняет чтение и понимание программы. В этом случае оператор следует продолжить в одной или нескольких строках. Чтобы продолжить (перенести) оператор на следующую строку, используется пара символов пробел-подчеркивание " _ ". Например,
MyAddress = "дом: " Number "улица: " Street _ "город: " City
Перед оператором в строке может стоять метка - последовательность символов, начинающаяся с буквы и кончающаяся двоеточием " :". Метки можно размещать и в отдельных строках перед теми операторами, которые они должны помечать. Они нужны для GoTo, использование которых считается "дурным тоном" в структурном программировании. Но иногда без меток и переходов на них обойтись трудно - в частности, для указания входов в обработчики ошибок в некоторых процедурах.
Комментарии на исполнение программы не влияют, но необходимы как признак "хорошего стиля". Офисные программы используются многократно и не раз модернизируются в процессе своей жизни. Вы можете сэкономить на комментариях и написать и отладить небольшой модуль без них. Но уже через неделю никто, в том числе и автор, не сможет понять его действие и модифицировать нужным образом. Затраченные на это усилия и время намного превзойдут "экономию". Любая строка текста программы может заканчиваться комментарием. Комментарий в VBA начинается апострофом (') и включает любой текст, расположенный правее в строке. Обычно в комментариях описывают задачи, решаемые модулями, функции, выполняемые процедурами, смысл основных переменных (если он неясен из имен), алгоритмы работы процедур. Полезно также комментировать операторы вызовов внешних для данного модуля процедур, объясняя их действия.
Другое применение комментарии находят при отладке программ. Если требуется исключить из программы некоторые операторы (например, вызовы еще не реализованных или сомнительных процедур), достаточно перед ними поместить апостроф. Например, при выполнении последовательности операторов
x=x+z 'z=fun(z,x) y=y*x
функция fun для вычисления нового значения z во второй строке не вызывается и не мешает проверить правильность значения y.
В VBA имеется еще один способ выделения комментариев с помощью ключевого слова Rem. Такой комментарий (в отличие от комментария, начинающегося апострофом) должен отделяться от предыдущего оператора в строке двоеточием:
weight= weight+z: Rem Увеличение веса value=weight*price 'Новая стоимость
При отладке VBA программ часто приходится временно комментировать целые участки текста, иногда страницы текста. В этом случае закомментировать или снять комментарии довольно утомительное дело. В этих случаях следует пользоваться двумя полезными командами меню Edit: "Comment Block" и "UnComment Block". Они позволяют автоматически закомментировать или снять комментарий с выделенного блока. Я всегда использую настройку (Customize) и выношу на панель редактора
Операторы присваивания - основное средство изменения состояния программы (значений переменных и свойств объектов). Мы уже многократно использовали их в примерах из предыдущих лекций. В VBA несколько видов операторов присваивания.
С помощью этого оператора происходит "обычное" присвоение значения выражения переменной или свойству.
Синтаксис:
[Let] переменная = выражение
Ключевое слово Let, как правило, опускается. Переменная является именем переменной или свойства; выражение задает значение, присваиваемое переменной. Его тип должен соответствовать типу переменной. Нарушение этого условия, например, при попытке присвоить числовой переменной строковое значение, приводит к тому, что при компиляции появится сообщение об ошибке. Переменным типа Variant можно присваивать значения разных типов, например, строковых или числовых выражений. Строковой переменной можно присваивать любое значение типа Variant, кроме Null. Числовой же переменной значение типа Variant можно присвоить, только если оно может быть преобразовано к числу.
Оператор Let можно применять для присвоения одной переменной типа "запись" значения другой такой переменной. Заметьте, это возможно только, если обе они - переменные одного определенного пользователем типа.
Примеры:
Public Sub Assign1() Dim MyStr As String, MyInt As Integer Let MyStr = "Здравствуй, зайчик!" ' С ключевым словом Let MyInt = 5 ' Без него. Обычный вариант. Debug.Print MyStr, MyInt End Sub
Этот оператор служит для присвоения строк с одновременным выравниванием слева, а также для копирования записи одного определенного пользователем типа в запись другого типа. Его синтаксис:
Lset СтрПеременная = СтрВыражение Lset переменная1 = переменная2
Здесь ключевое слово LSet обязательно, СтрПеременная - имя строковой переменной, СтрВыражение - выражение строкового типа. Во втором варианте переменная1 - имя переменной некоторого определенного пользователем типа, в которую выполняется копирование, переменная2 - имя переменной, возможно, другого пользовательского типа, значение которой копируется.
Результатом присвоения строк всегда является строка той же длины, что и у СтрПеременная. Если при этом СтрВыражение короче, добавляются пробелы справа; длиннее - лишние символы справа удаляются.
При втором варианте оператора двоичное представление записи из участка памяти, отведенного переменной2 копируется в участок памяти, отведенный переменной1, - При этом данные не преобразуются в соответствии с типами элементов (полей) записи, и если типы соответствующих элементов обеих записей не совпадают, результат операции трудно предсказать (часто выдается сообщение о несоответствии типов). Поэтому этот вариант следует использовать, лишь тогда, когда типы всех соответствующих элементов записей совпадают и имеют одинаковый размер.
Примеры.
Public Sub Assign2() Dim Str1 As String, Str2 As String Str1 = "0123456789" ' Начальное значение Str2 = "abcd" Debug.Print Str1, Str2 LSet Str2 = Str1 ' Результат - "0123" LSet Str1 = " Влево" ' Результат - " Влево Debug.Print Str1, Str2 End Sub"
Вот результаты отладочной печати:
0123456789 abcd Влево 0123
В следующем примере происходит корректное копирование одной записи в другую; типы соответствующих элементов в определенных пользователем типах MyType1 и MyType2 совпадают:
Type MyType1 age As Integer cost As Long End Type Type MyType2 year As Integer pay As Long 'pay As Integer End Type Public Sub Assign3() Dim my1 As MyType1 Dim my2 As MyType2 my1.age = 50 my1.cost = 45666 my2.year = 1997 my2.pay = 22000 Debug.Print my1.age, my1.cost, my2.pay, my2.year LSet my2 = my1 ' после этого присвоения my2.year=50 и my2.pay=45666 Debug.Print my1.age, my1.cost, my2.pay, my2.year End Sub
Вот результаты отладочной печати:
50 45666 22000 1997 50 45666 45666 50
Если изменить тип элемента pay в MyType2 на Integer, то будет напечатано значение my2.pay, равное 0.
Этот оператор присваивает значение строковой переменной с выравниванием справа:
RSet СтрПеременная = СтрВыражение
СтрПеременная - имя строковой переменной, СтрВыражение - выражение строкового типа. В отличие от LSet оператор RSet нельзя использовать для копирования переменных записей. Результатом присвоения строк всегда является строка той же длины, что и СтрПеременная. Если при этом СтрВыражение короче, добавляются пробелы слева, длиннее - лишние символы слева удаляются.
Примеры:
Public Sub Assign4() Dim Str1, Str2, Str3 Str1 = "0123456789" ' Начальное значение Str2 = "abcd" Debug.Print Str1, Str2 RSet Str2 = Str1 ' Результат - "0123" RSet Str1 = "Вправо " ' Результат - " Вправо " RSet Str3 = Str1 ' Результат - пустая строка "" Debug.Print Str1, Str2, Str3 End Sub
Вот результаты отладочной печати:
0123456789 abcd Вправо 0123
Этот оператор применим при работе с объектами, устанавливает ссылку на вновь созданный или существующий объект. Его синтаксис:
Set ОбПеременная = {[New] ОбВыражение| Nothing}
ОбПеременная - имя переменной или свойства, New - необязательное ключевое слово, используемое для явного вызова операции создания нового экземпляра класса (объекта). Если ОбПеременная содержала ссылку на объект, при присвоении эта ссылка освободится. ОбВыражение может быть именем объекта (класса), другой переменной того же типа, функцией или методом, возвращающими объект соответствующего типа. Выполнение оператора Set с правой частью Nothing прерывает связь между ОбПеременной и объектом, на который она ссылалась. Если при этом на него не осталось других ссылок, ресурсы системы и память, выделенные под этот объект, освобождаются. В общем случае, если ключевое слово New не указано, новая копия объекта не создается, а ОбПеременная как значение получает ссылку на существующий объект. При этом может оказаться, что несколько переменных ссылаются на один объект и изменение этого объекта через одну из них влияет на все остальные.
Примеры:
Определим класс объектов Child:
'Класс Child 'Свойства Public Age As Byte Public Name As String 'Другие свойства и методы пока не определены
А теперь введем объекты этого класса:
Public Sub Assign5() Dim Children(1 To 2) As Child Dim Boy As Child, Girl As Child 'Создаем объекты Set Children(1) = New Child Set Children(2) = New Child 'Инициализируем их Children(1).Age = 10 Children(1).Name = "Александр" Children(2).Age = 7 Children(2).Name = "Мария" Debug.Print "Имя: ", Children(1).Name, "Возраст: ", Children(1).Age Debug.Print "Имя: ", Children(2).Name, "Возраст: ", Children(2).Age 'Утанавливаем дополнительные ссылки на существующие объекты Set Boy = Children(1) Set Girl = Children(2) Boy.Name = "Саша" Girl.Name = "Маша" 'Изменились сввойства объектов Debug.Print "Имя: ", Children(1).Name, "Возраст: ", Children(1).Age Debug.Print "Имя: ", Children(2).Name, "Возраст: ", Children(2).Age 'Удаляем одну из ссылок, но объект остается Set Children(1) = Nothing Set Children(2) = Nothing Debug.Print "Имя: ", Boy.Name, "Возраст: ", Boy.Age Debug.Print "Имя: ", Girl.Name, "Возраст: ", Girl.Age End Sub
Вот результаты отладочной печати:
Имя: Александр Возраст: 10 Имя: Мария Возраст: 7 Имя: Саша Возраст: 10 Имя: Маша Возраст: 7 Имя: Саша Возраст: 10 Имя: Маша Возраст: 7
Набор управляющих операторов VBA делает честь любому хорошо If и оператор разбора случаев Case - все эти средства позволяют организовать процесс вычислений надежно и эффективно в соответствии с лучшими традициями программирования.
Это общепринятый в языках программирования
Синтаксис.
Имеется два варианта синтаксиса: в одну строку и в форме блока. В первом случае он имеет вид:
If условие Then [операторы1] [Else операторы2 ]
Во втором случае оператор расположен на нескольких строках:
If условие Then [операторы] [ElseIf условие-n Then [операторы-n]... [Else [ИначеОператоры]] End If
Здесь условие обязательно в обоих вариантах. Оно может быть числовым или строковым выражением со значениями True или False ( Null трактуется как False ). В качестве условия можно использовать и выражение вида TypeOf ИмяОбъекта Is ТипОбъекта, где ИмяОбъекта - ссылка на объект, а ТипОбъекта - произвольный корректный тип объекта. Операторы1 и операторы2 - это последовательности из одного или нескольких разделенных двоеточием операторов. По крайней мере, одна из этих последовательностей должна быть непустой. Если условие истинно ( True ), выполняется последовательность операторы1, ложно ( False ) - операторы2. Форма условного оператора определяется по наличию в строке, начинающейся If условие Then, текста после Then, отличного от комментария. Если такой текст есть, считается, что использована форма в одну строку, нет - оператор должен иметь форму блока. В этом случае подблоки вида:
[ElseIf условие-n Then [операторы-n]
могут отсутствовать либо повторяться несколько раз; подблок:
[Else [ИначеОператоры]]
также необязателен, а закрывающий оператор End If необходим. По крайней мере одна из последовательностей операторы, операторы-n … или ИначеОператоры должна быть непустой. Если условие истинно, выполняются операторы, нет - отыскивается первое истинное условие-n, и выполняются операторы-n. Если все эти условия ложны, выполняются ИначеОператоры. После выполнения одной (возможно, пустой) последовательности End If.
Примеры:
Public Sub MinMax1(ByVal X As Integer, ByVal Y As Integer, _ Min As Integer, Max As Integer) 'Оператор If в одну строку If X > Y Then Max = X: Min = Y Else Max = Y: Min = X End Sub Public Sub MinMax2(ByVal X As Integer, ByVal Y As Integer, _ Min As Integer, Max As Integer) 'Оператор If в виде блока If X > Y Then Max = X Min = Y Else Max = Y Min = X End If End Sub Public Sub If1() Dim Max As Integer, Min As Integer Call MinMax1(2 + 3, 2 * 3, Min, Max) Debug.Print Max, Min Call MinMax2(2 + 3, 2 * 3, Min, Max) Debug.Print Max, Min End Sub
По-видимому, можно было бы классифицировать программистов в зависимости от того, какая из форм записи процедуры MinMax кажется им предпочтительнее при записи и при чтении. Приведем еще один пример, где идет работа с объектами. Вначале добавим еще один класс объектов:
'Класс Man 'Свойства Public Age As Byte Public Name As String 'Другие свойства и методы пока не определены
А теперь приведем процедуру, в которой будем работать с объектами класса Child и Man. Заметьте, в условии оператора IF проверяется тип объекта:
Public Sub BoyOrMan()
Dim Boy As New Child
Dim Person As New Man
Dim SomeBody As Object
Dim Answer As Integer
Boy.Age = 10: Boy.Name = "Александр"
Person.Age = 21: Person.Name = "Александр"
Answer = InputBox("Введите число от 10 до 20", "Возраст", 15)
If Answer > 15 Then
Set SomeBody = Person
Else: Set SomeBody = Boy
End If
If TypeOf SomeBody Is Child Then
Debug.Print "Это мальчик!"
ElseIf TypeOf SomeBody Is Man Then
Debug.Print "Это Мужчина"
Else
Debug.Print "Не знаю, кто это"
End If
End Sub
Результат ее работы зависит от того, какой возраст Вы введете в окне ввода.
Этот оператор производит разбор случаев и в зависимости от значения анализируемого выражения выбирает и исполняет одну из последовательностей операторов.
Синтаксис.
Select Case Выражение-тест [Case СписокВыражений-n [операторы-n]] [Case Else [ИначеОператоры]] End Select
Выражение-тест должно присутствовать обязательно. Оно может быть произвольным выражением с числовым или строковым значением. СписокВыражений-n должен присутствовать в строке, начинающейся ключевым словом Case (Случай). Выражения в этом списке отделяются запятыми и могут иметь одну из форм:
выражение,выражение-нижняя-граница To выражение-верхняя-граница,Is оператор-сравнения выражение.Первая форма задает отдельные значения, вторая и третья позволяют задавать сразу целые диапазоны (области) значений. Последовательность операторов операторы-n необязательна. Она будет исполнена, если соответствующий СписокВыражений-n является первым списком, сопоставимым с текущим значением Выражения-теста (т. е. он явно содержит это значение, либо оно попадает в один из заданных в списке диапазонов). После исполнения операторов последовательности операторы-n проверка на соответствие другим спискам выражений не производится, и управление передается на оператор, следующий за End Select. Необязательная последовательность ЕслиОператоры выполняется, если ни один из списков выражений несопоставим со значением Выражения-теста.
Пример:
Public Sub Case1()
Dim Before As Integer
Dim CurrentYear As Integer, Str As String
' Инициализация переменных:
CurrentYear = 1999
Before = InputBox("Сколько лет тому назад?", "Когда", 10)
Select Case CurrentYear - Before
Case 1954 To 1969, 1971 To 1974, 1982, Is < 1970
Str = " Годы учебы"
Case 1972 To 1989
Str = "Годы воспитания"
Case Else
Str = "Прочие годы"
End Select
Debug.Print Str
End Sub
Здесь, если перед выполнением выбора Before = 20, значением тестового выражения будет 1979, и будет работать второй вариант (" Годы воспитания "). При Before = 25 значение 1974 сопоставимо с двумя списками, но для исполнения будет выбран лишь первый вариант (" Годы учебы ").
Диапазоны значений можно задавать и для строк. При этом их значения считаются упорядоченными лексикографически. Например, возможен такой список выражений:
Case "everything", "nuts" To "soup"
Задаваемое им множество строк включает строку " everything " и все строки от " nuts " до " soup " (например, " onion ").
Позволяет повторять группу операторов заданное число раз.
Синтаксис:
For счетчик_цикла = начало To конец [Step шаг] тело цикла Next [счетчик_цикла]
Здесь счетчик_цикла - это числовая переменная. В начале выполнения цикла она принимает значение, задаваемое числовым выражением начало. (Переменная счетчик_цикла не может иметь тип Boolean или быть элементом массива.) Числовое выражение конец задает заключительное значение счетчика цикла. Оно вычисляется до начала исполнения тела цикла и не меняется, даже если входящие в него переменные изменяют в теле цикла свои значения. Числовое выражение шаг необязательно. Его значение также вычисляется в начале цикла и прибавляется к счетчику цикла всякий раз, когда завершается выполнение тела цикла и вычисление достигает строки Next [счетчик_цикла]. Если шаг цикла явно не указан, по умолчанию он равен 1. тело цикла - это последовательность операторов, которая будет выполнена заданное число раз. При каком значении переменной счетчик_цикла происходит завершение цикла, зависит от знака параметра шаг. Если шаг положителен, цикл завершится, когда впервые выполнится условие:
счетчик_цикла > конец
Если шаг цикла отрицателен, условие его завершения:
счетчик_цикла < конец
Это условие проверяется перед началом выполнения цикла, а затем - после каждого прибавления шага к счетчику цикла в операторе Next. Если оно выполнено, управление передается на оператор, следующий за Next, нет - выполняются операторы из тела цикла. Завершить цикл For … Next можно и с помощью оператора Exit For. Такие операторы могут быть расположены в тех местах тела цикла, где требуется из него выйти, не дожидаясь выполнения условия завершения.
Примеры.
В нашем примере три вложенных цикла For … Next использованы для вычисления произведения двух целочисленных матриц, инициализированных случайными числами. Затем результирующая матрица проверяется на наличие в ней нулевого значения:
Public Sub For1() Dim A(1 To 5, 1 To 5) As Integer Dim B(1 To 5, 1 To 5) As Integer Dim C(1 To 5, 1 To 5) As Integer Dim I As Integer, J As Integer, K As Integer Dim Res As String ' Инициализация матриц A и B случайными числами в интервале [-10, +10] VBA.Randomize For I = 1 To 5 For J = 1 To 5 'Получение случайного числа Rnd и преобразование в целое A(I, J) = Int(21 * Rnd) - 10 Next J Next I For I = 1 To 5 For J = 1 To 5 B(I, J) = Int(21 * Rnd) - 10 Next J Next I 'Вычисление произведения матриц For I = 1 To 5 For J = 1 To 5 C(I, J) = 0 For K = 1 To 5 C(I, J) = C(I, J) + A(I, K) * B(K, J) Next K Next J Next I Res = "No" C(2, 2) = 0 'Проверка на нулевое значение For I = 1 To 5 For J = 1 To 5 If C(I, J) = 0 Then Debug.Print "Индексы: ", I, J Res = "Yes" Exit For End If Next J Next I Debug.Print Res End Sub
Обратите внимание, оператор выхода Exit For прекращает выполнение только внутреннего цикла, так что проверка на ноль будет осуществляться в каждой строке матрицы, независимо от существования нулей в предыдущих строках. Сделаем еще несколько замечаний по поводу оператора For Next:
Next можно не указывать имя переменной, задающей счетчик, это имя подразумевается по умолчанию, как завершающее последний открытый оператор For. Однако и эту возможность не следует использовать. Рекомендуем всегда явно указывать имя счетчика в операторе Next.Public Sub For2() Dim A(1 To 5) As Integer Dim i As Integer For i = 5 To 1 Step -1 A(i) = i i = i + 1 Next i End Sub
Обычно попытка изменить значение счетчика цикла в его теле означает, что вместо цикла For…Next следовало бы применить цикл другого вида, например Do…Loop.
Повторяет блок операторов, пока заданное условие является истинным или пока оно не станет истинным.
Синтаксис:
Имеется четыре варианта синтаксиса этого цикла. В двух первых вариантах условие проверяется в начале цикла:
Do [{While | Until} условие]
тело цикла
Loop
В других двух вариантах условие проверяется в конце цикла:
Do
тело цикла
Loop [{While | Until} условие]
Здесь условие является числовым или строковым выражением со значениями True или False. Вообще оно необязательно. Значение Null условия трактуется как False. Тело цикла - это последовательность операторов, которая будет выполняться, пока условие остается истинным, если перед ним стоит ключевое слово While или пока оно остается ложным - в Until. Таким образом, циклы вида While условие эквивалентны циклам вида Until Not условие. Кроме того, в тело цикла может входить оператор Exit Do, выполнение которого сразу прекращает цикл и передает управление оператору, непосредственно следующему за Loop. В случае нескольких вложенных циклов Do … Loop оператор Exit Do завершает лишь самый внутренний цикл, в теле которого он расположен.
Примеры.
В нашем примере реализованы три варианта поиска по образцу с проверкой условия в начале цикла, в конце цикла и в середине цикла для варианта поиска по образцу с барьером:
Public Sub Loop1() Const Size = 5 Dim X() As Integer Dim i As Integer Dim Found As Boolean Const pat = 7 'Инициализация случайными числами в интервале [1 - 10] ReDim X(1 To Size) Randomize For i = 1 To Size X(i) = Int(11 * Rnd) Next i 'Поиск по образцу с проверкой в начале цикла i = 1: Found = False Do While (i <= Size) And (Not Found) If X(i) = pat Then Found = True Else: i = i + 1 End If Loop If Found Then Debug.Print "Найден образец!" Else: Debug.Print "Образец не найден!" End If 'Поиск по образцу с проверкой в конце цикла i = 1: Found = False Do If X(i) = pat Then Found = True Else: i = i + 1 End If Loop Until Found Or (i = Size + 1) If Found Then Debug.Print "Найден образец!" Else: Debug.Print "Образец не найден!" End If 'Поиск с барьером ReDim Preserve X(1 To Size + 1) X(Size + 1) = pat i = 1 Do If X(i) = pat Then Exit Do i = i + 1 Loop If i = Size + 1 Then Debug.Print "Образец не найден!" Else: Debug.Print "Образец найден!" End If End Sub
Повторяет выполнение последовательности операторов, пока заданное условие не станет ложным.
Синтаксис:
While условие тело цикла Wend
Здесь условие и тело цикла такие же, как и для цикла Do…Loop. Только для этого вида цикла не предусмотрен оператор выхода Exit. Фактически цикл While…Wend - частный случай цикла Do…Loop - оставлен в языке для совместимости с предыдущими версиями.
Повторяет заданную последовательность операторов для каждого элемента массива или набора.
Синтаксис:
For Each элемент In группа тело цикла Next [элемент]
Здесь элемент - переменная, которая пробегает в качестве значений элементы коллекций или массива. Для коллекций элемент может быть переменной типа Variant, переменной типа Object или переменной (объектом) некоторого класса. В случае цикла по массиву элемент обязан быть переменной типа Variant. Группа - это имя набора объектов (чаще всего это коллекция объектов) или массива, для элементов которых выполняется цикл. Цикл не применим для массивов, тип элементов которых определен пользователем, так как такие элементы не могут быть значениями переменной типа Variant. В таких массивах можно использовать цикл вида For … Next. Тело цикла - последовательность операторов, выполняемая для каждого элемента набора или массива, - может содержать операторы Exit For, позволяющие прервать выполнение цикла и передать управление оператору, следующему за Next (обычно такой выход происходит при выполнении некоторого условия, проверяемого в операторе If…Then…Else ). Указывать переменную элемент после ключевого слова Next не обязательно, но желательно.
Примеры.
В примере создается коллекция, число элементов которой и сами элементы выбираются случайным образом. Затем эта коллекция копируется в For …Each прекрасно работают в подобных ситуациях:
Public Sub ForEach1() Dim X As New Collection Dim Y() As Integer Dim item As Variant Dim i As Integer, Size As Integer 'Инициализация коллекции Randomize Size = Int(21 * Rnd) For i = 1 To Size X.Add Int(11 * Rnd) Next i 'Копирование коллекции в динамический массив Size = 1 For Each item In X ReDim Preserve Y(1 To Size) Y(Size) = item Size = Size + 1 Next item 'Печать элементов динамического массива For Each item In Y Debug.Print item Next item End Sub
Кроме рассмотренных управляющих операторов VBA содержит доставшиеся в наследство от прежних версий GoTo, перехода по метке с возвратом GoSub...Return и условные On...GoSub и On...GoTo. Мы никогда не пользуемся этими операторами.
Операторы этой группы позволяют перемещать текущий каталог (папку) по дискам системы, создавать новые и удалять каталоги (папки): изменять атрибуты файлов, копировать и удалять файлы. Их набор по существу совпадает с набором соответствующих команд операционной системы.
Синтаксис:
ChDrive диск
Обязательный параметр диск - это строка, задающая имя существующего диска, который должен стать текущим, например:
ChDrive "D"
сделает диск "D" текущим.
Синтаксис:
ChDir путь
Обязательный параметр путь - это строковое выражение, значение которого задает новый текущий каталог (папку). Если путь не содержит имени диска, меняется текущий каталог на текущем диске. Подчеркнем, что оператор ChDir меняет текущий каталог (папку), но не диск. Например, если текущим является диск С, команда:
ChDir "D:\TMP"
изменит текущий каталог на диске D, но диск C останется текущим.
Синтаксис:
MkDir путь
Обязательный параметр путь - это строковое выражение, значение которого задает новый создаваемый каталог (папку). Если путь не содержит имени диска, каталог создается на текущем диске. В следующем примере на диске F создаются три новых каталога (папки):
Public Sub Dirs() 'Сделать текущим диск F ChDrive "F" 'Создать 3 каталога на F MkDir "Temp1" MkDir "F:\Temp2" MkDir "F:Temp3" End Sub
Позволяет переименовывать каталоги (папки) и файлы и перемещать файлы.
Синтаксис:
Name СтароеИмя As НовоеИмя
СтароеИмя и НовоеИмя - обязательные параметры, задающие старое и новое имя файла (каталога, папки). Они могут включать имя диска и путь. СтароеИмя должно быть именем существующего файла (каталога, папки), а НовоеИмя не должно быть именем уже существующего объекта. Оба имени должны использовать один и тот же диск. Если указанный новый путь существует и отличается от старого, оператор перемещает файл в новый каталог (папку) и, если требуется, переименовывает его. Каталоги и папки с помощью оператора Name перемещать нельзя, - лишь переименовывать. Перед переименованием файл должен быть закрыт.
В этом примере файл переименовывается, а затем и перемещается в другой каталог:
Public Sub DirsAndFiles() 'Сделать текущим диск F ChDrive "F" 'Переименование файла Name "Exam1E.xls" As "Example1.xls" 'Перемещение файла Name "Example1.xls" As "Temp1\Example1.xls" End Sub
Синтаксис:
RmDir путь
Аргумент путь - строковое выражение, задающее удаляемый каталог или папку. Нельзя удалять каталог или папку, содержащие файлы (иначе будет выдано сообщение об ошибке). Чтобы удалить все файлы из каталога (папки), используйте оператор Kill.
RmDir "Temp3"
удалит папку Temp3 с текущего диска.
Синтаксис:
SetAttr имяфайла, атрибуты
Первый параметр имяфайла - строковое выражение, задающее имя файла, у которого требуется изменить атрибуты. Оно может включать имя диска и путь по каталогам (папкам). Параметр атрибуты - константа или числовое выражение, определяющее новые атрибуты файла в соответствии с таблицей:
| Имя константы | Значение | Описание |
|---|---|---|
VbNormal |
0 | Нормальный (по умолчанию) |
vbReadOnly |
1 | Только для чтения |
VbHidden |
2 | Скрытый |
VbSystem |
4 | Системный файл |
VbArchive |
32 | Файл изменен со времени последнего создания резервной копии |
Нельзя менять атрибуты открытого файла (иначе будет выдано сообщение об ошибке).
Синтаксис:
FileCopy файл-источник, файл-результат
Параметр файл-источник - строковое выражение, задающее имя копируемого файла, Файл-результат - строковое выражение, которое определяет имя результирующего файла. Оба имени могут включать имена дисков, каталогов или папок. Открытый в данный момент файл копировать нельзя.
Пример:
'Копирование файла FileCopy "Temp1\Example1.xls", "Temp2\Example1.xls"
Синтаксис:
Kill файл
Параметр файл - строковое вырыжение, задающее имя удаляемого файла. Он может включать имя диска и путь по каталогам или папкам. Для удаления нескольких файлов можно использовать в образце имени файла символ '*' для обозначения произвольной последовательности букв и '?' - для обозначения одного символа. Нельзя удалять открытый в данный момент файл.
Пример.
Допустим, в текущем каталоге находятся файлы PROG.DOC, PROG.CPP и PROG.OBJ. Тогда оператор:
Kill "PROG.*"
удалит эти файлы с диска.
И еще несколько полезных операторов VBA, не попавших ни в одну из предыдущих групп.
Если в одном блоке программы предстоит выполнить несколько операций с одним объектом, то, чтобы не повторять многократно имя этого объекта, можно ввести оператор With.
Синтаксис:
With объект [операторы] End With
Здесь объект - имя объекта или переменной, определенного пользователем типа, а операторы - последовательность операторов, которые могут действовать с указанным объектом. В этих операторах имена свойств и методов указанного объекта можно начинать с точки, опуская имя самого объекта.
Допустим, пользовательский тип Person и переменная MyFriend определены так.
Type Person Name As String Age As Integer Height As Single End Type Dim MyFriend As Person
Тогда присвоение значений свойствам переменной MyFriend можно произвести с помощью оператора With:
With MyFriend Name = "Сергей" Age= 35 .Height = 178.5 End With
Подчеркнем, что в каждом блоке имя лишь одного объекта задается по умолчанию. При вложенности операторов With:
With объект1 операторы1 With объект2 операторы2 End With End With
в блоке операторы2 имя объекта1 нужно указывать полностью. Если же объект2 - элемент (подобъект) объекта1, то, использовав оператор With объект2, можно получить во внутреннем блоке сокращенный доступ к свойствам объекта " объект1. объект2 ".
Например, если к типу Person добавить данные о встрече:
Type Meeting Place As String Date As Date End Type Type Person Name As String Age As Integer Height As Single LastMeeting As Meeting End Type Dim NewAcquaintance As Person
то задавать данные о новом знакомом NewAcquaintance можно, используя вложенные операторы With.
With NewAcquaintance .Name = "Елена" .Age= 40 .Height = 168 With.LastMeeting .Place= "библиотека" 'этот оператор эквивалентен: 'NewAcquaintance. LastMeeting.Place="библиотека" .Date= #08/03/99# End With End With
Подает звуковой сигнал через динамик компьютера.
Синтаксис:
Beep
Частота и сила звука зависят от оборудования и могут меняться от компьютера к компьютеру. Обычно звуковой сигнал используется как реакция на какие-либо ошибки или исключительные ситуации, возникающие при выполнении программы.
Синтаксис:
Date = дата
Пример:
Date = #April 29, 1999# ' Изменение системной даты.
Синтаксис оператора Time:
Time = время
Пример:
Time = #8:15:47 PM# ' Установка системного времени
Посылает один или несколько кодов символов в текущее активное окно, как если бы соответствующие клавиши были нажаты.
Синтаксис:
SendKeys строка[, режим-ожидания]
Параметр строка - строковое выражение, задающее последовательность посылаемых символов. Необязательный параметр режим-ожидания - выражение с булевым значением. Если оно False (по умолчанию), управление возвращается в процедуру сразу же после посылки кодов; True - посланная последовательность кодов должна быть обработана, прежде чем управление возвратится в процедуру.
Большинство символов, набираемых на клавиатуре, входят в строку непосредственно. Например, чтобы послать последовательность из трех символов Y, E и S, возьмите в качестве строки " YES ". Символы: +, ^, %, ~, скобки и некоторые другие следует помещать в фигурные скобки. Например, чтобы послать +, в параметр строка нужно поместить {+}. Для посылки кодов клавиш, не отображаемых на экране, имеются специальные коды. Некоторые представлены в таблице, остальные можно найти с помощью подсказки:
| Клавиша | Код |
|---|---|
| BACKSPACE | {BS} |
| BREAK | {BREAK} |
| {CAPSLOCK} | |
| DEL | {DEL} |
| DOWN ARROW | {DOWN} |
| END | {END} |
| ENTER | {ENTER} или ~ |
| ESC | {ESC} |
| HOME | {HOME} |
| INS | {INS} |
| {LEFT} | |
| PAGE DOWN | {PGDN} |
| PAGE UP | {PGUP} |
| RIGHT ARROW | {RIGHT} |
| TAB | {TAB} |
| UP ARROW | {UP} |
| Fn | {Fn} (n=1,…, 12) |
Чтобы послать комбинацию клавиш, для Shift, Ctrl и Alt используются следующие коды (В примере используется документ DocTwo7:
Shift - + Ctrl ^ Alt %
Пример:
В качестве примера рассмотрим открытие документа, требующего пароль при его открытии:
Public Sub OpenDocWithPassword()
'Открытие документа с паролем
SendKeys "+^" 'Переключение раскладки клавиатуры
SendKeys "don" "{'}" "t know", False 'пароль "don't know"
Documents.Open "e:\O2000\CD2000\Ch7\DocTwo7.doc"
Documents("DocTwo7.doc").Activate
End Sub
Обратите внимание на два момента:
Open предшествовал оператору SendKeys, то окно ввода пароля появилось бы до выполнения этого оператора. В данном же случае при открытии документа пароль автоматически появится в окне ввода, так что останется только щелкнуть по кнопке OK.Программный код большинства примеров данной лекции можно найти в проектах, доступных для просмотра: DocOne7, DocTwo7.
Большая часть материала этой и последующих лекций носит справочный характер. Для программистов, хорошо знакомых с VBA по предыдущим версиям, вполне достаточно беглого просмотра их содержания. Они будут обращаться к этим лекциям по мере необходимости. Конечно, для тех, кто впервые знакомится с этим языком, чтение этой и последующих лекций не только полезно, но и может предшествовать чтению предыдущих лекций, предполагающих хорошее знание основ языка VBA.
VBA - операторный язык. Это значит, что его программы (модули) представляют последовательности операторов. Набор операторов VBA весьма обширен и не уступает в этом "большим" языкам вроде Паскаля и С. Группу декларативных операторов VBA, служащих для описания объектов, с которыми работает программа (типов, переменных, констант, объектов приложений и др.), мы уже рассмотрели. Операторы другой группы обеспечивают присвоение и изменение значений этих объектов, операторы третьей группы управляют ходом вычислений, четвертой - работой с каталогами и файлами и т.д. Часть операторов досталась VBA в наследство от предыдущих версий Бейсика и без них вполне можно обойтись при написании новых программ.
При записи текста программ для упрощения чтения, отладки и модификации программы удобней каждый оператор располагать в отдельной строке текста. Следуйте правилу: "Один оператор - одна строка". Но, разрешается размещать на строке и несколько операторов, в отличие от общепринятого символа разделения операторов "точки с запятой", в VBA символом разделения двух операторов в одной строке служит двоеточие. Заметьте, некоторые операторы, например оператор If, могут стоять лишь на первом месте в строке. И по этой причине каждый оператор, как правило, следует начинать с новой строки, лишь иногда, разумно, группу операторов присваивания размещать в одной строке. Чаще возникает другая ситуация, - оператор слишком длинный и его текст не виден полностью на экране дисплея, что затрудняет чтение и понимание программы. В этом случае оператор следует продолжить в одной или нескольких строках. Чтобы продолжить (перенести) оператор на следующую строку, используется пара символов пробел-подчеркивание " _ ". Например,
MyAddress = "дом: " Number "улица: " Street _ "город: " City
Перед оператором в строке может стоять метка - последовательность символов, начинающаяся с буквы и кончающаяся двоеточием " :". Метки можно размещать и в отдельных строках перед теми операторами, которые они должны помечать. Они нужны для GoTo, использование которых считается "дурным тоном" в структурном программировании. Но иногда без меток и переходов на них обойтись трудно - в частности, для указания входов в обработчики ошибок в некоторых процедурах.
Комментарии на исполнение программы не влияют, но необходимы как признак "хорошего стиля". Офисные программы используются многократно и не раз модернизируются в процессе своей жизни. Вы можете сэкономить на комментариях и написать и отладить небольшой модуль без них. Но уже через неделю никто, в том числе и автор, не сможет понять его действие и модифицировать нужным образом. Затраченные на это усилия и время намного превзойдут "экономию". Любая строка текста программы может заканчиваться комментарием. Комментарий в VBA начинается апострофом (') и включает любой текст, расположенный правее в строке. Обычно в комментариях описывают задачи, решаемые модулями, функции, выполняемые процедурами, смысл основных переменных (если он неясен из имен), алгоритмы работы процедур. Полезно также комментировать операторы вызовов внешних для данного модуля процедур, объясняя их действия.
Другое применение комментарии находят при отладке программ. Если требуется исключить из программы некоторые операторы (например, вызовы еще не реализованных или сомнительных процедур), достаточно перед ними поместить апостроф. Например, при выполнении последовательности операторов
x=x+z 'z=fun(z,x) y=y*x
функция fun для вычисления нового значения z во второй строке не вызывается и не мешает проверить правильность значения y.
В VBA имеется еще один способ выделения комментариев с помощью ключевого слова Rem. Такой комментарий (в отличие от комментария, начинающегося апострофом) должен отделяться от предыдущего оператора в строке двоеточием:
weight= weight+z: Rem Увеличение веса value=weight*price 'Новая стоимость
При отладке VBA программ часто приходится временно комментировать целые участки текста, иногда страницы текста. В этом случае закомментировать или снять комментарии довольно утомительное дело. В этих случаях следует пользоваться двумя полезными командами меню Edit: "Comment Block" и "UnComment Block". Они позволяют автоматически закомментировать или снять комментарий с выделенного блока. Я всегда использую настройку (Customize) и выношу на панель редактора
Операторы присваивания - основное средство изменения состояния программы (значений переменных и свойств объектов). Мы уже многократно использовали их в примерах из предыдущих лекций. В VBA несколько видов операторов присваивания.
С помощью этого оператора происходит "обычное" присвоение значения выражения переменной или свойству.
Синтаксис:
[Let] переменная = выражение
Ключевое слово Let, как правило, опускается. Переменная является именем переменной или свойства; выражение задает значение, присваиваемое переменной. Его тип должен соответствовать типу переменной. Нарушение этого условия, например, при попытке присвоить числовой переменной строковое значение, приводит к тому, что при компиляции появится сообщение об ошибке. Переменным типа Variant можно присваивать значения разных типов, например, строковых или числовых выражений. Строковой переменной можно присваивать любое значение типа Variant, кроме Null. Числовой же переменной значение типа Variant можно присвоить, только если оно может быть преобразовано к числу.
Оператор Let можно применять для присвоения одной переменной типа "запись" значения другой такой переменной. Заметьте, это возможно только, если обе они - переменные одного определенного пользователем типа.
Примеры:
Public Sub Assign1() Dim MyStr As String, MyInt As Integer Let MyStr = "Здравствуй, зайчик!" ' С ключевым словом Let MyInt = 5 ' Без него. Обычный вариант. Debug.Print MyStr, MyInt End Sub
Этот оператор служит для присвоения строк с одновременным выравниванием слева, а также для копирования записи одного определенного пользователем типа в запись другого типа. Его синтаксис:
Lset СтрПеременная = СтрВыражение Lset переменная1 = переменная2
Здесь ключевое слово LSet обязательно, СтрПеременная - имя строковой переменной, СтрВыражение - выражение строкового типа. Во втором варианте переменная1 - имя переменной некоторого определенного пользователем типа, в которую выполняется копирование, переменная2 - имя переменной, возможно, другого пользовательского типа, значение которой копируется.
Результатом присвоения строк всегда является строка той же длины, что и у СтрПеременная. Если при этом СтрВыражение короче, добавляются пробелы справа; длиннее - лишние символы справа удаляются.
При втором варианте оператора двоичное представление записи из участка памяти, отведенного переменной2 копируется в участок памяти, отведенный переменной1, - При этом данные не преобразуются в соответствии с типами элементов (полей) записи, и если типы соответствующих элементов обеих записей не совпадают, результат операции трудно предсказать (часто выдается сообщение о несоответствии типов). Поэтому этот вариант следует использовать, лишь тогда, когда типы всех соответствующих элементов записей совпадают и имеют одинаковый размер.
Примеры.
Public Sub Assign2() Dim Str1 As String, Str2 As String Str1 = "0123456789" ' Начальное значение Str2 = "abcd" Debug.Print Str1, Str2 LSet Str2 = Str1 ' Результат - "0123" LSet Str1 = " Влево" ' Результат - " Влево Debug.Print Str1, Str2 End Sub"
Вот результаты отладочной печати:
0123456789 abcd Влево 0123
В следующем примере происходит корректное копирование одной записи в другую; типы соответствующих элементов в определенных пользователем типах MyType1 и MyType2 совпадают:
Type MyType1 age As Integer cost As Long End Type Type MyType2 year As Integer pay As Long 'pay As Integer End Type Public Sub Assign3() Dim my1 As MyType1 Dim my2 As MyType2 my1.age = 50 my1.cost = 45666 my2.year = 1997 my2.pay = 22000 Debug.Print my1.age, my1.cost, my2.pay, my2.year LSet my2 = my1 ' после этого присвоения my2.year=50 и my2.pay=45666 Debug.Print my1.age, my1.cost, my2.pay, my2.year End Sub
Вот результаты отладочной печати:
50 45666 22000 1997 50 45666 45666 50
Если изменить тип элемента pay в MyType2 на Integer, то будет напечатано значение my2.pay, равное 0.
Этот оператор присваивает значение строковой переменной с выравниванием справа:
RSet СтрПеременная = СтрВыражение
СтрПеременная - имя строковой переменной, СтрВыражение - выражение строкового типа. В отличие от LSet оператор RSet нельзя использовать для копирования переменных записей. Результатом присвоения строк всегда является строка той же длины, что и СтрПеременная. Если при этом СтрВыражение короче, добавляются пробелы слева, длиннее - лишние символы слева удаляются.
Примеры:
Public Sub Assign4() Dim Str1, Str2, Str3 Str1 = "0123456789" ' Начальное значение Str2 = "abcd" Debug.Print Str1, Str2 RSet Str2 = Str1 ' Результат - "0123" RSet Str1 = "Вправо " ' Результат - " Вправо " RSet Str3 = Str1 ' Результат - пустая строка "" Debug.Print Str1, Str2, Str3 End Sub
Вот результаты отладочной печати:
0123456789 abcd Вправо 0123
Этот оператор применим при работе с объектами, устанавливает ссылку на вновь созданный или существующий объект. Его синтаксис:
Set ОбПеременная = {[New] ОбВыражение| Nothing}
ОбПеременная - имя переменной или свойства, New - необязательное ключевое слово, используемое для явного вызова операции создания нового экземпляра класса (объекта). Если ОбПеременная содержала ссылку на объект, при присвоении эта ссылка освободится. ОбВыражение может быть именем объекта (класса), другой переменной того же типа, функцией или методом, возвращающими объект соответствующего типа. Выполнение оператора Set с правой частью Nothing прерывает связь между ОбПеременной и объектом, на который она ссылалась. Если при этом на него не осталось других ссылок, ресурсы системы и память, выделенные под этот объект, освобождаются. В общем случае, если ключевое слово New не указано, новая копия объекта не создается, а ОбПеременная как значение получает ссылку на существующий объект. При этом может оказаться, что несколько переменных ссылаются на один объект и изменение этого объекта через одну из них влияет на все остальные.
Примеры:
Определим класс объектов Child:
'Класс Child 'Свойства Public Age As Byte Public Name As String 'Другие свойства и методы пока не определены
А теперь введем объекты этого класса:
Public Sub Assign5() Dim Children(1 To 2) As Child Dim Boy As Child, Girl As Child 'Создаем объекты Set Children(1) = New Child Set Children(2) = New Child 'Инициализируем их Children(1).Age = 10 Children(1).Name = "Александр" Children(2).Age = 7 Children(2).Name = "Мария" Debug.Print "Имя: ", Children(1).Name, "Возраст: ", Children(1).Age Debug.Print "Имя: ", Children(2).Name, "Возраст: ", Children(2).Age 'Утанавливаем дополнительные ссылки на существующие объекты Set Boy = Children(1) Set Girl = Children(2) Boy.Name = "Саша" Girl.Name = "Маша" 'Изменились сввойства объектов Debug.Print "Имя: ", Children(1).Name, "Возраст: ", Children(1).Age Debug.Print "Имя: ", Children(2).Name, "Возраст: ", Children(2).Age 'Удаляем одну из ссылок, но объект остается Set Children(1) = Nothing Set Children(2) = Nothing Debug.Print "Имя: ", Boy.Name, "Возраст: ", Boy.Age Debug.Print "Имя: ", Girl.Name, "Возраст: ", Girl.Age End Sub
Вот результаты отладочной печати:
Имя: Александр Возраст: 10 Имя: Мария Возраст: 7 Имя: Саша Возраст: 10 Имя: Маша Возраст: 7 Имя: Саша Возраст: 10 Имя: Маша Возраст: 7
Набор управляющих операторов VBA делает честь любому хорошо If и оператор разбора случаев Case - все эти средства позволяют организовать процесс вычислений надежно и эффективно в соответствии с лучшими традициями программирования.
Это общепринятый в языках программирования
Синтаксис.
Имеется два варианта синтаксиса: в одну строку и в форме блока. В первом случае он имеет вид:
If условие Then [операторы1] [Else операторы2 ]
Во втором случае оператор расположен на нескольких строках:
If условие Then [операторы] [ElseIf условие-n Then [операторы-n]... [Else [ИначеОператоры]] End If
Здесь условие обязательно в обоих вариантах. Оно может быть числовым или строковым выражением со значениями True или False ( Null трактуется как False ). В качестве условия можно использовать и выражение вида TypeOf ИмяОбъекта Is ТипОбъекта, где ИмяОбъекта - ссылка на объект, а ТипОбъекта - произвольный корректный тип объекта. Операторы1 и операторы2 - это последовательности из одного или нескольких разделенных двоеточием операторов. По крайней мере, одна из этих последовательностей должна быть непустой. Если условие истинно ( True ), выполняется последовательность операторы1, ложно ( False ) - операторы2. Форма условного оператора определяется по наличию в строке, начинающейся If условие Then, текста после Then, отличного от комментария. Если такой текст есть, считается, что использована форма в одну строку, нет - оператор должен иметь форму блока. В этом случае подблоки вида:
[ElseIf условие-n Then [операторы-n]
могут отсутствовать либо повторяться несколько раз; подблок:
[Else [ИначеОператоры]]
также необязателен, а закрывающий оператор End If необходим. По крайней мере одна из последовательностей операторы, операторы-n … или ИначеОператоры должна быть непустой. Если условие истинно, выполняются операторы, нет - отыскивается первое истинное условие-n, и выполняются операторы-n. Если все эти условия ложны, выполняются ИначеОператоры. После выполнения одной (возможно, пустой) последовательности End If.
Примеры:
Public Sub MinMax1(ByVal X As Integer, ByVal Y As Integer, _ Min As Integer, Max As Integer) 'Оператор If в одну строку If X > Y Then Max = X: Min = Y Else Max = Y: Min = X End Sub Public Sub MinMax2(ByVal X As Integer, ByVal Y As Integer, _ Min As Integer, Max As Integer) 'Оператор If в виде блока If X > Y Then Max = X Min = Y Else Max = Y Min = X End If End Sub Public Sub If1() Dim Max As Integer, Min As Integer Call MinMax1(2 + 3, 2 * 3, Min, Max) Debug.Print Max, Min Call MinMax2(2 + 3, 2 * 3, Min, Max) Debug.Print Max, Min End Sub
По-видимому, можно было бы классифицировать программистов в зависимости от того, какая из форм записи процедуры MinMax кажется им предпочтительнее при записи и при чтении. Приведем еще один пример, где идет работа с объектами. Вначале добавим еще один класс объектов:
'Класс Man 'Свойства Public Age As Byte Public Name As String 'Другие свойства и методы пока не определены
А теперь приведем процедуру, в которой будем работать с объектами класса Child и Man. Заметьте, в условии оператора IF проверяется тип объекта:
Public Sub BoyOrMan()
Dim Boy As New Child
Dim Person As New Man
Dim SomeBody As Object
Dim Answer As Integer
Boy.Age = 10: Boy.Name = "Александр"
Person.Age = 21: Person.Name = "Александр"
Answer = InputBox("Введите число от 10 до 20", "Возраст", 15)
If Answer > 15 Then
Set SomeBody = Person
Else: Set SomeBody = Boy
End If
If TypeOf SomeBody Is Child Then
Debug.Print "Это мальчик!"
ElseIf TypeOf SomeBody Is Man Then
Debug.Print "Это Мужчина"
Else
Debug.Print "Не знаю, кто это"
End If
End Sub
Результат ее работы зависит от того, какой возраст Вы введете в окне ввода.
Этот оператор производит разбор случаев и в зависимости от значения анализируемого выражения выбирает и исполняет одну из последовательностей операторов.
Синтаксис.
Select Case Выражение-тест [Case СписокВыражений-n [операторы-n]] [Case Else [ИначеОператоры]] End Select
Выражение-тест должно присутствовать обязательно. Оно может быть произвольным выражением с числовым или строковым значением. СписокВыражений-n должен присутствовать в строке, начинающейся ключевым словом Case (Случай). Выражения в этом списке отделяются запятыми и могут иметь одну из форм:
выражение,выражение-нижняя-граница To выражение-верхняя-граница,Is оператор-сравнения выражение.Первая форма задает отдельные значения, вторая и третья позволяют задавать сразу целые диапазоны (области) значений. Последовательность операторов операторы-n необязательна. Она будет исполнена, если соответствующий СписокВыражений-n является первым списком, сопоставимым с текущим значением Выражения-теста (т. е. он явно содержит это значение, либо оно попадает в один из заданных в списке диапазонов). После исполнения операторов последовательности операторы-n проверка на соответствие другим спискам выражений не производится, и управление передается на оператор, следующий за End Select. Необязательная последовательность ЕслиОператоры выполняется, если ни один из списков выражений несопоставим со значением Выражения-теста.
Пример:
Public Sub Case1()
Dim Before As Integer
Dim CurrentYear As Integer, Str As String
' Инициализация переменных:
CurrentYear = 1999
Before = InputBox("Сколько лет тому назад?", "Когда", 10)
Select Case CurrentYear - Before
Case 1954 To 1969, 1971 To 1974, 1982, Is < 1970
Str = " Годы учебы"
Case 1972 To 1989
Str = "Годы воспитания"
Case Else
Str = "Прочие годы"
End Select
Debug.Print Str
End Sub
Здесь, если перед выполнением выбора Before = 20, значением тестового выражения будет 1979, и будет работать второй вариант (" Годы воспитания "). При Before = 25 значение 1974 сопоставимо с двумя списками, но для исполнения будет выбран лишь первый вариант (" Годы учебы ").
Диапазоны значений можно задавать и для строк. При этом их значения считаются упорядоченными лексикографически. Например, возможен такой список выражений:
Case "everything", "nuts" To "soup"
Задаваемое им множество строк включает строку " everything " и все строки от " nuts " до " soup " (например, " onion ").
Позволяет повторять группу операторов заданное число раз.
Синтаксис:
For счетчик_цикла = начало To конец [Step шаг] тело цикла Next [счетчик_цикла]
Здесь счетчик_цикла - это числовая переменная. В начале выполнения цикла она принимает значение, задаваемое числовым выражением начало. (Переменная счетчик_цикла не может иметь тип Boolean или быть элементом массива.) Числовое выражение конец задает заключительное значение счетчика цикла. Оно вычисляется до начала исполнения тела цикла и не меняется, даже если входящие в него переменные изменяют в теле цикла свои значения. Числовое выражение шаг необязательно. Его значение также вычисляется в начале цикла и прибавляется к счетчику цикла всякий раз, когда завершается выполнение тела цикла и вычисление достигает строки Next [счетчик_цикла]. Если шаг цикла явно не указан, по умолчанию он равен 1. тело цикла - это последовательность операторов, которая будет выполнена заданное число раз. При каком значении переменной счетчик_цикла происходит завершение цикла, зависит от знака параметра шаг. Если шаг положителен, цикл завершится, когда впервые выполнится условие:
счетчик_цикла > конец
Если шаг цикла отрицателен, условие его завершения:
счетчик_цикла < конец
Это условие проверяется перед началом выполнения цикла, а затем - после каждого прибавления шага к счетчику цикла в операторе Next. Если оно выполнено, управление передается на оператор, следующий за Next, нет - выполняются операторы из тела цикла. Завершить цикл For … Next можно и с помощью оператора Exit For. Такие операторы могут быть расположены в тех местах тела цикла, где требуется из него выйти, не дожидаясь выполнения условия завершения.
Примеры.
В нашем примере три вложенных цикла For … Next использованы для вычисления произведения двух целочисленных матриц, инициализированных случайными числами. Затем результирующая матрица проверяется на наличие в ней нулевого значения:
Public Sub For1() Dim A(1 To 5, 1 To 5) As Integer Dim B(1 To 5, 1 To 5) As Integer Dim C(1 To 5, 1 To 5) As Integer Dim I As Integer, J As Integer, K As Integer Dim Res As String ' Инициализация матриц A и B случайными числами в интервале [-10, +10] VBA.Randomize For I = 1 To 5 For J = 1 To 5 'Получение случайного числа Rnd и преобразование в целое A(I, J) = Int(21 * Rnd) - 10 Next J Next I For I = 1 To 5 For J = 1 To 5 B(I, J) = Int(21 * Rnd) - 10 Next J Next I 'Вычисление произведения матриц For I = 1 To 5 For J = 1 To 5 C(I, J) = 0 For K = 1 To 5 C(I, J) = C(I, J) + A(I, K) * B(K, J) Next K Next J Next I Res = "No" C(2, 2) = 0 'Проверка на нулевое значение For I = 1 To 5 For J = 1 To 5 If C(I, J) = 0 Then Debug.Print "Индексы: ", I, J Res = "Yes" Exit For End If Next J Next I Debug.Print Res End Sub
Обратите внимание, оператор выхода Exit For прекращает выполнение только внутреннего цикла, так что проверка на ноль будет осуществляться в каждой строке матрицы, независимо от существования нулей в предыдущих строках. Сделаем еще несколько замечаний по поводу оператора For Next:
Next можно не указывать имя переменной, задающей счетчик, это имя подразумевается по умолчанию, как завершающее последний открытый оператор For. Однако и эту возможность не следует использовать. Рекомендуем всегда явно указывать имя счетчика в операторе Next.Public Sub For2() Dim A(1 To 5) As Integer Dim i As Integer For i = 5 To 1 Step -1 A(i) = i i = i + 1 Next i End Sub
Обычно попытка изменить значение счетчика цикла в его теле означает, что вместо цикла For…Next следовало бы применить цикл другого вида, например Do…Loop.
Повторяет блок операторов, пока заданное условие является истинным или пока оно не станет истинным.
Синтаксис:
Имеется четыре варианта синтаксиса этого цикла. В двух первых вариантах условие проверяется в начале цикла:
Do [{While | Until} условие]
тело цикла
Loop
В других двух вариантах условие проверяется в конце цикла:
Do
тело цикла
Loop [{While | Until} условие]
Здесь условие является числовым или строковым выражением со значениями True или False. Вообще оно необязательно. Значение Null условия трактуется как False. Тело цикла - это последовательность операторов, которая будет выполняться, пока условие остается истинным, если перед ним стоит ключевое слово While или пока оно остается ложным - в Until. Таким образом, циклы вида While условие эквивалентны циклам вида Until Not условие. Кроме того, в тело цикла может входить оператор Exit Do, выполнение которого сразу прекращает цикл и передает управление оператору, непосредственно следующему за Loop. В случае нескольких вложенных циклов Do … Loop оператор Exit Do завершает лишь самый внутренний цикл, в теле которого он расположен.
Примеры.
В нашем примере реализованы три варианта поиска по образцу с проверкой условия в начале цикла, в конце цикла и в середине цикла для варианта поиска по образцу с барьером:
Public Sub Loop1() Const Size = 5 Dim X() As Integer Dim i As Integer Dim Found As Boolean Const pat = 7 'Инициализация случайными числами в интервале [1 - 10] ReDim X(1 To Size) Randomize For i = 1 To Size X(i) = Int(11 * Rnd) Next i 'Поиск по образцу с проверкой в начале цикла i = 1: Found = False Do While (i <= Size) And (Not Found) If X(i) = pat Then Found = True Else: i = i + 1 End If Loop If Found Then Debug.Print "Найден образец!" Else: Debug.Print "Образец не найден!" End If 'Поиск по образцу с проверкой в конце цикла i = 1: Found = False Do If X(i) = pat Then Found = True Else: i = i + 1 End If Loop Until Found Or (i = Size + 1) If Found Then Debug.Print "Найден образец!" Else: Debug.Print "Образец не найден!" End If 'Поиск с барьером ReDim Preserve X(1 To Size + 1) X(Size + 1) = pat i = 1 Do If X(i) = pat Then Exit Do i = i + 1 Loop If i = Size + 1 Then Debug.Print "Образец не найден!" Else: Debug.Print "Образец найден!" End If End Sub
Повторяет выполнение последовательности операторов, пока заданное условие не станет ложным.
Синтаксис:
While условие тело цикла Wend
Здесь условие и тело цикла такие же, как и для цикла Do…Loop. Только для этого вида цикла не предусмотрен оператор выхода Exit. Фактически цикл While…Wend - частный случай цикла Do…Loop - оставлен в языке для совместимости с предыдущими версиями.
Повторяет заданную последовательность операторов для каждого элемента массива или набора.
Синтаксис:
For Each элемент In группа тело цикла Next [элемент]
Здесь элемент - переменная, которая пробегает в качестве значений элементы коллекций или массива. Для коллекций элемент может быть переменной типа Variant, переменной типа Object или переменной (объектом) некоторого класса. В случае цикла по массиву элемент обязан быть переменной типа Variant. Группа - это имя набора объектов (чаще всего это коллекция объектов) или массива, для элементов которых выполняется цикл. Цикл не применим для массивов, тип элементов которых определен пользователем, так как такие элементы не могут быть значениями переменной типа Variant. В таких массивах можно использовать цикл вида For … Next. Тело цикла - последовательность операторов, выполняемая для каждого элемента набора или массива, - может содержать операторы Exit For, позволяющие прервать выполнение цикла и передать управление оператору, следующему за Next (обычно такой выход происходит при выполнении некоторого условия, проверяемого в операторе If…Then…Else ). Указывать переменную элемент после ключевого слова Next не обязательно, но желательно.
Примеры.
В примере создается коллекция, число элементов которой и сами элементы выбираются случайным образом. Затем эта коллекция копируется в For …Each прекрасно работают в подобных ситуациях:
Public Sub ForEach1() Dim X As New Collection Dim Y() As Integer Dim item As Variant Dim i As Integer, Size As Integer 'Инициализация коллекции Randomize Size = Int(21 * Rnd) For i = 1 To Size X.Add Int(11 * Rnd) Next i 'Копирование коллекции в динамический массив Size = 1 For Each item In X ReDim Preserve Y(1 To Size) Y(Size) = item Size = Size + 1 Next item 'Печать элементов динамического массива For Each item In Y Debug.Print item Next item End Sub
Кроме рассмотренных управляющих операторов VBA содержит доставшиеся в наследство от прежних версий GoTo, перехода по метке с возвратом GoSub...Return и условные On...GoSub и On...GoTo. Мы никогда не пользуемся этими операторами.
Операторы этой группы позволяют перемещать текущий каталог (папку) по дискам системы, создавать новые и удалять каталоги (папки): изменять атрибуты файлов, копировать и удалять файлы. Их набор по существу совпадает с набором соответствующих команд операционной системы.
Синтаксис:
ChDrive диск
Обязательный параметр диск - это строка, задающая имя существующего диска, который должен стать текущим, например:
ChDrive "D"
сделает диск "D" текущим.
Синтаксис:
ChDir путь
Обязательный параметр путь - это строковое выражение, значение которого задает новый текущий каталог (папку). Если путь не содержит имени диска, меняется текущий каталог на текущем диске. Подчеркнем, что оператор ChDir меняет текущий каталог (папку), но не диск. Например, если текущим является диск С, команда:
ChDir "D:\TMP"
изменит текущий каталог на диске D, но диск C останется текущим.
Синтаксис:
MkDir путь
Обязательный параметр путь - это строковое выражение, значение которого задает новый создаваемый каталог (папку). Если путь не содержит имени диска, каталог создается на текущем диске. В следующем примере на диске F создаются три новых каталога (папки):
Public Sub Dirs() 'Сделать текущим диск F ChDrive "F" 'Создать 3 каталога на F MkDir "Temp1" MkDir "F:\Temp2" MkDir "F:Temp3" End Sub
Позволяет переименовывать каталоги (папки) и файлы и перемещать файлы.
Синтаксис:
Name СтароеИмя As НовоеИмя
СтароеИмя и НовоеИмя - обязательные параметры, задающие старое и новое имя файла (каталога, папки). Они могут включать имя диска и путь. СтароеИмя должно быть именем существующего файла (каталога, папки), а НовоеИмя не должно быть именем уже существующего объекта. Оба имени должны использовать один и тот же диск. Если указанный новый путь существует и отличается от старого, оператор перемещает файл в новый каталог (папку) и, если требуется, переименовывает его. Каталоги и папки с помощью оператора Name перемещать нельзя, - лишь переименовывать. Перед переименованием файл должен быть закрыт.
В этом примере файл переименовывается, а затем и перемещается в другой каталог:
Public Sub DirsAndFiles() 'Сделать текущим диск F ChDrive "F" 'Переименование файла Name "Exam1E.xls" As "Example1.xls" 'Перемещение файла Name "Example1.xls" As "Temp1\Example1.xls" End Sub
Синтаксис:
RmDir путь
Аргумент путь - строковое выражение, задающее удаляемый каталог или папку. Нельзя удалять каталог или папку, содержащие файлы (иначе будет выдано сообщение об ошибке). Чтобы удалить все файлы из каталога (папки), используйте оператор Kill.
RmDir "Temp3"
удалит папку Temp3 с текущего диска.
Синтаксис:
SetAttr имяфайла, атрибуты
Первый параметр имяфайла - строковое выражение, задающее имя файла, у которого требуется изменить атрибуты. Оно может включать имя диска и путь по каталогам (папкам). Параметр атрибуты - константа или числовое выражение, определяющее новые атрибуты файла в соответствии с таблицей:
| Имя константы | Значение | Описание |
|---|---|---|
VbNormal |
0 | Нормальный (по умолчанию) |
vbReadOnly |
1 | Только для чтения |
VbHidden |
2 | Скрытый |
VbSystem |
4 | Системный файл |
VbArchive |
32 | Файл изменен со времени последнего создания резервной копии |
Нельзя менять атрибуты открытого файла (иначе будет выдано сообщение об ошибке).
Синтаксис:
FileCopy файл-источник, файл-результат
Параметр файл-источник - строковое выражение, задающее имя копируемого файла, Файл-результат - строковое выражение, которое определяет имя результирующего файла. Оба имени могут включать имена дисков, каталогов или папок. Открытый в данный момент файл копировать нельзя.
Пример:
'Копирование файла FileCopy "Temp1\Example1.xls", "Temp2\Example1.xls"
Синтаксис:
Kill файл
Параметр файл - строковое вырыжение, задающее имя удаляемого файла. Он может включать имя диска и путь по каталогам или папкам. Для удаления нескольких файлов можно использовать в образце имени файла символ '*' для обозначения произвольной последовательности букв и '?' - для обозначения одного символа. Нельзя удалять открытый в данный момент файл.
Пример.
Допустим, в текущем каталоге находятся файлы PROG.DOC, PROG.CPP и PROG.OBJ. Тогда оператор:
Kill "PROG.*"
удалит эти файлы с диска.
И еще несколько полезных операторов VBA, не попавших ни в одну из предыдущих групп.
Если в одном блоке программы предстоит выполнить несколько операций с одним объектом, то, чтобы не повторять многократно имя этого объекта, можно ввести оператор With.
Синтаксис:
With объект [операторы] End With
Здесь объект - имя объекта или переменной, определенного пользователем типа, а операторы - последовательность операторов, которые могут действовать с указанным объектом. В этих операторах имена свойств и методов указанного объекта можно начинать с точки, опуская имя самого объекта.
Допустим, пользовательский тип Person и переменная MyFriend определены так.
Type Person Name As String Age As Integer Height As Single End Type Dim MyFriend As Person
Тогда присвоение значений свойствам переменной MyFriend можно произвести с помощью оператора With:
With MyFriend Name = "Сергей" Age= 35 .Height = 178.5 End With
Подчеркнем, что в каждом блоке имя лишь одного объекта задается по умолчанию. При вложенности операторов With:
With объект1 операторы1 With объект2 операторы2 End With End With
в блоке операторы2 имя объекта1 нужно указывать полностью. Если же объект2 - элемент (подобъект) объекта1, то, использовав оператор With объект2, можно получить во внутреннем блоке сокращенный доступ к свойствам объекта " объект1. объект2 ".
Например, если к типу Person добавить данные о встрече:
Type Meeting Place As String Date As Date End Type Type Person Name As String Age As Integer Height As Single LastMeeting As Meeting End Type Dim NewAcquaintance As Person
то задавать данные о новом знакомом NewAcquaintance можно, используя вложенные операторы With.
With NewAcquaintance .Name = "Елена" .Age= 40 .Height = 168 With.LastMeeting .Place= "библиотека" 'этот оператор эквивалентен: 'NewAcquaintance. LastMeeting.Place="библиотека" .Date= #08/03/99# End With End With
Подает звуковой сигнал через динамик компьютера.
Синтаксис:
Beep
Частота и сила звука зависят от оборудования и могут меняться от компьютера к компьютеру. Обычно звуковой сигнал используется как реакция на какие-либо ошибки или исключительные ситуации, возникающие при выполнении программы.
Синтаксис:
Date = дата
Пример:
Date = #April 29, 1999# ' Изменение системной даты.
Синтаксис оператора Time:
Time = время
Пример:
Time = #8:15:47 PM# ' Установка системного времени
Посылает один или несколько кодов символов в текущее активное окно, как если бы соответствующие клавиши были нажаты.
Синтаксис:
SendKeys строка[, режим-ожидания]
Параметр строка - строковое выражение, задающее последовательность посылаемых символов. Необязательный параметр режим-ожидания - выражение с булевым значением. Если оно False (по умолчанию), управление возвращается в процедуру сразу же после посылки кодов; True - посланная последовательность кодов должна быть обработана, прежде чем управление возвратится в процедуру.
Большинство символов, набираемых на клавиатуре, входят в строку непосредственно. Например, чтобы послать последовательность из трех символов Y, E и S, возьмите в качестве строки " YES ". Символы: +, ^, %, ~, скобки и некоторые другие следует помещать в фигурные скобки. Например, чтобы послать +, в параметр строка нужно поместить {+}. Для посылки кодов клавиш, не отображаемых на экране, имеются специальные коды. Некоторые представлены в таблице, остальные можно найти с помощью подсказки:
| Клавиша | Код |
|---|---|
| BACKSPACE | {BS} |
| BREAK | {BREAK} |
| {CAPSLOCK} | |
| DEL | {DEL} |
| DOWN ARROW | {DOWN} |
| END | {END} |
| ENTER | {ENTER} или ~ |
| ESC | {ESC} |
| HOME | {HOME} |
| INS | {INS} |
| {LEFT} | |
| PAGE DOWN | {PGDN} |
| PAGE UP | {PGUP} |
| RIGHT ARROW | {RIGHT} |
| TAB | {TAB} |
| UP ARROW | {UP} |
| Fn | {Fn} (n=1,…, 12) |
Чтобы послать комбинацию клавиш, для Shift, Ctrl и Alt используются следующие коды (В примере используется документ DocTwo7:
Shift - + Ctrl ^ Alt %
Пример:
В качестве примера рассмотрим открытие документа, требующего пароль при его открытии:
Public Sub OpenDocWithPassword()
'Открытие документа с паролем
SendKeys "+^" 'Переключение раскладки клавиатуры
SendKeys "don" "{'}" "t know", False 'пароль "don't know"
Documents.Open "e:\O2000\CD2000\Ch7\DocTwo7.doc"
Documents("DocTwo7.doc").Activate
End Sub
Обратите внимание на два момента:
Open предшествовал оператору SendKeys, то окно ввода пароля появилось бы до выполнения этого оператора. В данном же случае при открытии документа пароль автоматически появится в окне ввода, так что останется только щелкнуть по кнопке OK.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.