Лекция 5 Кафедра Прикладной математики М-703, тел К.т.н., профессор Глаголев Виктор Борисович, комн. Ж-405б, тел Процедуры 1.Процедуры: виды, вызов, объявление 2. Область действия имени процедуры 3. Именованные аргументы 4. Передача аргументов по ссылке и по значению 5. Аргументы – имена форм и элементов управления 6. Пример. Центрирование вектора
Процедуры В VB можно использовать несколько видов процедур. Вот некоторые из них: Подпрограмма общего назначения представляет собой самостоятельную часть программного кода, обладающую уникальным именем, благодаря которому она может быть вызвана и выполнена. Имя подпрограммы не возвращает никакого значения в вызывающую ее процедуру.
Функция подобна подпрограмме, главное ее отличие состоит в том, что ее имя возвращает результат в то место, откуда она была вызвана. Событийная подпрограмма – обработчик события отличается от обычной подпрограммы тем, что вызывается она автоматически при наступлении соответствующего события. Подпрограмма-свойство. Применяется при необходимости снабдить объект новым свойством.
Схема, показанная на следующем слайде, иллюстрирует последовательность выполнения программы, состоящей из подпрограмм и функций. Очередность выполнения групп инструкций показана на этом рисунке цифрами в скобках.
Последовательность выполнения программы Событийная подпрограмма Вызов процедуры А Подпрограмма А Вызов функции Б Возврат Функция Б Возврат (1) (2) (3) (4) (5)
Выполнение программы чаще всего начинается с событийной подпрограммы. В этой процедуре могут вызываться другие процедуры (процедура А) или функции. После вызова процедуры выполняются инструкции тела этой процедуры. В свою очередь в вызванной процедуре могут быть обращения к другим процедурам (функция Б).
Прекращение выполнения вызванной процедуры или функции (возврат) означает возвращение в вызывающую подпрограмму или функцию, выполнение которой продолжается с инструкции, следующей за инструкцией, в которой произошел вызов.
Вызов процедур Чтобы код функции или подпрограммы общего назначения был выполнен, она должна быть вызвана. Вызов подпрограммы осуществляется отдельной инструкцией, которая начинается с ее имени. Сразу после имени в скобках должны следовать разделенные запятой значения аргументов подпрограммы, если таковые предусмотрены: ИмяПодпрограммы _ ([Список значений аргументов])
Обращение к функции не является отдельной инструкцией. Оно является операндом выражения: X = A + ИмяФункции( _ [Список значений аргументов])
Чтобы функция могла вернуть значение, ее вызов должен фигурировать в конструкции, использующей возвращаемое функцией значение (например, в качестве присваиваемой величины в операции присваивания, в качестве условия в конструкции If и т. п.).
Объявление процедур Процедура не может быть объявлена внутри какой-либо другой процедуры.
Для объявления подпрограммы используют следующий синтаксис: [Private/Public] Sub _ ИмяПодпрограммы _ ([Список аргументов]) [Инструкции] [Exit Sub] [Инструкции] End Sub
Синтаксис объявления функции выглядит несколько иначе: [Private/Public] Function _ ИмяФункции _ ([Список аргументов]) [As Тип] [Инструкции] [Exit Function] [Инструкции] [Return (Выражение)] [ИмяФункции = Выражение] End Function
Пояснения синтаксиса: Public. Этим словом объявляют в модуле подпрограмму или функцию, которая должна быть доступна всем процедурам всех форм и модулей проекта. В форме это слово применять нельзя. Private. В этом случае подпрограмма или функция доступна только в пределах той формы или модуля, где она объявлена. Действует по умолчанию.
Exit Sub или Exit Function. Эти инструкции осуществляют досрочный выход из подпрограммы или соответственно из функции. Синтаксис аргументов сам по себе является достаточно развитым: [Optional] ByVal / ByRef _ [ParamArray] ИмяАргумента [()] _ [As Тип][= ЗначениеПоУмолчанию]
ИмяАргумента – это имя переменной, массива, элемента управления или формы (в последних двух случаях тип может принимать значения Control или Form или имя класса объекта).
В случае массива после имени массива ставится пара скобок ( ), внутри которых не указываются границы значений индексов, что позволяет использовать одну процедуру для разного числа элементов массива в каждом конкретном случае. Если размерность массива больше 1, то внутри скобок ставится одна или несколько запятых.
Тип аргумента может быть любым базовым или пользовательским типом, а также Control или Form, или именем класса (Button, Label, TextBox и др.). Список аргументов определяет связь по данным между вызывающей процедурой (процедура, из которой происходит вызов) и вызываемой процедурой.
ЗначениеПоУмолчанию допустимо только для необязательного аргумента. Задает значение, которое будет автоматически присвоено аргументу в случае отсутствия соответствующего значения аргумента при обращении.
Поясним назначение зарезервированных слов, применяемых при определении аргументов: Optional. Это слово должно предшествовать имени того аргумента, который является необязательным. В списке аргументов после необязательного аргумента могут следовать только необязательные же аргументы. Нельзя использовать необязательные аргументы совместно с массивом аргументов ( ParamArray ).
ByVal. Значение аргумента, которому предшествует это слово, будет передаваться в процедуру или функцию по значению (передается его копия). Предусматривается системой по умолчанию.
Если аргументом окажется внешняя относительно процедуры переменная, то никакие манипуляции с этим аргументом в теле процедуры или функции не изменят значения этой внешней переменной. Такой способ применяется для входных данных. При обращении к процедуре соответствующий аргумент может быть выражением.
ByRef. Передача значения аргумента будет производиться по ссылке (передается физический адрес аргумента). Значение внешней переменной, переданной процедуре в качестве этого аргумента, может быть изменено операторами процедуры. Этот режим передачи аргументов по ссылке используется для выходных аргументов.
При обращении к процедуре соответствующий аргумент может быть только переменной или массивом (не может быть выражением, например константой).
ParamArray. Массив аргументов. Таковым может быть объявлен только последний аргумент в списке, при этом он должен представлять собой массив типа Object. Этим способом можно передавать в процедуру или функцию значительные объемы данных. При использовании массива аргументов нельзя для этого аргумента применять свойства Optional, ByVal и ByRef, а также не должно быть других необязательных аргументов.
Пример объявления подпрограммы вычисления площади прямоугольника по заданным значениям сторон: Sub D (ByVal Ш As Single, _ ByVal В As Single, _ ByRef П As Single) П = В * Ш End Sub
Пример обращения к подпрограмме:. Dim w1, w2 As Single Dim h1, h2 As Single Dim s1, s2 As Single Dim s As Single. D(w1, h1, s1) D(w2, h2, s2) s = s1 + s2.
Пример объявления функции вычисления площади прямоугольника по заданным значениям сторон: Function Demof (ByVal Ш As _ Single, ByVal В As Single) _ As Single Demof = В * Ш End Function
Пример обращения к функции:. Dim w1, w2 As Single Dim h1, h2 As Single Dim s As Single. s = Demof(w1, h1) + Demof(w2, h2).
Пример подпрограммы вычисления значений элементов вектора, равных сумме значений элементов соответствующего столбца матрицы:
Пример обращения к подпрограмме: Dim m1,m2,n1,n2 As Integer. Dim x1(,), x2(,) As Single Dim y1(), y2() As Single. ReDim x1(m1,n1), x2(m2,n2) ReDim y1(n1), y2(n2).
Продолжение примера обращения к процедуре:. MatrVektor(x1, y1) MatrVektor(x2, y2).
В подпрограмме MatrVektor дважды применен метод GetUpperBound. В первом случае применение этого метода массива A.GetUpperBound(0) возвращает наибольшее возможное значение индекса первой размерности массива А.
Во втором случае применение этого метода массива A.GetUpperBound(1) возвращает наибольшее возможное значение индекса второй размерности массива А. Размерности массивов нумеруются, начиная с 0.
А вот пример функции для вычисления среднего значения элементов одномерного массива:
Пример обращения к функции:. Dim x() As Single, y() _ As Single Dim s As Single. ReDim x(kx), y(ky). s = FunSumVector(x) _ + FunSumVector(y)
Область действия имен процедур Процедура, объявленная в форме, а также в модуле со словом Private, доступна процедурам только этой формы или модуля. Для того чтобы процедура была доступна во всех модулях и формах проекта, она должна быть объявлена в модуле с зарезервированным словом Public.
В список аргументов подпрограммы рекомендуется включать все входные и все выходные для этой подпрограммы данные. В список аргументов функции рекомендуется включать все входные для этой функции данные. Ее единственный (как правило) результат возвращается в вызывающую программу через имя функции.
Аргумент при объявлении Значение аргумента при обращении ByRef ПеременнаяПеременная ByVal ПеременнаяВыражение (в частном случае константа, переменная, элемент массива, обращение к функции) Массив Форма или элемент управления Соответственно форма или элемент управления Должно выполняться следующее соответствие между списками аргументов при объявлении и при обращении:
Именованные аргументы При вызове процедур Sub или Function преимущественно применяется позиционная передача аргументов, т.е. в порядке следования их в объявлении процедуры.
Кроме того, аргументы могут передаваться по именам, вне зависимости от позиции в списке аргументов. В этом случае они задаются так: ИмяАргумента:= _ ЗначениеАргумента Именованный аргумент состоит из имени аргумента, за которым следует двоеточие со знаком равенства ( := ) и значение аргумента.
Именованные аргументы особенно полезны при вызове процедуры с необязательными аргументами ( Optional ). Если используются именованные аргументы, то запятые для обозначения отсутствующих позиционных аргументов не нужны. С помощью именованных аргументов проще проследить, какие аргументы переданы, а какие опущены.
При вызове процедуры с аргументом Optional можно как указывать, так и не указывать необязательный аргумент. Если аргумент не указан, то для него используется имеющееся значение по умолчанию.
Передача аргументов по ссылке и по значению Передача значений аргументов при вызове подпрограммы или функции по ссылке (при этом перед аргументом стоит зарезервированное слово ByRef) означает, что в процедуру из вызывающей процедуры передается адрес ячейки памяти, по которому хранится значение аргумента.
В этом случае вызываемая процедура использует одну и ту же ячейку или область памяти, что и вызывающая процедура. При этом не выделяется дополнительная память для работы с переданным аргументом. Изменение аргумента в вызываемой процедуре означает изменение значения аргумента и в вызывающей процедуре.
Связь по ссылке поясняет следующий слайд. Существо такого способа связи состоит в том, что аргумент процедуры связан с той же физической ячейкой памяти, что и значение аргумента в вызывающей процедуре. Следствием этого является ограничение – значением аргумента не может быть выражение.
Пояснение способа связи по ссылке Значение аргумента в обращении к процедуре в вызывающей процедуре Физическая ячейка памяти, в которой хранится данное вызывающей процедуры – значение аргумента Аргумент в объявлении процедуры
Пояснение способа связи по значению Значение аргумента в обращении к процедуре в вызывающей процедуре Физическая ячейка памяти Дополнительная ячейка памяти (копия значения аргумента) Аргумент в объявлении процедуры
Передача значений аргументов по значению при вызове процедуры означает, что для аргумента выделяется дополнительная область памяти, в которую записывается копия значения передаваемого аргумента.
В списке аргументов вызываемой процедуры перед передаваемым таким образом аргументом должно стоять зарезервированное слово ByVal. Для копии требуется дополнительная память. Зато значение аргумента в вызывающей программе может быть выражением.
Изменения аргумента в вызываемой процедуре не ведут к изменению значения аргумента в вызывающей процедуре. Это удобно, если модификация данных необходима только внутри вызываемой процедуры и нет необходимости передавать измененные данные обратно в вызывающую процедуру.
Передача по значению (выделение дополнительной памяти) приводит к неэффективному использованию памяти. В связи с этим, для строк символов и массивов нецелесообразно использовать передачу по значению.
Имена форм и элементов управления в качестве аргументов Список аргументов процедур может включать имена форм и элементов управления (в качестве описателей типа для них применяются соответственно Form и Control ). Это позволяет создавать универсальные алгоритмы для работы с формами и управляющими элементами.
Для управляющих элементов рекомендуется вместо слова Control применять название класса, к которому относится этот управляющий элемент.
Например, для привлечения внимания пользователя к одному из управляющих элементов формы можно создать одну универсальную подпрограмму, изменяющую цвет текста (например, на кнопке, на надписи и т.д.): Sub Внимание(ByVal Объект As _ Control) Объект.ForeColor = Color.Red End Sub
Аргументом подпрограммы является имя управляющего элемента. Обращение к данной подпрограмме с указанием в качестве значения имени какого-либо конкретного управляющего элемента приведет к установке красного цвета текста. Пример обращения к этой подпрограмме: Внимание(Button1) В результате этого обращения текст на кнопке Button1 станет красного цвета.
Инструкция With Инструкция With позволяет указывать имя только один раз для последовательности инструкций. Инструкция With ускоряет выполнение процедур и помогает избежать повторного задания имени объекта. With Button1.Text = Вычислить.Tag = Огонь.Visible = False End With
Без применения инструкции With этот программный код следовало бы записать так: Button1.Text = Вычислить Button1.Tag = Огонь Button1.Visible = False Для увеличения эффективности программы возможно создание вложенных инструкций With.
Пример. Центрирование вектора Заданы два одномерных массива a(1), a(2), …, a(k) и b(1), b(2), …, b(l). Центрировать и вывести массив a, если среднее значение его элементов меньше среднего значения элементов массива b. В противном случае центрировать и вывести массив b.
Каждый элемент центрированного массива получается как разность значения соответствующего элемента исходного массива и среднего значения его элементов.
Разработка интерфейса Интерфейс, который мы сейчас разработаем, будет применяться не только при решении этого примера, но и при решении подавляющего числа следующих примеров. В некотором смысле это будет стандартный интерфейс.
Разместим на форме кнопку btnПуск и текстовое поле txtЖурнал. Зададим значения свойств, как это задано в расположенной далее таблице. txtЖурнал btnПуск
Кнопка btnПуск Name (имя объекта) btnПуск Text (задает текст на кнопке) Вычислить Font (задает параметры шрифта на кнопке) Microsoft Sans Serif; 12pt Anchor (анкер, задает привязку к нижней, левой и правой границам формы при изменении размеров формы во время счета) Bottom, Left, Right (нижняя, левая, правая)
Текстовое поле txtЖурнал Name (имя объекта) txtЖурнал MultiLine (задает возможность размещения в текстовом окне нескольких строк) True ScrollBars (задает полосы прокрутки) Both (обе)
Текстовое поле txtЖурнал Font (задает параметры шрифта на текстовом поле) Microsoft Sans Serif; 12pt Anchor (анкер, задает привязку к верхней, нижней, левой и правой границам формы) Top, Bottom, Left, Right (верхняя, нижняя, левая, правая) ReadOnly (задает невозможность редактирования текстового поля во время выполнения) True
Изменение имен объектов полезно для выполнения рекомендации, чтобы имя объекта напоминало его класс и его назначение. Это достигается тем, что имя объекта устанавливается состоящим из двух частей. Первая часть имени (обычно это трехсимвольный префикс) напоминает о классе, которому он принадлежит. А вторая часть имени напоминает о его назначении. Класс для объекта – это примерно то же самое, что тип для переменных.
Перечень подзадач Сначала следует разбить задачу на отдельные подзадачи, для решения каждой из которых мы предусмотрим отдельную процедуру или функцию. При формулировании подзадачи требуется правильно составить список аргументов, а также правильно задать тип каждого аргумента. Подобные навыки можно получить только опытным путем.
1. Ввод вектора x. Применим подпрограмму: Sub InputVector(ByRef x() As _ Single, Optional ByVal ArrayName _ As String = "элемент") Второй аргумент необязательный. Это текстовая строка, являющаяся именем вводимого массива.
Второй аргумент позволяет сделать более наглядным ввод массива за счет того, что в окне функции InputBox указывается имя вводимого массива (например, при вводе пятого элемента вектора a это будет выглядеть так: a(5) = ?). Если же второй аргумент при обращении к подпрограмме опустить, то на месте имени массива будет выводиться строка «элемент»: (элемент(5) = ?).
Код подпрограммы InputVector Эта подпрограмма обеспечивает ввод всех элементов массива x, кроме элемента x(0).
2. Вычисление для вектора x среднего значения его элементов. Применим функцию: Function Среднее(ByVal x() As _ Single) As Single
Код функции Среднее
Эта функция предназначена для вычисления среднего арифметического значения всех элементов вектора, индекс которых принадлежит диапазону [1, максимальное значение]. При этом значение элемента вектора x(0) игнорируется. Метод GetUpperBound(0) возвращает максимальное значение индекса вектора x. Аргумент этого метода задает индекс размерности массива. Размерности многомерного массива нумеруются, начиная с нуля.
3. Центрирование вектора x. Применим подпрограмму: Sub ЦентрированиеВектора(ByRef _ x() As Single)
Код подпрограммы ЦентрированиеВектора В этой подпрограмме выполняется центрирование всех элементов вектора x, кроме x(0).
4. Вывод вектора x. Применим подпрограмму: Private Sub OutputVector(ByVal _ x() As Single, ByVal y As _ TextBox) Второй аргумент y необходим для указания текстового поля, в которое должен быть выполнен вывод.
Код подпрограммы OutputVector Эта подпрограмма обеспечивает вывод в текстовом поле всех элементов массива x, кроме элемента x(0).
Укрупненная блок-схема главного алгоритма Алгоритмы подзадач 1 – 4 характеризуются простотой, что позволяет обойтись без их пояснения с помощью блок-схем. Основой всех этих трех алгоритмов является простой цикл. Блок-схема главного алгоритма, который должен выполняться при нажатии на кнопку с именем btnПуск, приведена на двух следующих слайдах.
Алгоритм подпрограммы btnПуск_Click Алгоритмы подзадач 1 – 4 характеризуются простотой, что позволило обойтись без их пояснения с помощью блок-схем. Основой всех этих трех алгоритмов является простой цикл.
Данные, применяемые для построения алгоритма подпрограммы btnПуск. Исходные: a() –динамический массив типа Single, заданный массив a; b() - динамический массив типа Single, заданный массив b; k – переменная целого типа, наибольшее значение индекса массива a; l - переменная целого типа, наибольшее значение индекса массива b;
Результаты: a() – центрированный динамический массив a; b() - центрированный динамический массив b;
Промежуточные: СреднееА – переменная типа Single, среднее значение элементов заданного массива a; СреднееВ - переменная типа Single, среднее значение элементов заданного массива b; i – переменная целого типа, значение индекса элемента массива.
Блок-схема алгоритма 1
1
Код событийной подпрограммы btnПуск_Click
Поясним назначение отдельных инструкций тела этой подпрограммы. В строке 3 выполняется очистка текстового поля. При новом запуске проекта все, что в текстовом поле было выведено при возможных предыдущих запусках, будет удалено. В строках 4 и 5 обращения к функции InputBox обеспечивают ввод значений переменных k и l. Затем в строке 6 обеспечивается вывод для контроля введенных значений переменных k и l.
В строках 8 и 11 обращения к подпрограмме InputVector обеспечивают ввод векторов a и b. Затем в строках 9, 10 и 12, 13 обеспечивается вывод для контроля введенных значений элементов векторов a и b. При этом происходят соответственно два обращения к подпрограмме OutputVector. В строках 15 и 16 вычисляются средние значения элементов векторов a и b.
В разветвлении (строки 17 – 25) принимается решение о том, какой вектор следует центрировать и выводить. Центрирование векторов a и b выполняется соответственно в строках 18 и 22 благодаря обращениям к подпрограмме ЦентрированиеВектора. А в строках 20 и 24 выполняется вывод одного из центрированных векторов a или b при обращении к подпрограмме OutputVector.