Библиотека: А. Горев, С. Макашарипов, Р. Ахаян. Эффективная работа с СУБД
Глава 4 Основы языка программирования
- 4.1. Что такое язык программирования
- 4.2. Как написать программу
- 4.3. "Горячая десятка"
- 4.4. Еще несколько навязчивых советов
Авторы, обладая гипертрофированным самомнением, полагают, что эту книгу будут читать люди с самой разной степенью компьютерной подготовки.
Возможно даже, что она попадется тем, кто слышал о программировании,
как о занятии достаточно странных, обычно бородатых людей, бормочащих
о каких-то нулях и единицах. На самом деле этот страшный образ порожден
довольно давно, и истории про нули и единицы не имеют непосредственного
отношения к современным СУБД для персональных компьютеров, которые
оснащены языковыми средствами, позволяющими достаточно легко написать
простую программу.
В этой главе мы попробуем дать основные сведения о языке программирования Visual FoxPro читателям, которые от работы с диалоговыми средствами
хотят перейти к написанию пользовательской программы. Для тех, кто
уже пишет такие программы, мы систематизировали справочный материал
и дали несколько советов по наиболее эффективных приемам программирования
в рассматриваемых средствах разработки.
4.1. Что такое язык программирования
В предыдущей главе мы познакомились с основными действиями, которые можно выполнить с помощью диалоговых средств в визуальной среде разработки.
Очевидно, что, работая с СУБД, некоторые действия приходится выполнять
многократно. Например, открывать одни и те же таблицы. Многие функции
работы пользовательского приложения невозможно реализовать, используя
только визуальные средства. Решить эти проблемы можно с помощью языка
программирования.
В этом параграфе вы узнаете:
- Из чего состоит язык программирования.
- Где могут храниться нужные данные.
- С помощью каких средств можно выполнять какие-либо действия
с данными.
- Как делятся в программе переменные и массивы по области
действия.
При попытке описания языков программирования в рассматриваемых
средствах разработки авторы столкнулись с достаточно большими трудностями.
Не сомневаясь в своих интеллектуальных способностях, вину за это они
целиком и полностью возложили на сами языки, а пособниками признали
тех, кто их придумал - разработчиков из Microsoft.
Действительно, так как СУБД Access использует язык программирования
Visual Basic, то остается рассказать о нем и языке программирования
Visual FoxPro. Эти языки программирования имеют достаточно много общих
черт, но одна из них - богатое историческое наследие -
привела к тому, что современные объектно-ориентированные свойства
в них сосуществуют с традиционными структурными составляющими. Причем
число команд и функций, составляющих структурную основу языка, перевалило
далеко за тысячу. Чтобы разобраться в этой лавине, начнем со структурной
части рассматриваемых языков, а в следующей главе изучим их объектно-ориентированные
возможности. При этом мы будем стараться максимально выделять общие
черты рассматриваемых языков программирования и заранее приносим свои
извинения опытным разработчикам за игнорирование каких-то, может быть,
и достаточно важных особенностей каждого языка. Например, в наследство
от Xbase в Visual FoxPro до сих пор можно символьные значения указывать
не только в кавычках, но и в квадратных скобках. В Visual Basic так
делать нельзя. Мы думаем, что стоит придерживаться общих возможностей
и указывать символьные значения в кавычках, не упоминая о квадратных
скобках.
Язык программирования представляет собой набор команд, которые
последовательно обрабатываются интерпретатором и преобразуются им
в машинный код, в свою очередь обрабатываемый микропроцессором. С
помощью команд мы выполняем какие-либо действия, аналогично выбору
команды в меню. Типичная структура команды:
- COPY TO FileName [FIELDS FieldList] [Scope][FOR lExpression]
Название команды является ключевым элементом для ее идентификации.
В связи с тем, что разработчики языка старались дать названиям команд
максимальную смысловую нагрузку для их более легкого запоминания,
в ряде случаев команды получились достаточно громоздкими. Что ж, если
вы не хотите долго стучать по клавиатуре, откроем маленький секрет.
Например, в Visual FoxPro названия команд в большинстве случаев можно
сокращать до четырех символов. Если в каком-то случае так делать нельзя
из-за опасности потерять уникальность идентификации, об этом обязательно
будет написано в справочном файле Visual FoxPro при описании данной
команды.
Опции служат для уточнения действия, выполняемого командой.
В данном примере можно использовать опцию FIELDS для указания списка
тех полей, которые будут копироваться в новый файл.
Часть команды, обозначенная словом Scope, позволяет
задать диапазон записей, на которые будет воздействовать команда.
Если мы используем эту возможность, то в команде вместо слова Scope
надо использовать один из перечисленных вариантов:
ALL - все записи в таблице;
NEXT nRecords - указанное число записей после текущей
(включая текущую);
RECORD nRecordNumber - запись с указанным номером;
REST - записи от текущей до конца таблицы.
Условие выполнения команды FOR позволяет предопределить выполнение
команды в зависимости, например, от содержания данных в полях.
Для обработки информации мы можем использовать данные, хранящиеся
в таблицах или в памяти компьютера. В последнем случае для данных
в памяти, которые называются переменными, мы должны определить идентификатор,
ссылаясь на который можно однозначно установить, какие данные мы имеем
в виду. Для хранения в памяти однородных данных используются массивы.
Таблица 4.1. Способы представления данных
Способ представления | Описание |
Константы | Единичные элементы данных, записываемые в программном коде и неизменяемые в процессе работы |
Переменные | Единичные элементы данных, хранящиеся в оперативной памяти (ОЗУ) |
Массивы | Множество элементов данных, хранящихся в ОЗУ |
Записи в таблицах | Множество строк, содержащих заранее определенные
поля, каждое с предопределенным фрагментом данных, хранящихся в файле таблицы |
Константы часто используются для включения в выражения каких-то предопределенных данных, которые не изменяются во время работы программы.
В качестве констант мы можем использовать данные различных типов:
- Символьные данные записываются в кавычках. Например,
мы можем запомнить слово имя, используя его указание в кавычках:
"Имя".
- Данные типа "дата" или "дата и время"
в Visual FoxPro записываются в фигурных скобках: {10/10/95}. В Visual
Basic функции этих двух типов данных выполняет один тип данных "дата
и время". Данные этого типа выделяются значками "решетка":
#10/10/95#.
- Числовые данные используются без каких-либо разделителей.
- Логические данные в качестве константы могут принимать
одно из двух значений. В Visual FoxPro при записи они ограничиваются
точками: ".T." - соответствует истине (True), ".F."
- ложному значению (False). В Visual Basic присваивание любого
отличного от нуля значения установит константу в значение True, и
только 0 - в значение False.
Для работы с данными используются операторы, перечень которых
приведен в табл. 4.2. Для того чтобы вспомнить обозначение типа данных,
вернитесь к табл. 3.2.
Помните, что с одним оператором необходимо использовать данные одного типа!
Многие из приведенных в табл. 4.2 операторов знакомы нашим
читателям со школьной скамьи. Для некоторых же из этих операторов
требуется более пространное пояснение.
- Оператор "$" используется для поиска символа
или набора символов в каком-либо символьном выражении или поле примечаний.
Искомый символ указывается слева от этого оператора.
- Оператор "==" отнюдь не то же самое, что оператор
"=". Если последний можно идентифицировать словом "равно",
то для первого больше подходит название "идентично". Например,
если мы будем искать данные по условию cName = "ИВАН", то
Visual FoxPro будет считать верным результат, если найдет значения
"ИВАНОВ", "ИВАНЕНКО", так же как и указанное слово
"ИВАН". Если же в выражении для поиска указать оператор "==",
то к верному результату приведет только найденное слово "ИВАН".
Это различие очень удобно использовать для поиска данных по неполному
соответствию, когда точно неизвестно искомое значение.
Поля, переменные, константы, функции и операторы представляют
собой элементы для составления выражений. При написании выражений
необходимо учитывать приоритет выполнения операций:
- Возведение в степень
- Умножение и деление
- Сложение и вычитание
- Сложение символьных выражений
- Операции сравнения
- NOT
- AND
- OR
При необходимости изменения порядка действий следует использовать скобки.
Переменные в программе имеют строго определенные области действия и по этому признаку делятся на три типа.
Локальные переменные (private) существуют только во
время работы процедуры или программного файла (модуля), в котором
они были определены. По умолчанию всем переменным, определяемым в
программе, присваивается статус локальных. Явно определить статус
переменной в Visual FoxPro можно командой
- PRIVATE MemVarList | PRIVATE ALL [LIKE Sceleton
| EXCEPT Sceleton]
В Visual Basic для этого используется команда
- Dim VarName [([Subscripts])] [As [New] Type][, VarName [([Subscripts])] [As [New] Type]]...
или
- Static VarName [([Subscripts])] [As [New] Type][, VarName [([Subscripts])] [As [New] Type]]...
В последнем варианте объявленные переменные сохранят свои значения до конца работы программы.
Важная особенность локальных переменных заключается в том, что если
они были определены с теми же именами, которые были объявлены ранее
(в программе более высокого уровня), то после завершения работы программы
"старые" значения будут восстановлены. Таким образом, локальные
переменные, созданные в какой-либо процедуре, будут действовать и
во всех вызываемых из нее процедурах и функциях, но перестанут быть
доступными, как только мы возвратимся из создавшей их процедуры на
более высокий уровень. Опции команды в Visual FoxPro позволяют не
приводить полный список всех переменных, а использовать для их идентификации
шаблон, который с помощью символов "*" и "?" укажет
распространение действия команды на переменные, имена которых соответствуют
шаблону (LIKE), или на переменные, имена которых не соответствуют
приведенному шаблону (EXCEPT). Напомним, что шаблон обычно включает
общую часть имени и знаки замещения "?" и "*", первый
замещает один алфавитно-цифровой символ, а второй - любое их
число. Это позволяет знаком "*" задавать все имена, а несколькими
знаками "?" имена соответствующей длины.
В Visual Basic мы должны перечислить все объявляемые переменные.
При большом количестве однотипных переменных более эффективно использовать вместо них массивы, то есть одно- или двумерные таблицы переменных
под общим именем. Обращение к элементам массива производится с помощью
указания после имени массива в круглых или квадратных скобках нужных
номеров строк и (или) столбцов. Перед использованием массивов в Visual
FoxPro их надо объявить командой
- DIMENSION ArrayName1(nRows1 [, nColumns1]) [, ArrayName2(nRows2 [, nColumns2])] ...
Каждый массив может содержать не более 65000 элементов, то есть предельная
размерность двумерного массива может составить 254x255,
1000x65 и т. п. В последнем случае nRows1 =1000 и nColumns1=65,
если значение nColumns1 не опpеделено, то массив одномеpный.
После объявления массива по умолчанию всем его элементам присваивается
логический тип данных со значением .F..
В Visual Basic задать массив можно в команде Dim, указав его размерность в параметре Subscripts.
Для задания нужного типа данных, а это относится и к переменным, в Visual FoxPro необходимо использовать команду
- STORE Expression TO MemVarList | ArrayList
или использовать присвоение
- MemVar | Array = Expression
= Пpи указании идентификатоpа массива без аpгументов указанное
значение Expression пpисваивается всем элементам массива. Например:
- DIMENSION aMembers(4,2)
- STORE 5 TO aMembers
В Visual Basic такая же процедура будет выглядеть следующим образом (нам придется использовать цикл, о чем мы будем говорить в дальнейшем):
- Dim aMembers(4,2), nX As Integer
- For nX = 0 To 4
- aMembers(nX) = 5
- Next nX
Для определения переменной типа даты в Visual FoxPro можно использовать следующую команду, которая одновременно присвоит ей нулевое значение:
- STORE CTOD('. .') TO dDate
или
- STORE {} TO dDate
Для присвоения конкретного значения лучше воспользоваться вариантом с фигурными скобками, например:
- SET DATE GERMAN
- STORE {01.01.91} TO dDate
Для форматирования значения даты в Visual FoxPro удобно использовать установочную команду SET DATE.
В Visual Basic присвоение значения даты можно выполнить следующим образом:
- Dim dToday As Date
- dToday = #1/11/96#
А для форматирования даты надо использовать функцию
- Format(Expression [, Format [, FirstDayOfWeek
[, FirstWeekOfYear]]])
Например:
- dDate = Format(dToday, "dd.mm.yy")
Возвращает значение переменной dToday в виде 01.11.96.
Глобальные переменные (public) будут сохранять свои значения во всех программных файлах и вызываемых ими процедурах. Для объявления
переменных и элементов массива глобальными в Visual FoxPro используется команда
- PUBLIC MemVarList | [ARRAY] ArrayName1(nRows1 [, nColumns1]) [, ArrayName2(nRows2 [, nColumns2])]...
В Visual Basic такая команда будет выглядеть аналогично команде Dim
- Public VarName [([Subscripts])] [As [New] Type][, VarName [([Subscripts])] [As [New] Type]] ...
Лишь после объявления глобальным переменным можно присвоить какие-либо значения.
Внутренние переменные (local) действуют только в пределах процедуры
или функции, в которых были созданы. К ним нельзя обратиться из программы
или функции ни более высокого, ни более низкого уровня. Объявить переменные
внутренними в Visual FoxPro можно командой
- LOCAL MemVarList | [ARRAY] ArrayName1(nRows1
[, nColumns1])
[, ArrayName2(nRows2 [, nColumns2])] ...
В Visual Basic для этой цели можно использовать команду Dim.
Вы должны сначала объявить переменные или массивы внутренними и только потом присвоить им необходимые значения. После выхода из процедуры
или функции, в которой были созданы внутренние переменные, они будут
удалены из памяти.
Региональные переменные или массивы (regional) могут использоваться
только в Visual FoxPro. Они подобны локальным и объявляются с помощью
команды
- REGIONAL MemVarList
Перед командой помещается директива
- #REGION nRegionNumber
с указанием номера региона nRegionNumber (от 0 до 31), в котором действуют переменные, перечисленные в списке MemVarList. В
регионе с другим номером та же переменная может иметь другое значение.
4.2. Как написать программу
В этом параграфе мы научимся составлять очень простые
программы, которые будут работать в
- СУБД Visual FoxPro;
- Visual Basic;
- СУБД Access.
Писать даже самую простую программу непросто. Из рассматриваемых средств разработки легче всего сделать это в Visual FoxPro. С него
и начнем.
Чаще всего самым трудным бывает первый шаг. Не будем искать
трудностей и просто избежим этого первого шага. Поручим это самой
СУБД, пусть сама напрягает свои "электронные мозги".
Обратите внимание, что при выполнении каких-либо действий
в интерфейсе Visual FoxPro в окне Command автоматически записывается
соответствующая команда. Если несколько последовательных команд перенести
в программный файл, то получится программа. Если ее запустить, несколько
действий, которые мы до этого делали с помощью меню и соответствующих
диалоговых окон, будут выполнены сразу без нашего непосредственного
вмешательства.
Если мы захотим из таблицы SPPOS.DBF, содержащей список поставщиков,
прочитать данные, относящиеся к фирме с названием "Компьютерное
образование", мы должны из меню File выбрать команду Open,
установить тип файла и из списка выбрать SPPOS.DBF. Из меню Database
выбрать команду Browse и найти запись, относящуюся к указанной
фирме.
Программно тот же результат можно получить, набрав в окне Command следующие команды:
- USE Sppos
- BROWSE
- LOCATE FOR Company = "Компьютерное образование"
Если приведенная выше последовательность команд будет записана в файле, мы получим простейшую программу. Это может быть сделано несколькими
способами. Например, можно из меню File выбрать команду New,
установить тип файла Program. Откроется окно Редактора FoxPro. В нем
можно набрать указанные строчки или скопировать их из окна Command.
При закрытии окна редактирования будет необходимо указать имя файла,
которое в дальнейшем и будет являться именем программы.
Для изменения или дополнения программы необходимо ее открыть
с помощью команды Open в меню File.
Если вы взялись за разработку программ, то вам часто придется
проделывать эту операцию и работать с редактором Visual FoxPro. Поэтому
уделим ему немного внимания. Начнем с конфигурации, ведь от того,
насколько удобно установлены те или иные параметры работы редактора,
зависит производительность вашего труда.
Откройте какой-либо файл с программой или создайте новый
файл. Выберите команду Options в меню Tools. В появившемся
диалоговом окне найдите вкладку Edit. Доступные установки для редактора
видны из рис. 4.1.
Рис. 4.1.
При первом запуске программы и в последующем, при ее изменении,
FoxPro компилирует исходный код программы в так называемый препроцессорный
код, или "p-код", который выполняется во много раз быстрее
интерпретируемой программы. Файлы с "p-кодом" получают другое
расширение. Обратите внимание на очень удобную возможность компиляции
программы перед ее сохранением. Включение этой опции позволяет сразу
определить синтаксические ошибки, выявляемые на этом этапе, -
недостаток или отсутствие запятых, неправильное написание ключевых
слов и т. д.
В связи с тем, что редактор Visual FoxPro используется не
только для работы с файлами программ, но и вообще для редактирования
текстовых данных, например в полях примечаний, то перечень доступных
опций в диалоговом окне Options зависит от типа окна, которое было
активным перед его вызовом. Например, если активным окном было окно
с данными поля примечаний, то внешний вид окна Options будет таким,
как это видно на рис. 4.2. Естественно, при этом некоторые опции,
например компиляции, будут недоступны.
Рис. 4.2.
При работе с редактором мы можем использовать команды, которые располагаются в меню Edit и Format. Еще удобнее использовать
клавиатурные комбинации, перечень которых приведен в табл. 4.3. Не
забудьте также о кнопках на стандартной панели инструментов. При наборе
программы в редакторе очень удобно использовать макросы.
Макросом называется предварительно записанная последовательность
команд, которая выполняется при его запуске. Для запуска макроса чаще
всего используются клавиатурные комбинации.
В Visual FoxPro макрос можно записать с помощью соответствующей
команды в меню Tools. Появляющееся при этом диалоговое окно
представлено на рис. 4.3.
Рис. 4.3.
В своей работе вы можете использовать несколько наборов макросов,
сохраняя их в соответствующих файлах. Для сохранения и загрузки необходимых
макросов надо использовать кнопки, расположенные внизу диалогового
окна.
Для записи макроса нажмите кнопку New. Появится диалоговое
окно для создания и редактирования макросов, представленное на рис. 4.4.
Нажмите клавиатурную комбинацию, с помощью которой вы хотите в дальнейшем
вызывать данный макрос.
Рис. 4.4.
Таблица 4.3. Комбинации клавиш, используемые при работе с редактором
Комбинация клавиш | Пункт меню | Выполняемое действие |
Ctrl+A | Select All | Выделить весь текст в окне редактора |
Ctrl+C | Copy | Скопировать выделенный текст |
Ctrl+F | Find | Найти |
Ctrl+L | Replace | Заменить |
Ctrl+R | Redo | Вернуть отмененное действие |
Ctrl+V | Paste | Вставить фрагмент текста из буфера в место нахождения курсора |
Ctrl+W | - | Закрыть редактор и сохранить все сделанные
изменения |
Ctrl+X | Cut | Вырезать выделенный текст |
Ctrl+Z | Undo | Отменить сделанное действие |
Ctrl+Home | - | Переместить курсор в начало текста |
Home | - | Переместить курсор в начало строки |
Ctrl+End | - | Переместить курсор в конец текста |
End | - | Переместить курсор в конец строки |
В качестве примера мы с вами создадим макрос для автоматического набора какой-нибудь сложной команды. Пусть это будет команда задания
цикла FOR...NEXT. Такие структурные команды чаще всего вызывают
ошибки, так как тело цикла может занимать десятки строк и, разбираясь
в его перипетиях, программист забывает о необходимости закрытия цикла.
Присвоим этому макросу клавиатурную комбинацию Ctrl+F.
Тогда по умолчанию он получит имя ctrl_f. Не следует пытаться присвоить
макросу клавиатурную комбинацию, которая уже используется в Visual
FoxPro. Теперь в поле Macro Contents наберем такой текст:
- FOR{ENTER}{ENTER}NEXT
В фигурных скобках мы указали название клавиш, нажатие которых нам надо имитировать в данный момент. В этом примере мы имитируем двухкратное
нажатие клавиши Enter для перехода на следующую строку и тем
самым создаем внутри команды пустую строку для записи тела цикла.
Как правильно записать в макросе названия других клавиш и их сочетаний
можно узнать, изучив длинную таблицу в справке к команде ON KEY
LABEL после вызова контексной помощи.
Теперь, работая в редакторе, мы всегда можем нажать клавиши Ctrl+F и в программе у нас автоматически появятся следующие три строчки:
- FOR
- NEXT
Программа в FoxPro - это текстовый файл, содержащий
набор команд, написанных в соответствии с синтаксическими правилами
языка. Программа может иметь подпрограммы (процедуры), в которые помещаются
часто повторяющиеся фрагменты кода, размещаемые после основного текста
программы или в отдельном файле. Подпрограмма начинается с ключевого
слова
- PROCEDURE ProcedureName
и выполняется, пока не будет выполнено одно из следующих условий:
- Еще раз встретится слово PROCEDURE.
- Будет обнаружена команда RETURN - возвращение
в предыдущую программу.
- Будет выдана команда CANCEL - прерывание работы программы.
- Будет выдана команда QUIT - выход из СУБД.
- Встретится новая команда DO для запуска другой программы.
- Будет достигнут конец файла.
В FoxPro аналогично подпрограмме трактуется понятие пользовательской функции, которая начинается с ключевого слова
- FUNCTION FunctionName
и в отличие от процедуры, может вернуть необходимые значения в вызывающую программу.
Имеются четыре способа вызвать функцию:
- Присвоить возвращаемое значение переменной. Например, следующая
строка кода запоминает текущую системную дату в переменной dToday:
dToday = DATE()
- Включить вызов функции в команду. Например, следующая команда
устанавливает по умолчанию каталог, имя которого возвращает функция
GETDIR():
SET DEFAULT TO GETDIR()
- Напечатать возвращаемое значение в активное окно:
? TIME()
- Вызвать функцию без запоминания где-либо возвращаемого значения:
SYS(2002)
Для прерывания выполнения программы служит оператор
RETURN [Expression | TO MASTER | TO ProgramName]
который возвращает управление в вызывающую программу, и в ней выполняется следующая команда после вызывающей; если указана опция TO MASTER,
то управление возвращается на самый верхний уровень вызывающей программы,
а эта же программа с опцией TO ProgramName передает управление в указанную
программу. При использовании в функции команда автоматически возвращает
.T., если не указано другое выражение на месте Expression.
RETRY
действует подобно команде RETURN, но при возвращении управления в вызывающую программу повторяется выполнение последней команды.
Создайте новый программный файл и наберите в редакторе приведенный
ниже текст. В этой программе объявляется массив, элементы которого
принимают значения от 1 до 10. Каждое присвоение значения сопровождается
появлением на экране сообщения с указанием присвоенной величины. Посмотрите
на сообщения, выводимые этой программой на экран.
- * Пример простейшей программы
- DIMENSION aSampleArray(10)
- FOR nItem = 1 TO 10
- aSampleArray(nItem) = nItem
- = Append_proc()
- NEXT
- FUNCTION Append_proc
- ? "В массив добавлено новое значение "
- ?? nItem
Если эта программа показалась вам слишком примитивной, то без сомнения
вы правы. По мере чтения книги и расширения лексического запаса языка
(набора команд и функций), вы сможете сочинять куда более полезные
вещи.
Теперь посмотрим на Visual Basic. Это средство разработки настолько
сфокусировано на визуальных возможностях разработки программ, что
написать вручную несколько строк кода, запустить их на выполнение
и тут же увидеть результат не так просто для начинающего программиста,
как в Visual FoxPro. Однако попробуем это сделать.
Начнем с задания команды Options меню Tools. В появившемся
диалоговом окне настройки конфигурации Visual Basic выберем вкладку
Project (рис. 4.5). В раскрывающемся списке Startup Form вместо
значения, установленного по умолчанию, - Form1, выберем Sub
Main. Значение Form1 обеспечивает запуск в качестве главной программы
визуальной формы с этим именем по умолчанию. Значение Sub Main позволяет
в качестве запускаемой программы использовать процедуру.
Рис. 4.5.
Создадим в проекте программный модуль путем выполнения команды Module
в меню Insert. Потом в этом же меню выполним команду Procedure.
В появившемся диалоговом окне, показанном на рис. 4.6, напишем имя
создаваемой процедуры - Main, для типа процедуры выберем Sub,
а для диапазона действия - Public. После нажатия кнопки OK в
окне программного модуля появится шаблон, готовый для написания программного
кода.
Рис. 4.6.
Здесь следует заметить, что редактор в Visual Basic по своим функциальным
возможностям и принципам работы с текстом программы похож на редактор
Visual FoxPro. В Visual Basic нет макросов, зато редактор обеспечивает
выделение цветом ключевых слов, строк с ошибками и т. д. Цвет в
редакторе существенно помогает избежать случайных ошибок. При этом
вы можете сами устанавливать цвет для различных ситуаций, как это
видно из рис. 4.7, на котором показано диалоговое окно Options,
открытое на вкладке Editor.
Рис. 4.7.
Теперь мы можем попробовать создать простейшую программу по аналогии
с той, которую мы написали в Visual FoxPro. В окне программного модуля
в раскрывающемся списке Proc выберите пункт (declarations), как это
показано на рис. 4.8.
Рис. 4.8. Пример простейшей программы в Visual Basic
Наберите следующую строчку для объявления используемого массива и переменной как целых чисел:
Dim aSampleArray(10), nItem As Integer
Переключитесь в раскрывающемся списке Proc на пункт Main и наберите следующий текст:
- Public Sub Main()
- For nItem = 1 To 10
- aSampleArray(nItem) = nItem
- Append_proc
- Next
- End Sub
Теперь создадим новую процедуру с помощью команды Procedure меню Insert и в ней запишем код для функции, которая будет
отображать процесс заполнения массива:
- Private Function Append_proc()
- Debug.Print nItem
- End Function
Запустим нашу программу на выполнение командой Start в меню Run. Можно воспользоваться и соответствующей кнопкой на панели
инструментов или просто нажать клавишу F5.
В отличие от Visual FoxPro в Visual Basic нельзя направить вывод результатов выполнения программы в главное окно. Его просто нет. Сначала надо
создать какое-то окно, обычно в виде формы, а затем уже в него направлять
вывод данных. Чтобы не усложнять нашу задачу, мы сознательно выбрали
простейший вариант, используя для вывода окно отладки (Debug Window).
Для этого перед командой Print необходимо указать через точку
Debug. Для того чтобы увидеть результат, откройте окно отладки командой
Debug Window в меню View.
Обратите внимание, что коды программ в Visual FoxPro и в Visual Basic очень похожи; код Visual Basic может легко читаться программистом,
знающим только Visual FoxPro, и наоборот. В то же время существуют
и определенные различия, которые с увеличением сложности программы
разрастаются. Посмотрите на команды вызова функции и объявления переменных -
в Visual Basic в отличие от Visual FoxPro мы должны явно объявить
все используемые переменные и указать их тип.
Что касается СУБД Access, то, как мы уже говорили, многие
воспринимают ее как типичное средство создания личных информационных
систем, предусматривающее использование только имеющихся в Access
диалоговых средств. Поэтому пользователи часто останавливаются на
результатах, достигнутых с помощью визуальных средств разработки,
и считают, что самостоятельное создание таблиц, не говоря уже о создании
форм и отчетов, это нечто из ряда вон выходящее. На самом деле все
не совсем так, и стоит относиться к Мастерам как к чернорабочим, которые
строят каркас здания, а отделкой лучше заниматься самостоятельно.
Программистов при переходе к Access из процедурного языка
или среды с командной строкой обычно удручает отсутствие непосредственной
возможности написать команду или процедуру, создать базу данных и
при желании добавить тем же путем таблицы, формы или отчеты. При первом
запуске Access этой возможности действительно нет. Вы не можете написать
ни строчки кода, пока не создадите базу данных или не откроете уже
созданную.
Вы можете создать какую-либо процедуру после открытия контейнера
БД. Для создания программ в Access используется язык программирования
Visual Basic, о котором мы уже говорили. Перейдите на страницу Модули
контейнера базы данных и создайте новый модуль. Меню Access слегка
видоизменится. Надо привыкнуть, что меню динамически меняется, то есть
при смене объекта, с которым вы работаете, загружается новое меню.
Теперь можно набрать следующую строчку
Sub Ясоздаюбазуданныхвручную()
Не забудьте, что каждая процедура должна заканчиваться командой End Sub, но набирать эту строчку не обязательно - после
нажатия клавиши Enter она появится автоматически.
Ваша процедура должна выглядеть следующим образом:
- Sub ЯсоздаюБазуДанныхВручную()
- Dim MyDb As DATABASE
- Set MyDb =_ DBEngine.Workspaces(0).CreateDatabase("МояБазаДанных",_ dbLangCyrillic)
- End Sub
Чтобы запустить эту процедуру на исполнение, выведите на экран окно отладки и наберите в нем название процедуры, возможно, у вас она будет
называться по-другому. После этого можете смело нажимать клавишу ввода,
уверяем, что база данных у вас появится.
Для того чтобы в программе можно было разобраться хотя бы на следующий день после написания, не ленитесь писать комментарий к выполняемым
действиям. Для написания строк комментария в Visual FoxPro надо в
начале строки поставить "звездочку"
* [Comments]
Знак звездочки часто используется также для разделения отдельных смысловых фрагментов программы. Строки комментария нельзя вставлять внутрь команды, если, например, она написана на нескольких строчках с использованием
символа переноса - точки с запятой.
При написании комментария на одной строке с командой текст команды и комментария разделяется двумя амперсендами:
&& [Comments]
Эти знаки можно опустить только после команд, начинающихся на END.
В Visual Basic признаком комментария является знак апострофа:
[Comments]
Он может применяться и в начале строки, и после команды на одной строке с ней.
Признаком переноса командной строки в Visual Basic является знак подчеркивания, а в Visual FoxPro - точка с запятой.
4.3. "Горячая десятка"
Если вы следовали руководящим указаниям авторов, то вам не
трудно написать простейшую программу. Если вы написали даже очень
простую программу, то вы, несомненно, можете сказать, что являетесь
программистом. Если вы являетесь программистом, то пришла пора заглянуть
в красивую коробку, в которой, мы надеемся, вы принесли от продавца
Access, Visual Basic или Visual FoxPro, и вместо Руководства пользователя
вытащить оттуда Руководство программиста. Если после всего этого у
вас упало настроение и стало рябить в глазах от длинных списков многочисленных
объектов, команд и функций, не надо впадать в отчаяние.
В этом параграфе мы попробуем взять реванш у разработчиков
Microsoft за их неуемную фантазию. Возьмем на вооружение успехи лингвистов
в деле составления частотных словарей, вообразим себя обладателями
опыта составителей музыкальных хит-парадов и составим "горячую
десятку" - расскажем о тех командах и функциях, которые сразу
продвинут вас в деле написания программ далеко вперед.
10. Пока мы учимся программировать, нам очень поможет самая простая команда вывода данных в Visual FoxPro
? | ?? Expression
Мы даем здесь не полный ее синтаксис, так как эта команда
вряд ли пригодится вам для чего-то более виртуозного, чем вывод нужного
значения в процессе разработки и отладки прикладной программы. Ее
очень удобно набирать в окне Command. Один знак вопроса всегда
выводит значение выражения Expression с новой строки, два знака
вопроса - на той же строке. В Visual Basic этой команде в наибольшей
степени соответствует конструкция
Debug.Print Expression
которая выводит значение Expression в окно отладки Debug Window.
9. Для запуска программы или для передачи управления другой программе в Visual FoxPro дайте команду Do из меню Program
и выберите файл с нужным именем, или в окне Command наберите
команду
- DO ProgramName1 | ProcedureName [WITH ParameterList] [IN ProgramName2]
Если в ProgramName1 расширение не указывается, то Visual FoxPro будет пытаться запустить эту версию программы в следующей последовательности
расширений для файла с одним и тем же именем:
- EXE - исполняемая версия.
- APP - прикладная программа.
- FXP - откомпилированная версия.
- PRG - программа.
Опция WITH используется для передачи параметров (заранее
определенных данных) в программу (число параметров не должно превышать
27). По умолчанию параметры передаются по ссылке, для передачи по
значению необходимо установить SET UDFPARMS TO VALUE. В ProgramName2
можно указать файл, в котором размещается вызываемая программа.
В Visual Basic сходные задачи выполняет команда
Call Name([ParameterList])
Как ее использовать покажем на примере вызова на выполнение подпрограммы:
- Call PrintToDebugWindow("Печать в окне отладки")
- Sub PrintToDebugWindow(cString)
- Debug.Print AnyString
- End Sub
8. Ранее мы научились определять в программе нужные нам переменные с требуемым типом данных. При обработке данных программисту в силу
различных причин часто приходится преобразовывать данные из одного
типа в другой.
В языке программирования Visual FoxPro для этого существует большое количество функций, из которых наиболее часто используемыми можно
назвать следующие:
STR(nExpression [, nLength [, nDecimalPlaces]])
Преобразует числовое выражение nExpression в строку символов. Необязательные параметры nLength и nDecimalPlaces позволяют
задать длину и число десятичных разрядов соответственно.
VAL(cExpression)
Преобразует в число строку символов, представляющую собой набор цифр.
В Visual Basic существуют аналогичные функции:
Str(nExpression)
Val(cExpression)
7. Трудно представить себе программу обработки данных, в которой программисту не пришлось бы с этими данными хоть что-то делать. С
числами все просто. В этой области мы постоянно тренируем себя при
посещении магазинов. Суммы растут, тренировки становятся все более
напряженными. Сложнее с символьными данными. И здесь мы должны включить
в почетную десятку хотя бы основные функции для работы со строками.
В Visual FoxPro по частоте употребления можно выделить следующие функции:
SUBSTR(cExpression, nStartPosition [, nCharactersReturned])
Возвращает фрагмент строки символов из строкового выражения cExpression,
начинающийся с позиции nStartPosition и длиной nCharactersReturned.
LEFT(cExpression, nExpression)
Возвращает из строкового выражения cExpression фрагмент, включающий первые nExpression символов.
RIGHT(cExpression, nExpression)
Возвращает из строкового выражения cExpression фрагмент, включающий последние nExpression символов.
ALLTRIM(cExpression)
Исключает все начальные и конечные пробелы из строкового выражения.
В Visual Basic существуют аналогичные функции:
- Mid(cExpression, nStartPosition [, nCharactersReturned])
- Left(cExpression, nExpression)
- Right(cExpression, nExpression)
- Trim(cExpression)
6. При работе с данными нам постоянно приходится думать об их "свежести", поэтому мы никак не можем обойти вниманием функции,
связанные с определением текущей даты и времени.
В Visual FoxPro для этого можно использовать следующие функции:
Для определения текущей даты
DATE()
Для определения текущего времени
TIME([nExpression])
Для определения текущей даты и времени в формате дата и время
DATETIME()
Если в функции TIME() в качестве выражения задать любую числовую величину, значение текущего времени будет возвращено с сотыми долями
секунд, хотя тогда лучше уж обратиться к функции SECONDS().
В Visual Basic существуют аналогичные функции:
- Date
- Time
- Now
5. В том случае, если необходимо многокpатно выполнять какой-либо блок команд, пока выполняется заданное условие, может быть использована
команда, которая в Visual FoxPro выглядит вот так
- DO WHILE lExpression Commands [LOOP] [EXIT]
- ENDDO
Каждый раз, когда программа достигает строки с командой DO WHILE, она проверяет значение выражения lExpression, и если оно
равно .T., то выполняются команды внутри структуры, если .F., то управление
передается строке, следующей за ENDDO. Опция LOOP позволяет после
ее указания вернуть управление к строке DO WHILE, а опция EXIT -
прекратить выполнение цикла, невзирая на значение lExpression.
Наиболее часто в качестве условия используют выражения:
- DO WHILE .NOT. EOF() - до исчерпания записей в таблице;
- DO WHILE nMin<<10 .AND. nMax>>100 - пока переменная
nMin меньше 10 и переменная nMax больше 100;
- DO WHILE .T. - бесконечно выполняемый цикл (выход только по EXIT).
Естественно, что в случае использования опций LOOP и (или) EXIT
перед ними должны быть записаны свои условия их выполнения (чаще всего
команда IF...ENDIF). Приведем простой пример организации цикла
для реакции на действия пользователя.
- DO WHILE .T.
- CLEAR
- WAIT "Наберите цифру 1 или 2" TO cNumber
- DO CASE
- CASE cNumber = "1"
- ? "Вы набрали цифру 1"
- CASE cNumber = "2"
- ? "Вы набрали цифру 2"
- OTHERWISE
- ? "Ошибка: введенное значение не 1 или 2!"
- ENDCASE
- WAIT "Хотите попробовать еще раз (Y/N)" TO cYesNo
- IF UPPER(cYesNo) <<>> "Y"
- EXIT
- ENDIF
- ENDDO
В этом примере для обеспечения ввода пользователем данных используется
простейший вариант команды WAIT, которая приостанавливает работу
программы и после нажатия пользователем какой-либо клавиши присваивает
значение этой клавиши переменной, указанной в опции TO.
В Visual Basic для записи этой команды надо использовать один из
следующих эквивалентных вариантов синтаксиса:
- Do [{While | Until} Expression] [Commands] [Exit Do] [Commands]
- Loop
или
- Do [Commands] [Exit Do] [Commands]
- Loop [{While | Until} Expression]
Как правильно использовать эту команду, видно из следующего примера:
- lCheck = True
- nCounter = 0
- Do ` Первый (внешний) цикл
- Do While nCounter << 20 ` Второй (внутренний) цикл
- nCounter = nCounter + 1
- If nCounter = 10 Then
- lCheck = False
- Exit Do ` Выход из второго цикла
- End If
- Loop
- Loop Until lCheck = False ` Выход из первого цикла
4. Если мы запишем в программу некую последовательность
команд, то они будут выполняться построчно от начала до конца программы.
Вряд ли таким образом мы сможем написать мощную программу, которая
должна обрабатывать действия пользователя в зависимости от тех или
иных условий. Нам потребуются средства для управления последовательностью
выполнения команд.
Наиболее простое ветвление программы в зависимости от
заданного условия можно обеспечить командой, синтаксис которой в Visual
FoxPro записывается в следующем виде:
- IF lExpression
- Commands
- [ELSE
- Commands]
- ENDIF
В качестве условия может быть использовано любое выражение,
в том числе и логическое. На месте команд, в свою очередь, может стоять
снова команда IF (вложенное условие). Если выражение равно .T.,
то выполняются команды, заключенные между IF и ELSE. Если .F., то
выполняются команды, следующие за ELSE, а в том случае, если эта необязательная
опция ELSE в команде не используется, выполняются команды, следующие
за ENDIF.
В Visual Basic эту команду можно записать на одной строке:
- If lExpression Then Commands [Else Commands]
или в более сложном виде:
- If Expression Then
- [Commands]
- [ElseIf Expression_n Then
- [Commands]] ...
- [Else
- [Commands]]
- End If
Если выражение Expression имеет значение True, выполняются команды, следующие за ключевым словом THEN. В противном случае выполняется
один из блоков, в котором Expression_n будет соответствовать
выражению Expression. Если и этого не произойдет, будет выполнен
блок команд, следующих за ключевым словом ELSE.
Для выбора по условию очень эффективно можно использовать
функцию, которая по смыслу похожа на рассматриваемую команду и имеет
совершенно одинаковый синтаксис как в Visual FoxPro, так и в Visual
Basic
IIF(lExpression, Expression1, Expression2)
Возвращает значение Expression1, если lExpression
=.T., и значение Expression2, если lExpression =.F.;
Expression1 и Expression2 должны быть одного типа, например:
TITLE = IIF(nSign=0,"автомобиль","автопоезд") + cModel
Эта функция может использоваться и для выбора выполняемых подпрограмм, например:
- cProc_var = IIF(nVid>>5,cProc_1,IIF(nVid<<2,cProc_2,cProc_3))
- DO (cProc_var)
Здесь, в зависимости от значения переменной nVid, будет
выполняться та или другая процедура, причем для увеличения числа вариантов
в качестве Expression2 используется еще одна - вложенная
функция IIF(). Использование этой функции для программного ветвления,
там где это возможно, значительно увеличивает быстродействие программы
и делает ее значительно меньше, чем при употреблении команды IF...ENDIF.
3. Более сложное ветвление, когда есть несколько условий,
в зависимости от которых надо выполнить ту или иную группу команд,
организуется стpуктуpной командой, которая в Visual FoxPro выглядит
так:
- DO CASE
- CASE lExpression1
- Commands
- [CASE lExpression2
- Commands]
- ...
- [OTHERWISE
- Commands]
- ENDCASE
Команда выполняет проверку условий, заданных в операторах
CASE. Они просматриваются последовательно сверху вниз, и, как только
первое из них оказывается верным (логическое выражение равно .T.),
выполняется блок команд для этого CASE, после чего управление передается
строке программы, следующей за ENDCASE. Если ни одно из условий не
истинно, выполняется опция OTHERWISE, пpи отсутствии этой опции команда
игнорируется.
Например:
- nChoice = 3
- DO CASE
- CASE nChoice = 1
- ? "Выбрано значение 1"
- CASE nChoice = 2
- ? "Выбрано значение 2"
- OTHERWISE
- ? "Выбрано неправильное значение!"
- RETURN
- ENDCASE
В Visual Basic синтаксис этой структурной команды организован несколько по-иному:
- Select Case Expression
- [Case Expression_n
- [Commands]] ...
- [Case Else
- [Commands]]
- End Select
Выполняются те блоки CASE, в которых выражение Expression_n соответствует выражению Expression. Если такого соответствия
не обнаруживается, то выполняется блок CASE ELSE.
Приведенный выше пример можно записать примерно так:
- Dim nChoice As Integer
- Select Case nChoice
- Case 1
- Debug.Print "Выбрано значение 1"
- Case 2
- Debug.Print "Выбрано значение 2"
- Case Else
- Debug.Print "Выбрано неправильное значение"
- End
- End Select
2. Цикл, помимо структуры DO WHILE, можно организовать и стандартным для большинства языков программирования способом.
Поэтому следующая команда куда популярнее предыдущей:
- FOR MemVarName = nInitialValue TO nFinalValue [STEP nIncrement]
- Commands
- [LOOP]
- [EXIT]
- NEXT
Команда FOR...NEXT обеспечивает выполнение блока
команд для каждого значения переменной, начиная со значения, равного
nInitialValue, до значения nFinalValue, пошаговое увеличение
или уменьшение происходит на величину, заданную nIncrement,
которая по умолчанию равна 1. Опция LOOP приводит к передаче управления
на начало следующего цикла, а EXIT - к прекращению действия
команды.
В Visual Basic синтаксис этой команды выглядит очень похоже:
- For MemVarName = nInitialValue To nFinalValue [Step nIncrement]
- [Commands]
- [Exit For]
- [Commands]
- Next [MemVarName]
По сравнению с Visual FoxPro здесь нет возможности "досрочно"
начать новый цикл с помощью опции LOOP.
Циклы FOR...NEXT могут быть вложены, но в этом случае
в каждом цикле должен использоваться уникальный параметр MemVarName.
В синтаксисе Visual FoxPro пример организации вложенного цикла приведен
ниже. В переменную MyString десять раз записываются значения от 0
до 9.
- MyString = " "
- FOR Words = 10 TO 1 Step -1
- FOR Chars = 0 To 9
- MyString = MyString + STR(Chars)
- NEXT
- MyString = MyString + " "
- NEXT
- ? MyString
В синтаксисе Visual Basic этот же пример будет иметь лишь
незначительные отличия:
- Public Sub Main()
- For Words = 10 To 1 Step -1
- For Chars = 0 To 9
- MyString = MyString & Chars
- Next
- MyString = MyString & " "
- Next
- Debug.Print MyString
- End Sub
В Visual Basic есть очень похожая на рассматриваемую команду
команда организации цикла:
- For Each MemVarName In ArrayName
- [Commands]
- [Exit For]
- [Commands]
- Next [MemVarName]
Эта команда позволяет выполнить какие-либо действия для группы
элементов массива, имя которого указывается в параметре ArrayName.
Вместо массива может использоваться коллекция объектов, о чем мы будем
более подробно говорить позднее.
1. Даже если мы научились составлять пока очень простенькие программы, мы должны стремиться к высоким идеалам и стараться создать
дружественный интерфейс. Здесь не обойтись без средств, позволяющих
в хорошей манере сообщать пользователям разную информацию, может и
не очень приятную, спрашивать у них совета о дальнейших действиях
и т. д. Учитывая важность этой проблемы для современного пользовательского
приложения, авторы, заранее сговорившись, на первое место поставили
следующую функцию. В Visual FoxPro она имеет такой синтаксис:
MESSAGEBOX(cMessageText [, nDialogBoxType [, cTitleBarText]])
Выводит на экран определяемое пользователем диалоговое окно.
Параметр cMessageText определяет текст, который появляется
в этом окне. Чтобы переместить часть сообщения на следующую строку
в диалоговом окне, используйте в cMessageText символ возврата
каретки (CHR(13)). Высота и ширина диалогового окна увеличиваются
по мере необходимости, чтобы вместить содержимое заданного в cMessageText
текста.
Параметр nDialogBoxType определяет кнопки и пиктограммы,
которые появляются в диалоговом окне, а также первоначально выбранную
после вывода диалогового окна на экран кнопку.
В следующей таблице приведены возможные значения для этих
элементов.
Значение nDialogBoxType | Элементы |
| Кнопки диалогового окна |
0 | Только кнопка OK |
1 | Кнопки OK и Cancel |
2 | Кнопки Abort, Retry и Ignore |
3 | Кнопки Yes, No и Cancel |
4 | Кнопки Yes и No |
5 | Кнопки Retry и Cancel |
| Пиктограмма |
16 | Знак "Стоп" |
32 | Знак "Вопрос" |
48 | Знак "Восклицание" |
64 | Пиктограмма "Информация (i)" |
| Кнопка по умолчанию |
0 | Первая кнопка |
256 | Вторая кнопка |
512 | Третья кнопка |
Пропуск значения nDialogBoxType идентичен определению
для него значения 0.
Параметр nDialogBoxType должен представлять собой
сумму трех значений - по одному из каждого раздела приведенной
таблицы.
Параметр cTitleBarText определяет текст, который появляется в заголовке диалогового окна. Если вы опускаете cTitleBarText,
в названии окна появится заглавие "Microsoft Visual FoxPro".
Возвращаемое значение функции MESSAGEBOX() указывает, какая кнопка была выбрана в диалоговом окне. В диалоговых окнах с
кнопкой Cancel при нажатии клавиши Esc будет возвращаться то
же самое значение (2), что и при выборе Cancel.
Следующая таблица содержит список возвращаемых функцией
MESSAGEBOX() значений.
Возвращаемое значение | Кнопка |
1 | OK |
2 | Cancel |
3 | Abort |
4 | Retry |
5 | Ignore |
6 | Yes |
7 | No |
В Visual Basic рассматриваемая функция имеет чуть-чуть другое написание и несколько более богатый синтаксис:
- MsgBox(cMessageText [, nDialogBoxType [, cTitleBarText] [, cHelpFileName, nContext])
Условия использования этой функции и задания ее параметров идентичны описанным выше для Visual FoxPro. В Visual Basic для некоторых параметров
можно устанавливать дополнительные значения. Так, параметр nDialogBoxType
дополнительно может принимать значение 4096, что устанавливает
модальность появляющегося сообщения на системном уровне, и пользователь
не может продолжить работать не только в текущем, но и ни в каком
другом из запущенных приложений, пока не отреагирует на данное сообщение.
Параметры cHelpFileName и nContext позволяют задать имя файла контекстной помощи и номер темы, которая будет выведена
на экран при нажатии пользователем клавиши F1.
4.4. Еще несколько навязчивых советов
Когда вы напишете пусть даже небольшую программу, посмотрите, сколько имен вы использовали. А если программа достаточно сложная? Что бы
не запутаться в громадном количестве имен, используемых в программе,
программисты давно выработали негласные соглашения, с помощью которых
здесь можно навести хоть какой-то порядок. Надо отметить, что, начиная
с версии 3.0, такие рекомендации включены и в руководство по Visual
FoxPro и по Visual Basic. Их основная идея заключается в систематизации
всех имен переменных или массивов по диапазону действия и типу хранимых
в них данных.
Таким образом, структура имени должна иметь следующий вид:
ДиапазонТип_данныхИмя
Для указания дипазона рекомендуется использовать следующие символы:
- l - внутренняя (local) lnCounter
- p - локальная (private) pnStatus
- r - региональная (region) rnCounter
- g - глобальная (public) gnOldRecno
- t - параметр (parameter) tnRecNo
В последнем столбце приведен пример наименования. Надо отметить, что в имени переменной диапазон ее действия программисты указывают редко.
В примерах, где это не имеет принципиального значения, мы тоже не
будем делать этого.
Для указания типа данных рекомендуется использовать следующие символы:
- a - массив aMonths
- c - символьные данные cLastName
- y - денежная единица yCurrentValue
- d - дата dBirthDay
- t - данные типа "дата и время" tLastModified
- b - двойной точности bValue
- l - логические lFlag
- n - числовые nCounter
- o - ссылка на объект oEmployee
- u - неопределенного типа uReturnValue
Как вы могли заметить из примеров, после обозначения диапазона действия
и типа данных, имя переменной для большей наглядности лучше начинать
с большой буквы. Не ленитесь давать имени максимальную смысловую нагрузку.
Это избавит вас от долгих раздумий: "И что же это за переменная
такая и зачем это она тут?"
Глава 3 || Содержание || Глава 5
|