информатика. Игнатьева Елена Александровна, Измайлова Елена Ивановна. Информатика. Электронный ресурс методические указания
Скачать 4.32 Mb.
|
Классификация процедур Процедуры VBA можно классифицировать по нескольким признакам: по способу использования (вызова) в программе, по способу запуска процедуры на выполнение, по способу создания кода процедуры, по месту нахождения кода процедуры в проекте. Процедуры VBA подразделяются на подпрограммы и функ- ции. Первые описываются ключевым словом Sub , вторые – Function . Различие между этими видами процедур только синтак- сическое, так как преобразовать процедуру одного вида в эквива- лентную процедуру другого вида не сложно. По способу создания процедуры делятся на: обычные, разрабатываемые "вручную"; процедуры, код которых создается автоматически генера- тором макросов (MacroRecoder). Это разделение можно считать условным, так как многие процедуры создаются генератором макросов, а затем изменяются и дописываются вручную. По способу запуска процедур на выполнение можно выде- лить в отдельную группу процедуры, запускаемые автоматически при наступлении того или иного события (процедуры обработки событий). По положению в проекте различаются процедуры: находящиеся в специальных программных единицах – стандартных модулях, модулях классов и модулях, связанными с объектами; реагирующие на события. Еще один специальный тип процедур – процедуры-свойства Property Let , Property Set и Property Get . Они служат для задания и получения значений закрытых свойств класса. 182 Главное назначение процедур во всех языках программиро- вания состоит в том, что при их вызове они изменяют состояние программного проекта, – изменяют значения переменных (свой- ства объектов), описанных в модулях проекта. У процедур VBA сфера действия шире. Их главное назначение состоит в измене- нии состояния системы документов, частью которого является изменение состояния самого программного проекта. Поэтому процедуры VBA оперируют, в основном, с объектами Office. Есть два способа, с помощью которых процедура получает и передает информацию, изменяя тем самым состояние системы документов. Первый и основной способ состоит в использовании параметров процедуры. При вызове процедуры ее аргументы, со- ответствующие входным параметрам получают значение, то есть процедура получает информацию от внешней среды, и в резуль- тате работы процедуры формируются значения выходных пара- метров, переданных ей по ссылке. Тем самым изменяется состоя- ние проекта и документов. Второй способ состоит в использова- нии процедурой глобальных переменных и объектов, как для по- лучения, так и для передачи информации. Синтаксис процедур и функций Описание процедуры Sub в VBA имеет следующий вид: [Private | Public] [Static] Sub имя([список-аргументов]) тело-процедуры End Sub Ключевое слово Public в заголовке процедуры используется, чтобы объявить процедуру общедоступной, то есть дать возмож- ность вызывать ее из всех других процедур всех модулей любого проекта. Если модуль, в котором описана процедура, содержит закрывающий оператор Option Private , процедура будет доступна лишь модулям своего проекта. Альтернативный ключ Private ис- пользуется, чтобы закрыть процедуру от всех модулей, кроме то- го, в котором она описана. По умолчанию процедура считается общедоступной. Ключевое слово Static означает, что значения локальных (объявленных в теле процедуры) переменных будут сохраняться в промежутках между вызовами процедуры (используемые про- 183 цедурой глобальные переменные, описанные вне ее тела, при этом не сохраняются). Параметр имя – это имя процедуры, удовлетворяющее стан- дартным условиям VBA на имена переменных. Необязательный параметр список-аргументов – это после- довательность разделенных запятыми переменных, задающих пе- редаваемые процедуре при вызове параметры. Аргументы (фор- мальные параметры), задаваемые при описании процедуры, все- гда представляют только имена (идентификаторы). В то же время при вызове процедуры ее аргументы – фактические параметры могут быть не только именами, но и выражениями. Последовательность операторов ( тело процедуры) задает программу выполнения процедуры. Тело процедуры может включать как "пассивные" операторы объявления локальных данных процедуры (переменных, массивов, объектов и др.), так и "активные" – они изменяют состояния аргументов, локальных и внешних (глобальных) переменных и объектов. В тело может входить оператор Exit Sub , приводящий к немедленному завер- шению процедуры и передаче управления в вызывающую про- грамму. Каждая процедура в VBA определяется отдельно от дру- гих, то есть тело одной процедуры не может включать описания других процедур и функций. Рассмотрим подробнее структуру одного аргумента из спи- ска-аргументов: [Optional] [ByVal | ByRef] [ParamArray] переменная[()] [As тип] [= значение-по-умолчанию] Ключевое слово Optional означает, что заданный им аргу- мент является возможным, но необязательным, – его необяза- тельно задавать в момент вызова процедуры. Для таких аргумен- тов можно задать значение по умолчанию. Необязательные аргу- менты всегда помещаются в конце списка аргументов. Альтернативные ключи ByVal и ByRef определяют способ передачи аргумента в процедуру. ByVal означает, что аргумент передается по значению, то есть при вызове процедуры будет создаваться локальная копия переменной с начальным передаваемым значением и изменения этой локальной переменной во время выполнения процедуры не отразятся на значении переменной, передавшей свое значение в 184 процедуру при вызове. Передача по значению возможна только для входных параметров, которые передают информацию в про- цедуру, но не являются результатами. Для таких параметров пе- редача по значению удобнее, чем передача по ссылке, так как в момент вызова аргумент может быть задан сколь угодно слож- ным выражением. Входные параметры, являющиеся объектами, массивами или переменными пользовательского типа, передают- ся по ссылке, что позволяет избежать создания копий. Выраже- ния над такими аргументами недопустимы, поэтому передача по значению теряет свой смысл. ByRef означает, что аргумент передается по ссылке, то есть все изменения значения передаваемой переменной при выполне- нии процедуры будут непосредственно происходить с перемен- ной-аргументом из вызвавшей данную процедуру программы. В VBA по умолчанию аргументы передаются по ссылке ( ByRef ). VBA допускает, чтобы фактическое значение аргумента, переда- ваемого по ссылке, было константой или выражением соответст- вующего типа. В таком случае этот аргумент рассматривается как передаваемый по значению, и никаких сообщений об ошибке не выдается, даже если этот аргумент встречается в левой части присвоения. Процедура VBA допускает возможность иметь необязатель- ные аргументы, которые можно опускать в момент вызова. Обобщением такого подхода является возможность иметь пере- менное, заранее не фиксированное число аргументов. Достигает- ся это за счет того, что один из параметров (последний в списке) может задавать массив аргументов, – в этом случае он задается с описателем ParamArray . Если список-аргументов включает мас- сив аргументов ParamArray , ключ Optional использовать в списке нельзя. Ключевое слово ParamArray . может появиться перед по- следним аргументом в списке, чтобы указать, что этот аргумент – массив с произвольным числом элементов типа Variant . Перед ним нельзя использовать ключи ByVal , ByRef или Optional Переменная – это имя переменной, представляющей аргу- мент. Если после имени переменной заданы круглые скобки, то это означает, что соответствующий параметр является массивом. 185 Параметр тип задает тип значения, передаваемого в проце- дуру. Он может быть одним из базисных типов VBA (не допус- каются только строки String c фиксированной длиной). Обяза- тельные аргументы могут также иметь тип определенной пользо- вателем записи или класса. Если тип аргумента не указан, то по умолчанию ему приписывается тип Variant Для необязательных ( Optional ) аргументов можно явно за- дать значение по умолчанию . Это константа или константное вы- ражение, значение которого передается в процедуру, если при ее вызове соответствующий аргумент не задан. Для аргументов типа объект ( Object ) в качестве значения по умолчанию можно задать только Nothing Синтаксис определения процедур-функций похож на опре- деление обычных процедур: [Public | Private] [Static] Function имя [(список-аргументов)] [As тип-значения] тело-функции End Function Отличие лишь в том, что вместо ключевого слова Sub для объявления функции используется ключевое слово Function , а по- сле списка аргументов следует указать параметр тип-значения , определяющий тип возвращаемого функцией значения. В теле функции должен быть использован оператор присвоения вида: имя = выражение Здесь, в левой части оператора стоит имя функции, а в пра- вой – значение выражения, задающего результат вычисления функции. Если при выходе из функции переменной имя значение явно не присвоено, функция возвращает значение соответствую- щего типа, определенное по умолчанию. Для числовых типов это 0 , для строк – строка нулевой длины ( "" ), для типа Variant функ- ция вернет значение Empty , для ссылок на объекты – Nothing Чтобы немедленно завершить вычисления функции и выйти из нее, в теле функции можно использовать оператор Exit Function. Основное отличие процедур от функций состоит в способе их использования в вызывающей программе. Следующая функ- ция возвращает аргумент, возведенный в куб: Function cube(ByVal N As Integer) As Long 186 cube = N*N*N End Function Вызов этой функции может иметь вид Dim x As Integer, y As Integer y = 2 x = cube(y+3) При преобразовании функции в процедуру появляется до- полнительный параметр, необходимый для задания результата. Поэтому у эквивалентной процедуры Cube1 появляется еще один аргумент: Sub cube1(ByVal N As Integer, ByRef C As Long) C = N*N*N ' получение результата в переменной, заданной по ссылке End Sub Ее также можно использовать для возведения в куб: cube1(y+3, x) Эта взаимозаменяемость не означает, что безразлично, ка- кой вид процедур использовать в программе. Если бы выражение, в котором участвует функция, было сложнее, например, x = cube(y)+sin(cube(x)) то его вычисление с помощью процедуры Cube1 потребовало бы выполнения нескольких операторов и ввода дополнительных пе- ременных: cube1(y,z) cube1(x,u) x = z+sin(u) Функции с побочным эффектом В классическом варианте все аргументы функции являются входными параметрами, и единственный результат вычисления функции – это ее возвращаемое значение, примером является функция Cube . Однако чаще всего, используются функции с по- бочным эффектом, то есть такие функции, которые помимо полу- чения значения функции изменяют значения некоторых резуль- тирующих параметров, передаваемых функции по ссылке. На- пример: Public Function SideEffect(ByVal X As Integer, ByRef Y As In- teger) As Integer 187 SideEffect = X+Y Y = Y+1 End Function Public Sub TestSideEffect() Dim X As Integer, Y As Integer, Z As Integer X = 3: Y = 5 Z = X+Y+SideEffect(X, Y) Debug.Print X, Y, Z X = 3: Y = 5 Z = SideEffect(X, Y)+X+Y Debug.Print X, Y, Z End Sub Вот результаты вычислений: 3 6 16 3 6 17 В данном примере результат вычисления суммы трех сла- гаемых зависит от порядка их записи. Более того, результат вы- числения будет непредсказуем, поскольку VBA может для увели- чения эффективности изменять порядок действий при вычисле- нии арифметического выражения. Поэтому лучше не использо- вать в выражении вызов функции с побочным эффектом, изме- няющей значения входящих в него переменных. Создание процедуры Для создания новой процедуры, текст которой пишется вручную, нужно: 1) открыть в окне проектов "Проект-(VBA)Project" (Project Explorer) папку с модулем (формой, документом, рабочим листом и т.п.), к которому требуется добавить процедуру, и, щелкнув этот модуль, открыть окно редактора с кодами процедур модуля; 2) перейти в редактор, набрать ключевое слово ( Sub , Function или Property ), имя процедуры и ее аргументы; затем на- жмите клавишу Enter, и VBA поместит ниже строку с соответст- вующим закрывающим оператором ( End Sub , End Function , End Property ); 3) написать текст процедуры между ее заголовком и закры- вающим оператором. 188 Можно автоматизировать работу, вызвав диалоговое окно "Вставка процедуры" (Insert Procedure). Последовательность дей- ствий в этом случае следующая: 1) выбрать в меню "Вставка" (Insert) команду "Процедура" (Procedure); 2) в поле "Имя" (Name) появившегося окна "Вставка проце- дуры" (Insert Procedure) ввести имя процедуры; 3) указать в группе кнопок-переключателей "Тип" (Type) тип создаваемой процедуры: Подпрограмма ( Sub ), Функция ( Function ) или Свойство ( Property ); 4) указать в группе кнопок-переключателей "Область опре- деления" (Scope) вид доступа к процедуре: Общая (Public) или Личная (Private); 5) пометить, если нужно, флажок "Все локальные перемен- ные считать статическими" (All Local Variables as Statics ), чтобы в заголовок процедуры добавился ключ Static ; 6) щелкнуть кнопку "OK" – в окне редактора появится заго- товка процедуры, состоящая из ее заголовка (без параметров) и закрывающего оператора; 7) добавить параметры в заголовок процедуры и написать текст процедуры между ее заголовком и закрывающим операто- ром. Создание процедур обработки событий VBA является языком, в котором, как и в большинстве со- временных объектно-ориентированных языков, реализована кон- цепция программирования, управляемого событиями (event driven programming). Здесь нет понятия программы, которая на- чинает выполняться от Begin до End . Пользователи системы до- кументов и операционная система могут инициировать события в мире объектов. В ответ на возникновение события операционная система посылает сообщение соответствующему объекту. Реак- цией объекта на получение сообщения является вызов процедуры – обработчика события. Задача программиста сводится к написа- нию обработчиков событий для объектов. Причем, все обычные процедуры и функции VBA, о которых мы говорили выше, вызы- ваются прямо или косвенно из процедур обработки событий, если 189 только речь не идет о режиме отладки. Именно эти процедуры приводят к последовательности вызовов обычных процедур и функций. С каждым из объектов Office связан набор событий, на ко- торые он может реагировать. Процедуры обработки этих событий располагаются в модулях, связанных с объектами, реагирующими на события. Для кнопок меню, у которых есть только один обра- ботчик события, соответствующая процедура может находиться в стандартном модуле или модуле макросов. Office позволяет при описании собственных классов, создаваемых программистом, за- дать определенный набор событий. Обработчики событий таких объектов создаются по определенной технологии. Например, процедура, которая будет пять раз подавать звуковой сигнал при закрытии документа: Private Sub Document_Close() Dim I As Integer For I = 1 To 5 ' 5 раз подается Beep ' звуковой сигнал Next I End Sub Эта процедура находится в модуле, связанном с объектом ThisDocument , и вызывается в момент закрытия документа. Вызовы процедур и функций Вызовы процедур Sub Вызов обычной процедуры Sub из другой процедуры можно оформить разными способами. Первый способ: имя список фактических параметров, где имя – имя вызываемой процедуры; список фактических пара- метров – список аргументов, передаваемых процедуре; он должен соответствовать списку аргументов, заданному в описании про- цедуры. Задать список параметров можно разными способами. 190 В простейшем случае в нем перечисляются через запятую значения передаваемых процедуре аргументов в том же порядке, что и в списке аргументов из заголовка процедуры. Может оказаться, что в одном проекте несколько модулей содержат процедуры с одинаковыми именами. Для различия этих процедур нужно при их вызове указывать имя процедуры через точку после имени модуля, в котором она определена. Например, если каждый из двух модулей Mod1 и Mod2 содержит определе- ние процедуры ReadData , а в процедуре MyProc нужно восполь- зоваться процедурой из Mod2 , этот вызов имеет вид: Sub Myproc() Mod2.ReadData End Sub Если требуется использовать процедуры с одинаковыми именами из разных проектов, нужно добавить к именам модуля и процедуры имя проекта. Например, если модуль Mod2 входит в проект MyBook , тот же вызов можно уточнить так: MyBooks.Mod2.ReadData Второй способ вызова процедур связан с использованием оператора Call . В этом случае вызов процедуры выглядит так: Call имя(список фактических параметров) Обратите внимание на то, что в этом случае список факти- ческих параметров заключен в круглые скобки, а в первом случае – нет. Если процедура VBA имеет только один параметр, то она может быть вызвана без оператора Call и с использованием круг- лых скобок, не сообщая об ошибке вызова, но возвращает не пра- вильный результат. Например: Public Sub MyInc(ByRef X As Integer) X = X+1 End Sub Public Sub TestInc() Dim X As Integer X = 1 'Вызов процедуры с параметром, заключенным в скобки, 'синтаксически допустим, но работает не корректно! MyInc (X) Debug.Print X 191 'Корректный вызов MyInc X Debug.Print X 'Это тоже корректный вызов Call MyInc(X) Debug.Print X End Sub Вот результаты ее работы: 1 2 3 Несмотря на то, что при первом вызове процедура вызыва- ется без ошибок и увеличивает значение результата, но по завер- шении ее работы значение аргумента не изменяется. В этой си- туации не действует описатель ByRef , вызов идет так, как будто параметр описан с описателем ByVal Если же процедура имеет более одного параметра, то по- пытка вызвать ее, заключив параметры в круглые скобки и не предварив этот вызов ключевым словом Call , приводит к синтак- сической ошибке. Например: Public Sub SumXY(ByVal X As Integer, ByVal Y As Integer, ByRef Z As Integer) Z = X+Y End Sub Public Sub TestSumXY() Dim a As Integer, b As Integer, c As Integer a = 3: b = 5 'SumXY (a, b, c) 'Синтаксическая ошибка SumXY a, b, c Debug.Print c End Sub В этом примере некорректный вызов процедуры SumXY бу- дет обнаружен на этапе проверки синтаксиса. Рассмотрим еще одну особенность вызова VBA процедур, связанную с аргументами, передаваемыми по ссылке. Как прави- ло, в языках программирования для таких аргументов возможное значение фактического параметра ограничивается, – он должен 192 быть именем переменной, ссылка на которую передается проце- дуре. VBA допускает возможность задания для таких аргументов констант и выражений в момент вызова. Например, процедура CompVal c четырьмя аргументами, которая в зависимости от положительности z возвращает в пере- менной y либо увеличенное, либо уменьшенное на сто значение x и сообщает об этом в строковой переменной w , определена сле- дующим образом. Sub CompVal(ByVal x As Single, ByRef y As Single, _ ByVal z As Integer, ByRef w As String) If z > 0 Then ' увеличение y = x+100 w = "increase" Else ' уменьшение y = x-100 w = "decrease" End If End Sub Рассмотрим процедуру TestCompVal , в которой несколько раз вызывается процедура CompVal : Sub TestCompVal() Dim a As Single Dim b As Single Dim n As Integer Dim S As String n = 5 : a = 7.4 ' значения параметров CompVal a, b, n, S ' 1-ый вызов Debug.Print b, S CompVal 7.4, b, 5, S ' 2-ой вызов Debug.Print b, S CompVal 0, 0, 0, S ' 3-ий вызов Debug.Print b, S CompVal 0, 0, 0, "В чем дело?" ' 4-ый вызов Debug.Print b, S End Sub В результате выполнения этой процедуры будут напечатаны следующие результаты: 107,4 increase 193 107,4 increase 107,4 decrease 107,4 decrease Первые два вызова корректны. Следующие два вызова хотя и допустимы в языке VBA, но приводят к тому, что параметры, переданные по ссылке, не меняют своих значений в ходе выпол- нения процедуры и, по существу, вызов ByRef по умолчанию за- меняется вызовом ByVal |