Процедуры и функции пользователя

advertisement
8. Процедуры и функции
Предварительно еще раз вернемся к понятию модуля. Чтобы было понято, о чем идет речь,
определимся под модулем понимать определенный блок проекта, принадлежащий какому
либо объекту или существующий независимо. В этом блоке содержатся процедуры и
функции, принадлежащие данному модулю. Так, модулем можно считать блок,
принадлежащий рабочему листу книги (каждому листу свой модуль), книге в целом, можно
вставить «независимый модуль». Также в VBA в наследство от VB существует очень
удобный элемент управления Форма (UserForm). Этот элемент имеет много свойств, схожих
со свойствами командной кнопки, надписи и т.д. Кроме того, одно из важных преимуществ
этого элемента – возможность располагать на нем другие элементы и таким образом
создавать свой интерфейс проекта, независимый от интерфейса приложения. Видимо, по
этой причине в редакторе VBA помимо создания модулей и процедур предусмотрено
создание форм, и они занимают особое место по сравнению с другими стандартными
элементами управления. Формы тоже имеют свои модули. Четкие представления о модуле
позволяют понять взаимное размещение процедур и функций по отношению друг к другу и
способы их взаимодействия. Это, в свою очередь, позволяет понять, какая процедура может
быть вызвана без указания модуля, в котором она находится, какие переменные являются
общими для тех или иных частей проекта и так далее.
Мы уже создавали процедуры в самом простом варианте, но теперь рассмотрим случаи,
когда процедуры могут быть расположены в самых различных модулях, и нам необходимо
определиться, насколько эта процедура будет доступна для других модулей, как должны
вести себя параметры внутри процедуры. Кроме того, при создании процедур необходимо
обращать внимание на поведение переменных используемых внутри процедуры. В ряде
случаев эти переменные нужны только для этой процедуры (внутренние переменные), но в
других ситуациях переменные могут понадобиться и для других процедур. Также важно
определиться, как будут вести себя внутренние переменные процедуры при ее многократном
вызове – либо сохранять предыдущие значения, либо «обнуляться». В обычных ситуациях
эти переменные при каждом вызове процедуры равны нулю.
Посмотрите на синтаксис инструкции, которую мы должны использовать при создании
процедуры
[{Private | Public}] [Static] Sub имя ([список Аргументов])
[инструкции]
[Exit Sub]
[инструкции]
End Sub
Как видите перед ключевым словом Sub можно добавить слова Private или Public, а также
слово Static. Смысл этих элементов представлен в таблице 5
Таблица 5.. Элементы синтаксиса инструкции Sub.
Элемент
Описание
Public
Необязательный. Указывает, что процедура Sub доступна для всех
других процедур во всех модулях.
Private
Необязательный. Указывает, что процедура Sub доступна для
других процедур только того модуля, в котором она описана.
Static
Необязательный. Указывает, что локальные переменные процедуры
Sub сохраняются в промежутках времени между вызовами этой
процедуры. Атрибут Static не действует на переменные, описанные
вне процедуры Sub, даже если они используются в процедуре.
имя
Обязательный. Имя процедуры Sub, удовлетворяющее стандартным
правилам именования переменных.
Список
Необязательный. Список переменных, представляющий аргументы,
Аргументов
Инструкции
которые передаются в процедуру Sub при ее вызове. Имена
переменных разделяются запятой.
Необязательный.
Любая группа инструкций, выполняемых в
процедуре Sub.
Отдельного внимания требует такой параметр как Список Аргументов. Очень часто
процедура работает с какой-либо переменной, числовое значение которой важно для других
процедур, и мало того, именно для обработки ряда внешних переменных используется эта
процедура. Для удобства программирования при написании процедуры эта переменная
может быть обозначена внутри процедуры каким-то своим именем, в то время как в других
процедурах эта переменная может иметь другое имя, хотя значение этой переменной будет
находиться в определенной области памяти, общей для всех процедур. Так вот, список
аргументов позволяет устанавливать правильное соотношение между именами переменных
внутри и вне процедуры, чтобы процедуры «понимали», о какой области памяти идет речь. В
списке аргументов перечисляются те имена переменных, используемые внутри процедуры,
которые должны взять и обрабатывать значения соответствующих переменных из других
процедур.
При этом процедура может изменить числовые значения переменных или, только
воспользовавшись их значениями, не изменять. В первом случае происходит обращение к
переменным по ссылке (как правило), а во втором случае – по значению.
В упрощенном варианте Список Аргументов формируется следующим образом
[ByVal] имяПеременной [As тип]
Необязательный элемент [ByVal] необходимо использовать в том случае, если данную
переменную можно использовать только по значению.
Посмотрите на пример, в котором описывается процедура с двумя внешними переменными
(L, W) и предполагается, что при ее вызове значения этих переменных будут заданы. Внутри
процедуры будет вычислена площадь прямоугольника, сохраненная в во внутренней
переменной Area.
Sub Sq(L, W)
Dim Area As Double
Объявляем локальную переменную.
If L = 0 Or W = 0 Then
Если хотя бы один из аргументов равен 0.
Exit Sub
то процедура немедленно завершается.
End If
Area = L * W ' Вычисляется площадь прямоугольника.
Debug. Print Area ' Выводится полученное значение в окно отладки.
End Sub
Теперь посмотрим, как можно заставить процедуру работать или по другому – вызвать.
Напомним, что некоторые процедуры могут быть вызваны с помощью событий на элементах
управления или на объектах. Чтобы вызвать процедуру Sub из другой процедуры, следует
указать в отдельной строке имя этой процедуры и значения для всех требуемых аргументов.
Возможно, также, использование инструкции Call, после которой вставляется имя
процедуры, и аргументы должны быть заключены в скобки. При подстановке параметров,
которые нужны для работы вызываемой процедуры, следует учитывать, что имена этих
параметров во внешней и в вызываемой процедурах могут не совпадать (вместо имен
параметров можно подставлять числовые значения); важно соблюдать последовательность
перечисления соответствующих параметров.
Так, если нам необходимо вычислить площадь прямоугольника с длиной 50 единиц и
шириной 45, то процедура Sq может быть вызвана следующими способами
Sq 50, 45
Или
Call Sq(50, 45).
Если значения длины и ширины перед вызовом процедуры хранятся в переменных А и В, то
процедуру можно вызвать и так
Sq А, В
Или так
Call Sq(А, В).
Почти такая же инструкция используется для описания функции. Напомним, что отличие
функции от процедуры заключается в том, что функция должна передать в программу,
вызвавшую ее значение одной переменной, и для этого в коде процедуры должна быть
строка, в которой значение этой переменной запоминается под именем функции. Поэтому,
при описании функции, после указания ее имени, можно указать тип переменной, которая
“прячется” под именем этой процедуры.
[Public | Private] [Static] Function имя [(списокАргументов)] [As тип]
[инструкции]
[имя = выражение] – строка передачи значения
[Exit Function]
[инструкции]
[имя = выражение]
End Function
Посмотрите на пример, когда вычисление площади организуется через функцию
Function Sq(L, W)
Dim Area As Double
Объявляем локальную переменную.
If L = 0 Or W = 0 Then
Если хотя бы один из аргументов равен 0.
Exit Sub
то процедура немедленно завершается.
End If
Area = L * W Вычисляется площадь прямоугольника.
Sq=Area Результат вычислений передается в имя функции.
Debug. Print Area ' Выводится полученное значение в окно отладки.
End Function
Отметим наличие в последнем примере обязательной строки. Sq=Area Возможен другой
вариант Sq=L*W. Тогда переменную Area декларировать не нужно.
При вызове функции, чтобы получить возвращаемое значение функции, надо присвоить эту
функцию переменной и заключить аргументы в скобки, как показано в следующем примере.
Ploshad = Sq(50,45)
В этом примере функция вычисления площади стоит после знака = и результат ее работы
передается переменной Ploshad.
Еще несколько особенностей, которые нужно учитывать при создании процедур и функций.
Процедуры Sub, тип которых не указан явно с помощью слов Public или Private, являются
общими по умолчанию. Если не используется слово Static, значения локальных переменных
не сохраняются между вызовами процедур.
Все выполняемые команды должны содержаться в процедурах. Не допускается определение
процедуры Sub внутри другой процедуры Sub, Function или Property.
Инструкция Exit Sub приводит к немедленному выходу из процедуры Sub. Выполнение
программы продолжается с инструкции, следующей за инструкцией, содержащей вызов
процедуры Sub. В любом месте процедуры Sub допускается наличие любого числа
инструкций Exit Sub.
Переменные, используемые в процедурах Sub, разбиваются на две категории: явно
описанные внутри процедуры и не описанные внутри процедуры. Переменные, которые
явно описаны в процедуре (с помощью ключевого слова Dim или эквивалентного ему),
всегда являются локальными для этой процедуры. Переменные, которые используются, но
явно не описаны в процедуре, также являются локальными, если они явно не описаны на
более высоком уровне.
В языке VBA содержится большое количество встроенных процедур, которые вызываются
таким же образом, например для вычисления синуса х используем строчку
Y=Sin(x)
8.1. Описание переменных
Вы помните, что при описании переменных обычно используется инструкция Dim. Для
создания переменной на уровне процедуры инструкция описания помещается внутри
процедуры. Чтобы создать переменную на уровне модуля, инструкция описания
располагается в начале модуля, в разделе описаний (General) .
В следующем примере создается переменная sName и задается тип данных String.
Dim sName As String
Когда эта инструкция располагается в процедуре, переменная sName может использоваться
только в данной процедуре. Если же такая инструкция находится в разделе (General), то
переменная sName доступна для всех процедур данного модуля, но не может использоваться
процедурами из других модулей проекта. Чтобы сделать переменную доступной для всех
процедур проекта, перед ней надо поставить инструкцию Public, как показано в следующем
примере:
Public sName As String
Допускается также описание нескольких переменных в одной строке. В этом случае, чтобы
задать тип данных, надо указать определенный тип для каждой переменной. В следующем
примере переменные inpX, inpY, и inpZ описываются как Integer.
Dim inpX As Integer, inpY As Integer, inpZ As Integer
В следующей строке inpX и inpY описываются как Variant; и только inpZ описывается как
Integer.
Dim inpX, inpY, inpZ As Integer
Инструкция Public используется для описания общих переменных на уровне модуля.
Public sName As String
Общие переменные могут использоваться в любой процедуре проекта. Если общая
переменная описана в стандартном модуле или в модуле класса, она также может
использоваться в любом проекте, в котором имеется ссылка на проект, где описана эта
переменная.
Инструкция Private используется для описания “личных” переменных уровня модуля.
Private MyName As String
“Личные” переменные доступны только для процедур одного и того же модуля.
На уровне модуля инструкция Dim эквивалентна инструкции Private, но использование
инструкции Private может упростить чтение и отладку программы. Переменные, описанные
с помощью инструкции Static вместо инструкции Dim, сохраняют свои значения при
выполнении программы.
Инструкция Option Explicit, помещенная в модуль перед всеми процедурами налагает
требование явного описания всех переменных этого модуля и при попытке использования
неописанного или неверно введенного имени переменной возникает ошибка во время
компиляции.
В заключение отметим, что от старых традиций Бейсика VBA сохранил возможность
«быстро» объявлять переменные с помощью суффиксов, присоединяемых к именам
переменных (см. таблицу 6)
Таблица 6. Суффиксы для различных типов переменных
Тип переменной
Суффикс Пример Тип переменной
Суффикс Пример
Integer
%
Z%
Double
#
Y#
Long
&
K&
String
$
F$
Single
!
X!
8.2. Массивы
Теперь обсудим использование массивов. Массив представляет собой одну переменную с
множеством областей памяти для хранения множества значений, тогда как обычная
переменная имеет только одну область, в которой может храниться только одно значение.
При необходимости сослаться на все элементы массива можно ссылаться на массив как
целое. Возможны также ссылки на его отдельные элементы. Например, для записи фамилий
30 сотрудников организации целесообразно использовать строковый массив с 30
элементами, вместо того, чтобы описывать 30 отдельных строковых переменных. Элементы
массива отличаются друг от друга по номерам или индексам. Каждый элемент массива
содержит одно значение. Следующая инструкция описывает массив Family с 30 элементами.
По умолчанию индексация массива начинается с нуля, так что верхняя граница массива - 29,
а не 30.
Dim Family (29) As String
Также можно в отдельном массиве сохранить значение зарплаты этих сотрудников
Dim Zarp (29) As Long
Можно пойти еще дальше, и в двумерном массиве хранить зарплату за все 12 месяцев. Тогда
объявление двумерного массива будет выглядеть так
Dim Zarpgod (29,11) As Long
Чтобы задать значение отдельного элемента, надо указать его индекс. В следующем примере
некоторым элементам массива присваивается исходное значение
Family (0)=”Ананасов”
Family (1)=”Ветров”
Зарплату этих сотрудников сохраним соответственно
Zarp(0)=25000
Zarp(1)=28000
Можно запомнить и их зарплату за январь месяц (номер месяца равен 0) в двумерном
массиве
Zarpgod (0,0)=18000
Zarpgod (1,0)=15000
Если нас не устраивает начало нумерации с нуля, то можно описать массив с указаием
верхней и нижней границы
Dim Zarpgod (0 To 29, 1 To 12)
Для обработки многомерных массивов используются вложенные инструкции For...Next. В
следующей процедуре двумерный массив заполняется значениями типа данных Single.
Sub TotulMass()
Dim K As Integer, J As Integer
Dim Pro (1 To 15, 1 To 10) As Single
' Заполнение массива.
For K= 1 To 15
For J = 1 To 10
Pro(K, J) = K * J
Next J
Next K
End Sub
В VBA максимальная размерность массива – 60.
9. Отладка программ
Если бы все программировали идеально, то необходимость; отладки программ отпала бы
сама собой: каждая создаваемая программа выполняла бы все требуемые действия с первого
раза. Как известно, такого не бывает, поэтому каждая среда программирования имеет
инструменты, с помощью которых можно решить проблемы, возникающие в процессе
программирования. В VBA также есть средства, которые позволяют исключить ошибки при
разработке программ.
Отладка программ — это проверка и внесение исправлений в программу при ее разработке.
Отладка позволяет идентифицировать ошибки, допущенные при программировании,
например, орфографические ошибки в инструкциях, именах функций и переменных, а также
логические ошибки.
Все ошибки, возникающие при программировании можно отнести к трем категориям:

Ошибки компиляции возникают, если VBA не может интерпретировать введенный
текст, например, при использовании неправильного синтаксиса инструкции или
задании неверного имени метода или свойства. Некоторые ошибки компиляции
обнаруживаются при вводе инструкции, а другие перед выполнением программы.
Данный тип ошибок обычно просто идентифицировать и исправить, поскольку VBA
выявляет их автоматически, а сами ошибки очевидны.

Ошибки выполнения возникают при выполнении программы, т. е. после успешной
компиляции. Причиной таких ошибок может быть отсутствие данных, или
неправильная информация, например, данные, введенные пользователем. Ошибки
выполнения, как и ошибки компиляции легко идентифицируются VBA. При этом
выводится инструкция, при выполнении которой произошла ошибка. Ошибки
данного типа тяжелее устранить: может понадобиться вывести значения переменных
или свойств, а также другие данные, которые влияют на успешное выполнение
программы.

Логические ошибки трудно заметить и устранить. Логические ошибки не приводят к
прекращению компиляции или выполнения. Однако они являются причиной того, что
программа не выдает желаемых результатов. Ошибки данного типа
идентифицируются путем тщательной проверки с помощью средств отладки VBA.
Обратите внимание, что если возникает ошибка выполнения, то исполнение макроса
прерывается и выводится стандартное сообщение, которое пользователю весьма не просто
понять. Однако самое главное — макрос не доводит до завершения операцию, для
выполнения которой он предназначен. Хотя и невозможно предотвратить возникновение
всех возможных ошибок, следует стремиться к уменьшению их числа. В маленьком макросе
довольно просто выявить ошибку. Однако по мере увеличения размеров и сложности
программ, а также добавления новых переменных и процедур, становится труднее и труднее
находить ошибки, В этом случае необходимо воспользоваться средствами отладки VBA.
Одним из самых простых инструментов, используемых для предотвращения множества
ошибок в приложениях VBA, является инструкция Option Explicit. Данная инструкция
определяет необходимость явного задания переменных в программах. Хотя кому-то может
показаться, что можно обойтись без инструкции Option Explicit, лучше все-таки использовать
ее, т. к. она имеет следующие достоинства:
Если неправильно указать имя описанной переменной, то при компиляции макроса
возникает ошибка. Сообщение об ошибке использования необъявленной переменной
является знаком того, что в имени переменной допущена орфографическая ошибка или что
переменная не описана. В любом случае такой недочет нетрудно исправить.
Для определения ошибок редактор VBA позволяет выполнять процедуры в пошаговом
режиме. Чтобы выполнить инструкции в пошаговом режиме, можно воспользоваться
командами меню“Debug” («Отладка»). Меню “Debug” включает команды и комбинации
клавиш, с помощью которых можно выполнить программу в пошаговом режиме Дли
выполнения программы в пошаговом режиме чаще всего используется команда “Step Into” (
“Шаг с заходом” ), которая позволяет выполнить одну строку программы и перейти к
следующей.
Отладка программ в Visual Basic выполняется главным образом в режиме прерывания.
Переход в данный режим выполняется:

При нажатии кнопки Debug в окне сообщения об ошибке выполнения.

При прерывании работы макроса с помощью комбинации клавиш <Ctrl>+<Break>.
Текущая инструкция выделяется в окне модуля
По достижении точки останова.

По достижении инструкции Stop

При пошаговом .выполнении программы
При возникновении событий Break When: True и Break When Changed
В режиме прерывания, можно:

Вывести значение переменной или свойства.

Вычислить выражение в окне отладки.

Сбросить выполнение процедуры.

Выполнить процедуру в пошаговом режиме.
Одной из наиболее полезных возможностей в режиме прерывания является вывод значений
переменных процедур и свойств используемых объектов. Это происходит в случае, если
навести курсор на имя переменной в окне кода. Если известны ожидаемые величины, то
можно сравнить их с полученными значениями. Также полезным является возможность
остановить выполнение программы в какой-нибудь строке и дальше работать в пошаговом
режиме. Установка и удаление точек прерывания реализуется командами отладки “Toggle
Breakpoints” ( «Установить точку прерывания») и “Clear All Breakpoint” («Убрать все точки
прерывания»).

Download