Занятие 14 “Область видимости переменной. Определяемые пользователем типы данных” В настоящем занятии подробно обсуждается вопрос , касающийся области видимости переменных вводится понятие модуля кода. Совместно с преподавателем слушатель делает проект, в котором используются переменные разной области видимости, имеющие несколько форм и модуль кода. Внимание слушателей акцентируется на особенностях переменных, объявленных как статические. Рассказывается, как в VB создавать пользовательские типы данных на основе стандартных. Слушатель выполняет проект, в котором формирует и использует свой тип данных. 1. Область видимости переменной Оператор, объявляющий переменную, сообщает Visual Basic, что будет храниться в этой переменной, и где эту переменную можно использовать. Область, где используется переменная, называется областью видимости переменной. Если переменная доступна, то она существует, не наоборот. Переменная может существовать в памяти и быть доступной для некоторых частей программного кода и при этом быть недоступной «невидимой» для других. Вы можете объявить переменную для работы в пределах одной процедуры, в любой процедуре данной формы или для работы во всей программе. Когда вы объявляете переменную, область ее видимости задается одним из ключевых слов: Dim, Private, Public. Однако область видимости переменной зависит и от того, где она объявлена. Dim. Таким образом объявляют локальные переменные, которые существуют только во время вызова процедуры, где они объявлены. Но если переменная с помощью Dim объявлена в разделе глобальных объявлений формы или модуля, то она будет доступна во всех процедурах этой формы или модуля, но для других форм и модулей такая переменная будет «невидимой». Private. Отличается от Dim тем, что не может объявлять переменные внутри процедуры или функции. При объявлении же в разделе глобальных объявлений формы или модуля Dim и Private равнозначны. Public. Если переменная объявлена с использованием этого ключевого слова, то она является глобальной и доступна из всех форм и модулей проекта. Если переменная объявлена как Public в коде формы, то из других форм и модулей доступ к ней должен осуществляться через следующую конструкцию: ИмяФормы . ИмяПеременной Если переменная объявлена как Public в разделе объявлений программного модуля, то доступ к ней возможен просто через ее имя. 1 Static. Переменные Static объявляются внутри процедур и функций и вне их недоступны, но после завершения работы процедуры или функции, в которой объявлены, сохраняют свое значение. По умолчанию объявленная переменная является локальной, действующей только в пределах той процедуры, в которой она была создана. 2. Модули кода Форма и весь связанный с ней код хранятся в отдельном файле с расширением frm. По мере того, как вы углубляете свои познания в языке Visual Basic, вы начинаете чувствовать потребность в усложнении структуры проектов, создаваемых вами. В определенный момент вы приходите к мысли, что вам необходимо сделать не одну форму в проекте, а две или больше. Тогда ваш проект будет содержать – соответственно – два или больше файлов с расширением frm. Кроме того, вы можете разрабатывать программы, содержащие только код. Он размещается в файлах модулей кода с расширением bas. Модули кода создаются в тот момент, когда вы выбираете в меню Project команду Add Module или нажимаете одноименную кнопку на панели инструментов. На отдельные модули кода программу разбивают, главным образом, чтобы упорядочить ее внутреннюю структуру. Чаще всего так поступают при разработке большой и сложной программы: блоки кода, отвечающие за работу ее отдельных компонентов, обычно помещают в отдельные модули. Глобальные объявления в любом модуле кода распространяются на всю программу. На сегодняшнем уроке мы сделаем проект, который будет иметь две формы и один модуль кода. 3. Проект prjGoods. Цель проекта. Графический интерфейс пользователя В проекте должна считаться сумма денег в рублях на покупки, которые пользователь вашей программы планирует совершить в какой-то день. Проект будет состоять из двух форм. Первая форма – входная: в ней пользователь записывает название товара, который он хочет приобрести, количество этого товара и стоимость единицы товара. Всего товаров может быть пять. Если их меньше, то соответствующие строки формы просто не заполняются. Назовем эту форму frmInput. Она может выглядеть приблизительно вот так: 2 Все тексты, которые есть на форме, сделайте в отдельных метках. Мы не будем подробно обсуждать их свойства, т. к. они будут влиять на внешнее оформление формы, но на содержательную часть проекта они влиять не будут. Оформите их по своему усмотрению. Подробно обсудим окна, в которые должна вводиться исходная информация. Для каждого товара предусмотрена своя строка. Пользователь вашей программы должен будет вписать название товара (элемент текстовое окно, название по умолчанию); количество товара (элемент текстовое окно, название txtSum1 для первого товара, txtSum2 для второго товара, …, txtSum5 для пятого товара); цену единицы товара (элемент текстовое окно, название соответственно txtPrice1, txtPrice2,…,txtPrice5). Внизу формы сделайте командную кнопку, в коде которой и будут производиться основные расчеты. Назовите ее cmdEnter. Первая форма готова. Во второй форме пользователь вашей программы должен видеть результат расчетов. Добавим сначала эту форму в проект. Это можно сделать, если выбрать в меню Project пункт Add Form или воспользоваться соответствующей кнопкой: Назовем эту форму frmOutput. Она может иметь приблизительно вот такой вид: 3 На форме frmOutput поместите метки с резюмирующим сообщением и текстом “руб.”( названия их можно оставить по умолчанию) и метку, в свойстве Caption которой будет распечатываться посчитанная сумма. Эту метку назовем lblRes. Еще на второй форме можно поместить командную кнопку для завершения работы проекта cmdExit. На этом мы закончили делать графический интерфейс пользователя. 4. Код проекта prjGoods Сформулируем сначала, что должно происходить у нас в файле первой и второй формы: пользователь вводит названия товаров, их цену и количество с помощью первой формы, потом нажимает на командную кнопку и происходит расчет – соответствующая цена умножается на соответствующее количество товара, и все эти произведения суммируются, далее из памяти выгружается файл с первой формой, загружается файл второй формы, при этом значение суммы передается во вторую форму. Во второй форме эта величина с соответствующими комментариями распечатывается как свойство Caption метки lblRes. В коде первой формы рассчет сумм денег по каждому товару будем производить в процедуре cmdEnter_Click( ), для подсчета общей суммы по всем товарам сделаем специальную процедуру Calc( ), а выгрузку первой формы и загрузку второй сделаем в отдельной процедуре Passage( ). В коде второй формы в процедуре Form_Load( ) будем присваивать свойству Caption метки lblRes значение суммы денег по всем товарам, что и увидит пользователь сразу после загрузки второй формы. Очевидно, для описанных выше целей потребуются переменные, причем разной области видимости. Переменная, в которой будет храниться общая сумма, должна быть глобальной, видимой из обеих форм. Объявим ее в файле первой формы, там, где она начинает функционировать, в глобальных объявлениях, сразу после Option Explicit: Public Summa As Single 4 Переменные, в которых будут храниться суммы по каждому товару, сделаем общими для первой формы. Во второй форме они нам уже не понадобятся. Сразу после объявления переменной Summa объявим эти переменные: Private S1 As Single , S2 As Single, S3 As Single Private S4 As Single, S5 As Single Переменные для хранения значений цен по каждому товару будут необходимы для расчетов только в процедуре cmdEnter_Click( ), поэтому сразу после заголовка процедуры объявим эти переменные: Dim C1 As Single,C2 As Single,C3 As Single Dim C4 As Single,C5 As Single Цены и количества товаров по каждому виду находятся у нас после их занесения пользователем в первую форму в виде свойства text соответствующих текстовых окон. Первое, что необходимо для проведения расчетов – это перевести их в числовой формат и присвоить значения соответствующим переменным, второе – перемножить цену на количество по каждому товару. Ниже для первого товара покажем, как произвести эти операции: С1 = Val ( txtPrice1.text) S1 = Val ( txtSum1.text) S1 = S1*C1 «Оставить» значение суммы денег, необходимой на покупку первого товара, можно в переменной S1, поскольку она будет видима из всех процедур первой формы. Заполните процедуру недостающими строками кода: Private Sub cmdEnter_Click ( ) Call Calc End Sub 5 В конце процедуры оператором Call вызывается следующая процедура кода первой формы, в которой будет вычисляться сумма денег, необходимая на покупку всех товаров. Мы назвали ее Calc. Теперь составим код процедуры Calc( ). Создадим заголовок и конец процедуры. Процедура будет выглядеть следующим образом: Private Sub Calc( ) Summa = S1 + S2 + S3 + S4 + S5 Call Passage End Sub В конце этой процедуры вызываем следующую: Passage, в которой выгрузим первую форму, загрузим вторую и покажем ее: Private Sub Passage ( ) Unload frmInput Load frmOutput frmOutput. Show End Sub Нам остается присвоить свойству Caption lblRes значение переменной Summa. Поскольку глобальная переменная Summa была объявлена в форме frmInput, то обратиться к ней можно, используя конструкцию frmInput.Summa. Тогда код загрузки второй формы будет следующий: Private Sub Form_Load( ) lblRes.Caption = frmInput.Summa End Sub Код для командной кнопки второй формы (для выхода из проекта допишите самостоятельно): Private Sub cmdExit_Click ( ) End Sub 5. Добавление к проекту prjGoods модуля для вычисления суммы в долларах Чтобы наши рассуждения в пункте 2 настоящего урока по поводу модулей кода не остались чисто теоретическими и чтобы «увидеть» в модуле кода глобальные переменные, давайте для нашего проекта создадим отдельный модуль, в котором посчитаем, какова же будет сумма денег на все покупки в долларах. 6 Добавим, как описано в пункте 2, модуль. Пусть он будет называться Module1, как и предлагает нам Visual Basic по умолчанию. В нем объявим глобальную переменную для суммы в долларах Sdollar: Public Sdollar As Single В модуле сделаем процедуру с объявлением Public, в которой значение переменной Summa будет переводиться в доллары путем деления Summa на константу conConv (соотношение рубля и доллара). Для упрощения в объявлении зададим ее равной 26. Тогда Module1 будет содержать следующие строки кода: Option Explicit Public Sdollar As Single Public Sub Dollar( ) Const conConv As Single = 26 Sdollar = frmInput.Summa / conConv End Sub В процедуру формы frmInput Passage( ) первой строкой вставим вызов процедуры Dollar( ): Call Dollar В форму frmOutput вставим метку lblResDollar, в свойстве Caption которой будем показывать сумму в долларах. В код Form_Load( ) добавим строку: lblResDollar.Caption = Sdollar Попробуйте сделать все эти добавления, и в вашем проекте будет рассчитываться и показываться еще и сумма в долларах. Результат может выглядеть, например, так: 7 6. Статические переменные Большинство локальных переменных, созданных внутри процедуры, становятся не нужны после завершения процедуры. Однако бывают случаи, когда необходимо сохранить значение переменной после того, как процедура выполнена. Это бывает, когда процедура вызывается несколько раз и ее значение зависит от ее предыдущего значения. Для создания такой локальной переменной, сохраняющей свое значение после завершения процедуры, в объявлении этой переменной необходимо использовать ключевое слово Static. Оно сообщает Visual Basic, что область действия переменной ограничивается процедурой, но переменная должна после выполнения процедуры сохранить свое значение. Статические переменные обычно используются в событиях таймера. 7. Проект prjStatVar Для того, чтобы понять, в чем особенности переменных, объявленных как статические, сделаем небольшой проект. На форму с именем frmStat и свойством Caption, равным строке “Статическая переменная”, поместим метку с именем lblLimit, свойство Caption у нее зададим равное пустой строке. Кроме этого на форму поместим еще таймер. Оставим значение свойства name у него таким, как дал ему по умолчанию Visual Basic – Timer1. Свойство Interval у таймера зададим равным 2000. Определим в процедуре Timer1_Timer( ) переменную I как статическую и будем увеличивать в этой процедуре значение переменной I на единицу, а в метке, в свойстве Caption печатать значение переменной. Код в нашем проекте будет следующий: Private Sub Timer1_Timer ( ) Static I As Integer lblLimit.Caption=“Текущее значение переменной I:”+Str(I) I=I+1 End Sub Если теперь запустить проект, можно увидеть, что значения переменной I увеличиваются на единицу каждый раз по событиям таймера. Это говорит о том, что после окончания работы процедуры значение переменной I сохраняется, и следующее событие таймера увеличивает ее на единицу. Давайте теперь попробуем в объявлении переменной I вместо слова Static поставить Dim. Запустив проект, можно увидеть, что значение переменной I перестало изменяться. Оно теперь все время равно нулю. Теперь после каждого события таймера значение переменной I теряется, оно каждый раз приравнивается первому – нулевому значению. Выполните проект на компьютере и проанализируйте результаты его работы. 8 8. Определяемые пользователем типы (структуры) В Visual Basic можно не только пользоваться стандартными типами данных, но и создавать свои. Для решения многих задач часто требуется скомпоновать данные по какомулибо признаку. Рассмотрим это на конкретном примере. Допустим, вам на лето дали список книг, которые надо прочитать. В начале лета вы решили составить список и хранить данные по книгам в компьютере, занося в него данные по названию книги, автору и количеству страниц. Скорее всего вы начали свою программу с такого рода объявлений: Dim book1_author As String Dim book1_title As String Dim book1_page As Integer Это по первой книге. Аналогично – по второй: Dim book2_author As String Dim book2_title As String Dim book2_page As Integer Гораздо проще объявить необходимые информационные компоненты один раз, а потом ссылаться на них. Visual Basic предлагает следующее решение этой проблемы: создать свой тип данных. Пользовательские типы конструируются на основе существующих типов: целых, строковых, вещественных и т. д. Ключевое слово Type служит признаком объявления пользовательского типа: Type Book Author As String Title As String Page As Integer End Type Это определение типа объединяет те информационные компоненты, которые вы считаете важными для описания книг. Пока вы сообщили системе только о структуре данных, но не выделили для них память. После того, как вы определили новый тип, можно создавать переменные, как обычно, ссылаясь на этот тип. Например: Dim Book1 As Book Dim Book2 As Book Эти операторы создают переменные Book1 и Book2, т. е. резервируют участок памяти, и присваивают им соответствующие имена. В каждой 9 переменной содержатся компоненты объявленного вами типа данных. Используя переменную Book1, вы ссылаетесь на все данные (автора, название, количество страниц) этого типа одновременно. Если нужно сослаться на отдельный компонент типа, нужно поставить за именем переменной разделитель (точку) и указать имя компонента. Например, Book1.author – компонент данных символьного типа, в котором хранится фамилия автора первой книги. Объявив новый тип данных, вы добиваетесь упорядоченности. Атрибуты в операторе Type четко увязаны с названием типа Book. Достаточно одного взгляда, чтобы понять: переменные Book1 и Book2 – переменные одного типа. Вы можете легко проверить, какую конкретную информацию они содержат. Если вы захотите усовершенствовать программу, например, чтобы добавить в набор данных такой параметр, как название издательства, вам нужно просто изменить оператор Type. Тем самым вы обновите определение всех переменных. Если же вам понадобится увеличить список книг еще на одну книгу, вы просто введете в программу еще одну переменную, объявив ее, например оператором Dim Book3 As Book 9. Проект prjBooks Для того, чтобы опробовать работу с созданным вами типом данных, сделаем следующий проект. Пользователь должен с помощью вашего проекта сформировать список из пяти книг (меньше можно, а больше нет) с указанием автора, названия и количества страниц с помощью формы frmBookInput, а после того, как ввод данных будет закончен, распечатать этот список с помощью формы frmBookOutput. Сначала создадим модуль кода, в общей части которого определим свой новый тип Book Public Type Book Name As String * 50 Author As String * 40 Page As String *5 End Type Здесь же определим пять глобальных переменных данного типа: Public BookOne As Book Public BookTwo As Book Public BookThree As Book Public BookFore As Book Public BookFive As Book 10 Для каждой книги у нас будет своя переменная. После этого сделаем графический интерфейс пользователя для формы frmBookInput. Для ввода названия книги на форму поместим текстовое окно txtName, для ввода фамилии автора – txtAuthor, для ввода количества страниц – txtPage. Свойство Text приравнено пустой строке. Пользователь заполняет для книги все данные и, чтобы они запомнились, нажимает на соответствующую командную кнопку. Для каждой книги разместим на форме командную кнопку: cmdBookOne – для первой книги, cmdBookTwo – для второй, cmdBookThree – для третьей, cmdBookFore – для четвертой, cmdBookFive – для пятой. Для перехода на следующую форму можно сделать еще одну командную кнопку cmdExit. В ее свойство Caption можно поместить строку «Ввод закончен». Форма может выглядеть приблизительно вот так: Составим код для формы frmBookInput. Для первой командной кнопки код может выглядеть, например, так: Private Sub cmdBookOne_Click() BookOne.Name = txtName.Text BookOne.Author = txtAuthor.Text BookOne.Page = txtPage.Text txtName.Text = “” txtPage.Text = “” txtAuthor.Text = “” End Sub 11 В первой части кода содержание свойства Text заносим в соответствующие компоненты переменной BookOne, а во второй части очищаем текстовые окна, подготавливая их для следующей книги. Составьте коды для командных кнопок cmdBookTwo, cmdBookThree, cmdBookFore, cmdBookFive. Private Sub cmdBookTwo_Click() End Sub Private Sub cmdBookThree_Click() End Sub Private Sub cmdBookFore_Click() End Sub Private Sub cmdBookFive_Click() End Sub В коде кнопки cmdExit выгрузим форму frmBookInput, загрузим форму frmBookOutput и покажем ее. Составьте код самостоятельно: Private Sub cmdExit_Click( ) End Sub Осталось сделать форму frmBookOutput и написать для нее код. На этой форме должен распечатываться список книг, данные по которым были введены ранее. Сделаем на форме две командные кнопки cmdExit – для выхода из программы и cmdOut для того, чтобы после нажатия на эту кнопку пользователь увидел список книг, красиво распечатанный на форме. Код для распечатывания текста напишем в процедуре cmdOut_Click( ). Допишите код до конца или сделайте его самостоятельно: Private Sub cmdOut_Click() Print frmBookOutput.FontBold = True frmBookOutput.FontSize = 16 Print “Книга первая:” frmBookOutput.FontBold = False frmBookOutput.FontSize = 14 Print ; Tab(3); BookOne.Author Print ; Tab(6); BookOne.Name 12 Print ; Tab(9); “Количество страниц – “; BookOne.Page Print End Sub Размеры формы сделайте соответствующими размерам распечатываемого текста. Опробуйте работу своего проекта. Исправьте ошибки. Результат может быть, например, такой: 10. Задания а). Сделайте проект, описанный в пунктах 3, 4, 5 занятия. Если сумеете придумать и и сделать проект, имеющий не менее двух форм и модуль кода, в котором функционируют переменные разной области видимости, то он будет помещен на сервер. б). Сделайте проект prjBooks, описанный в пункте 9 настоящего занятия. Если сумеете придумать и сделать проект с пользовательским типом данных, то он будет обязательно размещен на сервере. 13