КОМПЬЮТЕР

Visual Basic 6.0 Самоучитель для начинающих (в сокращении)

С.Н.Лукин

Редактор раздела: И. Трус




НАЧАЛО
ЧАСТЬ I. ПРОГРАММИРОВАНИЕ БЕЗ ПРОГРАММИРОВАНИЯ

Запускаем Visual Basic

Начинается все, конечно, с того, что вы запускаете Visual Basic. В результате запуска на экране появляется главное окно Visual Basic, в центре которого вы видите другое окно — приглашение начать создавать новый проект (см. рисунок). Если приглашение не появилось, то щелкните по пункту меню File, а затем выберите в выпавшем меню пункт Add Project — и оно появится.

(В дальнейшем вместо словесного описания щелчков мыши в меню я для краткости буду писать — File->Add project).



Вам предлагается выбрать тип проекта, который вы хотите создавать. Пока нам достаточно стандартного типа. Щелкните в окне приглашения в закладке New по значку Standard EXE, а затем по кнопке Open. Перед вами возникает следующая картинка, говорящая о том, что вы можете приступать к проектированию (внешний вид картинки у вас может быть немножко другой):



Что вас на картинке больше всего должно интересовать, так это серый прямоугольник в точечку, расположенный в центре на белом фоне. Это так называемая форма. Что же это такое — форма? Так вот, форма — это пустой стол, тот самый стол, на котором мы эту программу будем собирать. Когда вы запустите проект, форма станет окном Windows.

Обратите внимание на три черных квадратика — маркера — в правой нижней части формы. Ухватившись за них мышкой, вы можете менять размеры формы. Но таскать форму по экрану вам здесь не удастся.

Начнем работу над проектом с 1 этапа. Чтобы создать проект, нам нужны объекты — и Visual Basic нам их предоставляет. В левой части главного окна Visual Basic мы видим вертикальную серую панель. Это Toolbox (блок или палитра элементов управления), то есть набор наиболее популярных стандартных объектов, применяемых при создании проектов на Visual Basic. В их числе кнопка, текстовое поле, таймер, изображение и др. Чтобы познакомиться с названием какого-нибудь элемента, поместите на него мышиный курсор, не нажимая.

Если Toolbox вашего компьютера слишком узкий и на нем не помещаются все элементы, вы можете для его расширения перетащить мышкой его границу.

Замечание: Понятие "Объект" имеет в Visual Basic гораздо более широкий смысл, чем форма или элемент управления, но поскольку других объектов мы пока не знаем, я буду называть объектами именно их.


Размещаем объекты на форме

Ну что ж, начнем сборку. Возьмем кнопку (CommandButton) и поместим на форму. Для этого щелкнем по кнопке, а затем проведем мышкой внутри формы небольшую "рамочку". Что значит провести "рамочку"? Это значит поместить мышиный курсор куда-нибудь внутрь формы, нажать на левую клавишу мыши и, не отпуская клавишу, "протащить" мышь немного наискосок. При этом за курсором будет тянуться "рамочка". Отпустите мышь. На месте рамочки возникнет кнопка с надписью Command1.

По краям кнопки вы увидите 8 черных квадратиков — маркеров изменения размеров. Если щелкнуть по форме мимо кнопки, они пропадут, если снова щелкнуть по кнопке — появятся. Только не надо пока двойных щелчков. Перетащите мышкой любой из маркеров — размеры кнопки изменятся. Можно таскать кнопку по форме, если ухватиться мышью не за маркер, а за любое место внутри кнопки. Чтобы уничтожить кнопку, щелкните по ней правой клавишей мыши и в выскочившем контекстном меню выберите опцию Delete. Проделайте все это. А теперь, если вы ее уничтожили, то снова создайте.

Аналогичным образом поместим на форму объект текстовое поле (TextBox). Теперь у нас на форме два объекта.

Обратите внимание на слово [design] (проектирование) в заголовке главного окна Visual Basic. Оно говорит о том, что в настоящий момент Visual Basic находится в режиме проектирования, во время которого мы можем собирать наш проект (1 этап) и писать для него программу (2 этап).



Пока мы с вами создаем сами не знаем что. Ведь никакой задачи мы перед собой не поставили. Тем не менее, перескочим через 2 этап (составление программы) и сразу выполним 3 этап, то есть запустим наш проект на выполнение. Для этого щелкнем мышкой по кнопке Start на панели инструментов (не путать с блоком элементов управления).

Исторический момент. Что мы видим? Форма немного изменилась, пропали точки, она потеряла связь с главным окном Visual Basic и ведет себя, как независимая программа. Для убедительности сверните на панель задач главное окно Visual Basic. Теперь форма одна царит на экране. Ее можно таскать по всему экрану, ухватившись за заголовок, и ее значок вы можете видеть на панели задач Windows. Она надлежащим образом реагирует на щелчки по кнопкам в ее правом верхнем углу. Если подвести острие курсора к краю или углу формы, то можно менять ее размеры. А вот размеры кнопки и текстового поля мы не можем больше менять. Зато теперь на кнопку можно нажимать мышкой. Нажимаем. Ничего не происходит. Естественно — мы ведь не написали программу, объясняющую компьютеру, что нужно делать при нажатии на кнопку.

В текстовое поле теперь можно вводить текст и как угодно там его менять. Но и это без толку. Компьютер никак не реагирует, что бы мы там ни написали. Причина та же.

Если вы при не свернутом главном окне Visual Basic случайно щелкнете по нему мышкой мимо формы, то форма пропадет из вида, так как будет загорожена главным окном. Не беда — щелчок по значку формы на панели задач Windows вернет ее на передний план.

Обратите внимание на слово [run] (бег, работа) в заголовке главного окна Visual Basic. Оно говорит о том, что в настоящий момент Visual Basic находится в режиме работы, то есть в режиме выполнения проекта (3 этап), во время которого мы ни собирать проект (1 этап), ни писать для него программу (2 этап) не можем.


Итак, мы видим, что без программы наш проект не стоит ни гроша. Завершим выполнение проекта кнопкой End на панели инструментов или щелкнув по крестику в правом верхнем углу формы. Visual Basic вышел из режима [run] и вернулся в режим [design]. Теперь в проекте можно что-нибудь поменять и снова его запустить. И так далее.


Пишем программу

Давайте придумаем себе задачу для нашего проекта. Пусть на экране при нажатии кнопки что-нибудь происходит. Легко сказать — пусть! Для этого нужно знать, что вообще умеет делать Visual Basic при нажатии на кнопки, а если даже мы это знаем, то все равно не знаем, как это приказать, то есть как правильно написать программу. Ну что ж. Программирование мы будем изучать постепенно и постепенно всему научимся, а сейчас я выберу что-нибудь самое простое и подскажу, как это делается. К компьютеру не подходите, пока я не скажу.

Прикажем компьютеру при нажатии кнопки поменять цвет формы на красный. Команда (оператор) для этого пишется так:

Form1.BackColor = vbRed

Разберемся, что здесь написано.

Form1 — это имя нашей формы (его дал Visual Basic и мы пока не будем его менять)

BackColor — переводится "цвет фона", то есть это цвет, которым по крашена форма (пока он серый)

vbRed — это красный цвет (Red — красный, vb — Visual Basic)

Таким образом, наш оператор можно перевести так:

Form1.цвет = красный

Правило такое: Слева от точки мы записываем имя объекта, справа от точки — его свойство, а справа от знака равенства — значение этого свойства. Точку писать обязательно. Аналогия — Коля.рост = 140 Бразилия.климат = жаркий

Visual Basic воспримет наш оператор как приказ поменять цвет формы на красный. Теперь как нам сделать, чтобы компьютер выполнил этот оператор именно при нажатии на кнопку, а не в какой-либо другой момент? Садитесь за компьютер. Проверьте, находимся ли мы в режиме проектирования [design]. Сделайте двойной щелчок по кнопке Command1. Перед вами возникнет новое окно — окно программного кода или просто окно кода. Чтобы мы не спутались, в заголовке окна присутствует слово (Code).

Будем называть кодом любой текст программы. Таким образом, в окно кода будем записывать всю программу нашего проекта (большие проекты могут использовать несколько окон кода).



Мы видим, что в окне кода уже что-то написано. Строку Private Sub Command1_Click() можно вольно перевести как "Что делать, если щелкнуть (по-английски — Click) мышкой по кнопке Command1". Слово Private переводится "локальный" и о его смысле поговорим позже. Слово Sub обозначает "процедура". Таким образом, более точно эту строку переводим так: "Локальная процедура, в которой компьютеру пишется инструкция, что делать, если человек мышкой нажмет на кнопку Command1".

Ниже оставлено свободное место и там уже мигает курсор, приглашая нас вводить туда какие нам угодно операторы. Они-то и будут выполнены при щелчке по кнопке. Еще ниже находится строка End Sub, что означает "конец процедуры".

Таким образом, мы видим перед собой не что иное, как заготовку процедуры, которая должна выполниться при щелчке по кнопке Command1.

Введите на свободное место с клавиатуры наш оператор Form1.BackColor = vbRed. Вы не имеете права допустить ни малейшей ошибки в строке. Даже лишний пробел может быть ошибкой.

Кстати, Visual Basic очень услужлив. Когда вы введете точку, он (чтобы вам не утомлять свои персты вводом слова BackColor) развернет перед вами список всех уместных после точки слов. Вам останется только сделать двойной щелчок на нужном слове.

Если вы случайно щелкнете мышкой мимо окна кода, оно может пропасть из вида. Не беда. Ваши действия: View -> Code.

Если же окно кода загораживает от вас форму, а вам хочется что-нибудь в ней сделать, то ваши действия: View -> Object.

Но вот ввод оператора закончен. Теперь окно кода должно иметь такой вид:

Перед вами готовая процедура. Проверьте, не ввели ли вы по ошибке что-нибудь выше, ниже или правее этих трех строк. Если ввели, то сотрите.



Пришла пора снова запускать проект. Предположим, вы при вводе кода в окно нигде не ошиблись. Щелкните кнопку Start. На экране опять появляется знакомый вид формы с кнопкой и текстовым полем. Щелкните по кнопке — форма стала красной. Поздравляю! Ваш первый проект заработал. Щелкните еще раз. Ничего не изменилось. Естественно. Завершим выполнение проекта кнопкой End.

Если у вас при запуске получилось не то, что нужно, прочтите чуть ниже параграф "Как реагировать на сообщения Visual Basic об ошибках".


Сохранение, создание, открытие, закрытие проекта

А теперь нам пора сохранить проект. Вообще-то, сохраниться нам надо было еще давно, до первого запуска, но не хотелось отвлекаться. Если же у вас есть опыт сохранения при работе в Windows, то можете сразу сохраняться при помощи File —> Save Project, только помните, что проект сохраняется не в один, а в несколько файлов, поэтому обязательно для каждого проекта создавайте свою папку. Visual Basic предложит вам стандартные имена для сохраняемых файлов. Пока не меняйте их.

Сохранившись, вы можете спокойно выйти из Visual Basic, щелкнув по крестику в правом верхнем углу главного окна, и можете даже выключить компьютер. Чтобы продолжить через некоторое время работу над проектом, запустите Visual Basic и загрузите (откройте) сохраненный проект при помощи File —> Open Project.

Если вы хотите начать новый проект, то выполните File —> New Project.

Через некоторое время у вас накопится несколько сохраненных проектов. Вот вы поработали с одним из них и хотите, не выходя из Visual Basic, поработать с другим. Пока у вас еще мало опыта, я рекомендую такой порядок действий:

1. сохраните проект

2. удалите его из главного окна Visual Basic (не с диска, конечно) — File —> Remove Project. Теперь в главном окне Visual Basic и в окне Project Explorer у вас должно быть пусто. Заголовок Project Explorer должен быть таким: Project — No Open Projects.

3. Откройте другой проект при помощи File —> Open Project или создайте новый при помощи File —> New Project.

Если вы попытаетесь открыть или создать другой проект, не сохранив старый, Visual Basic предложит вам его сохранить и после сохранения автоматически удалит из среды. Если вы по ошибке вместо File —> Open Project или File —> New Project выполните File —> Add project, то старый проект не будет удален и в главном окне Visual Basic вы будете иметь вместо одного сразу два проекта. Вы это сразу же заметите, взглянув в окно Project Explorer. Иногда иметь два проекта удобно, иногда просто необходимо, но пока вам будет не повернуться в такой тесноте. Если это все же произошло, жмите File —> Remove Project, отвечая отказом на предложения сохраниться, пока главное окно Visual Basic не опустеет.

Часто новый проект, который мы создаем, бывает похож на старый, и удобнее не новый создавать, а старый переделывать. Мой опыт таков. Я копирую папку старого проекта. Затем открываю копию проекта и переделываю ее в новый про-


Как реагировать на сообщения Visual Basic об ошибках

Если вы при вводе кода в окно где-то ошиблись, то Visual Basic при запуске или сделает что-нибудь не то (например, покрасит форму в черный цвет) или даст вам знать об ошибке специальным сообщением. Сообщения могут возникать как в режиме проектирования, так и в режиме работы. Сейчас имеет смысл потренироваться. Давайте будем специально допускать ошибки и смотреть, что будет:

Form1.BackColor = vbRedd

Visual Basic вообще не заметит этой ошибки и покрасит форму не в тот цвет. Завершите работу проекта и исправьте ошибку.

Private Sub Command1 Click()

И этой ошибки Visual Basic не заметит. Просто при нажатии на кнопку ничего красится не будет.

Form1.BackColo = vbRed

Visual Basic не заметит этой ошибки до тех пор, пока вы в режиме работы не нажмете на кнопку. Тогда он выдаст сообщение об ошибке, пока для вас, впрочем, невразумительное, и выделит подозрительное место в программе. Вы можете нажать Help и тогда Visual Basic подробнее пояснит, что он имел в виду. Но пока смысл пояснения вряд ли до вас дойдет. Нажимайте ОК и Visual Basic выделит желтым заголовок подозрительной процедуры. Завершите работу проекта и исправьте ошибку.

Foorm1.BackColor = vbRed

И этой ошибки Visual Basic не заметит до тех пор, пока вы в режиме работы не нажмете на кнопку. В окне сообщения об ошибке нажмите Debug, тогда Visual Basic выделит подозрительную строчку в программе. Завершите работу проекта и исправьте ошибку.

Form1.BackColor = vbRed

А вот эту ошибку Visual Basic заметит еще в режиме проектирования, как только вы попытаетесь убрать курсор из ошибочной строки в другое место. Подозрительное место будет выделено. Жмите ОК и исправляйте ошибку.

Кстати, когда вы убираете курсор из вводимой строки, Бэйсику кажется, что вы закончили с ней работу. Он проверяет ее на наличие грамматических ошибок и если не находит, то немного изменяет ее внешний вид, приведя к стандартному.

Visual Basic не всегда правильно находит подозрительные места. Часто программисту самому приходится превращаться в детектива. Я не буду здесь останавливаться на сложном процессе поиска ошибок, так как вы еще к этому не готовы. Достаточно будет, если вы еще раз посмотрите, так ли выглядит ваш код, как на рисунке. Нет ли чего лишнего, в том числе ниже строки End Sub? Все ли буквы английские, или есть русские? Человеку очень легко спутать английские буквы с русскими того же начертания, компьютер же не спутает никогда и придерется.


Усложняем проект

Итак, вы сохранили свой первый проект. Закройте его — File -> Remove Project. Скопируйте папку проекта тут же, рядышком. Над копией будем продолжать работать.

Пусть при щелчке по кнопке происходит что-нибудь еще, кроме окрашивания формы. Например, изменяется размер шрифта в текстовом поле. Для этого достаточно в окне кода дописать следующий оператор:

Text1.FontSize = 16

Здесь Text1 — имя текстового поля, FontSize — размер шрифта. Наш оператор можно перевести так: Сделать размер шрифта текстового поля Text1 равным 16. Теперь содержимое окна кода таково:

Private Sub Command1_Click()

Form1.BackColor = vbRed Text1.FontSize = 16

End Sub

При щелчке по кнопке Visual Basic выполняет по порядку все операторы процедуры между строками Private Sub Command1_Click() и End Sub. Запустим проект кнопкой Start. Убедимся, что оба оператора выполнились. Поскольку компьютер работает очень быстро, нам будет казаться, что оба оператора выполнились одновременно. Но это не так: сначала поменялся цвет формы, а уж затем размер шрифта.

Продолжим работу. Пусть при нажатии на кнопку кроме всего прочего в текстовом поле появляется текст "Теперь форма красная". Для этого достаточно в окне кода дописать еще один оператор:

Text1.Text = "Теперь форма красная"

Здесь Text1 — имя текстового поля, Text — его свойство, а именно — текстовое содержимое. Привыкайте к почти одинаковым обозначениям разных вещей (у нас это Text1 и Text) и будьте внимательны. Наш оператор можно перевести так: Содержимое текстового поля Text1 сделать таким — "Теперь форма красная". Вид окна кода стал таким:

Private Sub Command1_Click()

Form1.BackColor = vbRed Text1.FontSize = 16

Text1.Text = "Теперь форма красная"

End Sub

После каждого изменения в окне кода проверяйте, как работает проект.

Продолжим. Создадим на форме еще одну кнопку:

Ее имя — Command2. Пусть при щелчке по ней форма окрашивается в желтый цвет (vbYellow), размер шрифта становится равным 12, в текстовом поле появляется текст "Теперь форма желтая".



Для этого так же, как и в случае с кнопкой Command1, сделаем по кнопке Command2 двойной щелчок мышкой. Перед нами — снова окно кода, но в нем появилась заготовка другой процедуры, то есть новое приглашение — для ввода операторов, реагирующих на щелчок кнопки Command2. Введем их. Теперь содержимое окна кода таково:



Запустите проект. Пощелкайте по кнопкам.


Что дальше?

Итак, проект готов и работает. Что дальше? Пока не очень понятно, как нам запрограммировать что-нибудь посложнее, например, игру с перестрелкой. Могу пояснить. Вы растягиваете форму во весь экран и придаете ей не цвет, а фотографию или нарисованный вами рисунок города. Получается город во весь экран.

Далее берете в Toolbox и расставляете по форме объекты типа Image (изображение) — это ваши будущие автомобили, прохожие, гангстеры, пули и т. п. Затем придаете каждому объекту нужную внешность. Для этого тоже разыскиваете где-то фотографии или сами рисуете. Наконец, пишете для каждого из этих объектов программу поведения, включая реакцию на нажатия клавиш и мышиные щелчки. Игра готова, можно запускать. Основная трудность здесь, конечно, в написании программы, она будет достаточно сложной и вам предстоит еще многому научиться, чтобы почувствовать себя в силах ее создать.

В Visual Basic много любопытных и полезных элементов управления. Так, вставив в форму объект типа Timer, вы сможете управлять работой проекта "по секундам". Многие элементы управления на Toolbox не показаны. Но их легко туда поместить и пользоваться ими. Так, вставив в форму объект типа Microsoft Multimedia Control 6.0, вы сможете сопровождать игру музыкой, звуковыми эффектами и видео. Следующая глава познакомит вас со многими полезными и приятными возможностями Visual Basic.


ПРОЕКТ — "КАЛЬКУЛЯТОР"

В этой главе на примере создания калькулятора я хочу познакомить вас с простыми и приятными возможностями Visual Basic. По сути, калькулятор будет нам проводником по элементарным средствам Visual Basic. Многие из них вы найдете именно в этой главе. По ходу дела нам удастся углубить и расширить наши знания Visual Basic. В то же время глава носит несколько рекламный оттенок. Перед вами распахнется скатерть-самобранка, на которой вы увидите в основном то, что повкуснее и не требует разгрызания. Однако, среди вкусного будет и полезное, и необходимое, поэтому читать главу "по диагонали" никак нельзя, без нее не будет понятно все остальное.

Сейчас мы поставим перед собой задачу сделать реальную вещь — калькулятор. Примерно такой же, какой имеется в Windows. Если вы его забыли, то в Windows (а отнюдь не в Visual Basic), выполните такие действия: Пуск —> Программы —> Стандартные —> Калькулятор. Как по вашему — много сил затратила фирма Microsoft на его создание? Калькулятор, который создадим мы, в смысле математики будет попроще, зато он будет красивым, снабжен музыкой, паролем и разными другими "приколами".

Начнем с того, что придумаем нашему калькулятору внешний вид (пока скромный):



Идея такая — вы набираете в двух верхних текстовых полях первое и второе число, затем щелкаете по одной из кнопок и в нижнем текстовом поле получаете результат.


Проектируем

Создайте новый проект и разместите на форме три текстовых поля и четыре кнопки. У вас получится вот так:



Чтобы продолжить дальше, нам нужно поближе познакомиться со свойствами форм и элементов управления.


Свойства форм и элементов управления

Чуть раньше мы уже познакомились с такими свойствами объектов, как BackColor, FontSize, Text. Количество свойств у каждого из объектов довольно большое. Многие из них мы можем менять в режиме работы [run] при помощи программы, как мы это уже делали (например, Form1.BackColor = vbRed). Оказывается, многие свойства форм и элементов управления можно менять и в режиме проектирования [design]. Делается это вручную, безо всякого программирования (для того и задумано, что вручную легче!).

Вы сейчас в режиме [design]? Хорошо. Один щелчок по кнопке Command1. При этом на кнопке появляются маркеры. Говорят, что объект выделен, стал активным. В этом случае его свойства вы можете видеть в окне свойств объекта. Если это окно кажется вам маловатым, попробуйте растянуть его, ухватившись за края. В окне два столбца: название свойства и его значение. Для вашего удобства свойства могут быть упорядочены по алфавиту (закладка alphabetic) или сгруппированы по категориям (закладка categorized).

Попробуем изменить значение какого-нибудь свойства кнопки Command1. Найдите в окне свойство Width (ширина), а справа — его численное значение. Введите вместо имеющегося там числа другое число, например, 200. Вы видите, что ширина кнопки изменилась. Точно такого же результата вы добились бы в режиме работы [run], выполнив оператор Command1.Width = 200. А теперь поступим наоборот — перетащим немного влево или вправо один из маркеров кнопки. Мы увидим, что соответственно изменилось и число.

Выделим щелчком какой-нибудь другой объект. Теперь в окне свойств — его свойства. Выделим форму, щелкнув по любому свободному месту ее поверхности — теперь мы видим и можем менять ее свойства. И так далее.

С названиями и смыслом разных свойств я буду знакомить вас постепенно.


Имена и надписи

У каждого объекта есть имя (Name). У многих есть надпись (Caption). Имя и надпись являются свойствами объекта. Попробуем их изменить и разобраться, зачем они нужны. В предыдущем проекте мы не заботились об именах и надписях и хорошо делали, потому что Visual Basic в случае нашей беспечности (как говорится — по умолчанию) сам придает значения свойствам, в том числе именам и надписям, причем, недолго думая, имя и надпись он делает одинаковыми. Проверим. Выделим форму. Заглянем в окно свойств и найдем там имя (Name) — оно в алфавите выше всех. Так и есть, имя нашей формы — Form1. Изменим его, скажем, на слово Калькулятор. Изменили. И что же? В заголовке формы ничего не изменилось. Дело, конечно, в том, что в заголовке мы видим не имя, а надпись. Имя остается скрытым (полковник Исаев), а надпись видна всем (Штирлиц). Убедимся в этом. Найдем в окне свойств свойство надпись (Caption). Ну конечно — надпись на нашей форме — тоже Form1. Изменим ее на Личный калькулятор Вовочки — классного программиста. Теперь все в порядке.

Зачем мы изменили надпись, нам понятно. А почему надо было менять имя? Ну, хотя бы потому, что оператор

Калькулятор. Width=6000

как-то понятнее, чем

Form1.Width=6000

Займемся кнопками. Выделим кнопку Command1 и дадим ей имя Кл_сложения.

Внимание! Имя должно состоять только из букв, цифр и знаков подчеркивания, причем начинаться имя должно с буквы. Раз в именах запрещены пробелы, я использовал вместо них знак подчеркивания.

Надпись нашей кнопки должна состоять из единственного символа +. Найдем + на клавиатуре и введем. На кнопке он получился маловат. Чтобы его увеличить, найдем в окне свойств свойство Font и щелкнем по нему. В поле значения появилась кнопочка с троеточием — это всегда приглашение к дальнейшему разговору. Щелкнем по ней — перед нами появилось так называемое диалоговое окно, предлагающее выбрать размер шрифта (Size), стиль (Font Style), сам шрифт (Font) и кое-что другое. Стиль может быть обычным (Regular), курсивом (Italic), полужирным (Bold) и полужирным курсивом (Bold Italic). Среди самих шрифтов (Font) попадаются любопытные. Выберите размер и прочее по вкусу. С клавишей сложения закончили.

Аналогичным образом придайте имена и надписи трем другим кнопкам. Имена: Кл_вычитания, Кл_умножения, Кл_деления. В качестве надписей для клавиш умножения и деления можете выбрать букву X и двоеточие.

Теперь займемся текстовыми полями. Придумаем и дадим им имена: Число1, Число2, Результат. А вот свойства Надпись (Caption) у текстовых полей нет. Вместо него есть свойство Text. Поскольку мы хотим, чтобы в начале работы с калькулятором в текстовых полях было пусто, сотрем в окне свойств значения свойства Text для всех трех полей.

А теперь займемся пояснительным текстом в левой части калькулятора (Первое число, Второе число, Результат). Для этого нам понадобится новый элемент управления — Label (метка), который в основном для пояснений и применяется. Найдите Label в окне Toolbox и поместите на форму три метки. Ваш проект выглядит так:



Заглянем в свойства меток. Мы видим, что Visual Basic по обыкновению дал каждой метке совпадающие имя и надпись (Label1, Label2, Label3). Имена менять мы не станем затрудняться, потому что в программе они никак участвовать не будут, а надписи, конечно, переменим на Первое число, Второе число, Результат, да и шрифт, пожалуй, увеличим.

Нам остается поместить на форму горизонтальную линию. Для этого найдем в окне Toolbox элемент управления Line (линия) и проведем линию на форме. Чтобы она была потолще, изменим в окне свойств свойство линии BorderWidth.

Итак, проектирование первой версии калькулятора закончено! Теперь калькулятор выглядит так, как задано. Можно приступать к программированию.


Программируем

Запустим проект. Введем в верхнее текстовое поле число 3, а в среднее введем 2. Щелкнем по кнопке сложения. Ничего не произошло. Естественно. Ведь никакой процедуры мы для кнопки не написали. Завершим работу проекта. Двойным щелчком по кнопке сложения откроем окно кода и попытаемся выдумать, что же там написать. Рассуждать будем так: 3 и 2 — не что иное, как значения свойства Text текстовых полей Число1 и Число2. По-другому, это Число1.Text и Число2.Text. Нам нужно, чтобы Результат.Text равнялся их сумме. Что если написать такой оператор:

Результат.Text = Число1.Text + Число2.Text

Сказано — сделано. Получаем:

Private Sub Кл_сложения_Click()

Результат.Text = Число1.Text + Число2.Text

End Sub

Запускаем проект. Вводим 3 и 2. Щелкаем по кнопке сложения. Результат есть. Но не совсем тот, что мы ожидали. Вместо 5 получилось 32. В чем причина? Дело в том, что Visual Basic привык считать знак + по отношению к содержимому текстовых полей не знаком сложения, а знаком "соединения". Проверьте. Вместо 3 и 2 введите Коро и бочка, в результате получится Коробочка. Недаром текстовые поля называются текстовыми, а не числовыми. То, что мы назвали их Число1 и Число2, делу никак не помогло, потому что Visual Basic не обращает внимания на смысл имен, для него имена — просто бессмысленные сочетания символов.

Что делать? Надо приказать Visual Basic обращаться в данном случае с содержимым текстовых полей не как с текстом, а как с числами. Для этого достаточно записывать их не в таком виде — Число1.Text и Число2.Text, а в таком — Val(Число1.Text) и Val(Число2.Text). Здесь Val — сокращение от Value — величина, численное значение. Теперь наш оператор будет выглядеть так:

Результат.Text = Val(Число1.Text) + Val(Число2.Text)

Кстати, после ввода открывающей скобки Visual Basic услужливо предложит подсказку на тему о том, что должно быть в скобках. Со временем вы научитесь эту подсказку понимать.

Запускаем проект. Вводим два любых целых числа и убеждаемся, что все складывается правильно.

Аналогично программируем три остальные кнопки. Вот как будет выглядеть после этого окно кода:

Private Sub Кл_сложения_Click()

Результат.Text = Val(Число1.Text) + Val(Число2.Text)

End Sub

_____

Private Sub Кл_вычитания_Click()

Результат.Text = Val(Число1.Text) — Val(Число2.Text)

End Sub

_____

Private Sub Кл_умножения_Click()

Результат.Text = Val(Число1.Text) * Val(Число2.Text)

End Sub

_____

Private Sub Кл_деления_Click()

Результат.Text = Val(Число1.Text) / Val(Число2.Text)

End Sub

Пояснения: В языках программирования умножение обозначается звездочкой *, а деление — косой чертой /.

При вводе в текстовые поля десятичных дробей вместо запятой ставьте точку. Результат же будет выводиться с запятой.

Итак, калькулятор готов!

Предостережения: Наш калькулятор пока не защищен от ввода вместо чисел всякой ерунды (например, текста КУ-КУ), от ввода слишком больших или слишком маленьких чисел, от деления на ноль. В таких случаях Visual Basic дает неправильный или неудобочитаемый результат или сообщение об ошибке. Защиту вы найдете в 0.

Задание 1: Создайте кнопку возведения в квадрат числа из верхнего текстового поля.

Указание: Возвести в квадрат — значит умножить само на себя.

Задание 2: На нашем калькуляторе не хватает кнопки СБРОС, которая опустошала бы все три текстовых поля. Создайте ее.

Указание: Для этого вам понадобятся операторы типа Число1.Text = В программах текстовое содержимое текстовых полей должно указываться в кавычках. В данном случае у нас внутри кавычек пусто, что и требовалось.


Кое-какие другие свойства объектов

Начнем в режиме проектирования украшать и усовершенствовать наш калькулятор. Для этого рассмотрим некоторые другие свойства объектов, из которых он сконструирован. Многие из этих свойств имеются у большинства объектов, некоторые — только у одного-двух. Прочтя материал об очередном свойстве, вам надлежит тут же проверить, как его различные значения влияют на вид и поведение формы, кнопок, текстовых полей и меток в режиме [run].

Полезный совет: У объектов очень много не объясненных мной свойств. Природная любознательность толкнет вас "поперед батьки" разобраться, что они значат, придавая им для этого наугад какие-нибудь значения. Нет проблем — ломайте голову на здоровье. Проблема же в том, что кое-кто норовит сохранить проект с измененными значениями неведомых свойств. А потом проект начинает себя вести как-то непонятно. Мораль — "Верни, как было!"


BackColor (цвет объекта) — знакомое свойство. Щелкнем по нему. В поле значения появилась кнопочка с черной треугольной стрелкой. Щелкнем по ней — перед нами появилось окно с двумя закладками. Выберем Palette (палитра) и понравившийся цвет.

ForeColor (цвет текста и линий, рисуемых на объекте).

Appearance (внешний вид) — 3D (трехмерный) или Flat (плоский).

BorderStyle (стиль границы). Здесь 6 вариантов, и заведуют они не только стилем границы, но и количеством кнопок на форме, и возможностью изменять размеры формы в режиме [run].

ToolTipText (всплывающая подсказка). Вы, возможно, привыкли к тому, что когда во время работы в приложениях Windows, таких как Word, вы помешаете курсор мыши на значок какого-нибудь инструмента, то рядом со значком появляется подсказка, поясняющая, зачем этот инструмент нужен.

Введите любой текст в качестве значения свойства ToolTipText. Запустите проект. Поместите курсор мыши на объект. Текст всплыл. Очень приятное свойство.

Mouselcon, MousePointer (значок мыши, указатель мыши). Эти свойства позволяют вам менять внешний вид мышиного курсора. Выберите кнопку и задайте для ее свойства MousePointer значение 2 (крест). Запустите проект. Поместите курсор мыши на объект. Курсор приобрел вид креста.

Если вы зададите вид мышиного курсора для объекта Форма, то он будет иметь заданный вид над всей поверхностью формы и теми объектами на форме, для которых он еще не изменен.

Всего у свойства MousePointer 16 скромных значений. Mouselcon позволяет вам задать более живописный значок для курсора. Для этого предварительно установите значение MousePointer в 99. Затем щелкните по троеточию в Mouselcon и в открывшемся окне проводника найдите значки мышиного курсора в папке Windows\Cursors или в папках Cursors и Icons, расположенных в папке Graphics, которая сама расположена в папке, куда установлен ваш Visual Basic.

Поиграли со значками мышиного курсора? А теперь верните все, как было. Не стоит без дела отвыкать от стандартного интерфейса — это рассеивает внимание. Экзотика хороша в экзотических случаях.


Следующие четыре свойства применимы только к форме.

MaxButton (кнопка максимизации — квадратик в правом верхнем углу формы). Сейчас значение этого свойства — True (Правда). Если установить его в False (Ложь), то квадратик пропадет или станет недоступен.

MinButton (кнопка минимизации — горизонтальная черточка в правом верхнем углу формы). Сейчас значение этого свойства — True (Правда). Если установить его в False (Ложь), то черточка пропадет или станет недоступна.

Moveable (можно ли двигать). Установите это свойство в False и вы увидите, что в режиме [run] форму нельзя таскать по экрану за заголовок. Хотя можно перетаскивать ее границы.

WindowState определяет, в каком виде возникает форма при запуске проекта: 0 — в нормальном, 1 — в минимизированном (то есть вы найдете ее на панели задач Windows) или 2 — максимизированном (во весь экран).

Visible (видимый). Обычно значение этого свойства — True (Правда). Если установить его в False (Ложь), то элемент управления перестанет быть виден в режиме работы. Но будет слушаться программу.

Enabled (в рабочем состоянии). Обычно значение этого свойства — True. Если установить его в False, то элемент управления виден будет, но он не будет работать и им нельзя будет пользоваться. Обычно он приобретает при этом бледно-серый оттенок.

Alignment. В зависимости от значения этого свойства текст в текстовом окне или метке будет располагаться вплотную к левому краю элемента, правому краю или по центру.

MultiLine. Если установить это свойство текстового поля в True, то в текстовое поле вы сможете вводить не одну, а много строк. А если вы измените значение его свойства ScrollBars, то снабдите текстовое поле одной или двумя полосами прокрутки.


Помещаем фото на калькулятор

Мы хотим, чтобы поверхность формы была покрыта какой-нибудь фотографией. Для этого необходимо, чтобы файл с этой фотографией уже хранился на жестком диске вашего компьютера. Если фото нет, то сойдет и рисунок, созданный вами в каком-нибудь графическом редакторе, например, в Paint.

Выделите форму. Найдите свойство Picture. Затем щелкните по троеточию. В открывшемся окне проводника доберитесь до нужного вам графического файла. Щелкните по Open — в результате фото окажется на форме. Можно использовать и другие типы графических изображений. Если у вас установлен Microsoft Office, то вы можете в его папке найти папку Clipart и там поискать файлы векторной графики.

Если вам не хочется занимать под фото все пространство формы, вы можете поместить на форму один из двух новых для вас элементов управления — PictureBox или Image — и аналогичным образом поместить изображение в них.

Графику можно поместить и на кнопку (предварительно установив свойство Style кнопки в Graphical).


Музыка в проекте

Если у вашего компьютера есть звуковая карта, то вы можете добавлять в ваш проект самые разнообразные музыкальные и звуковые эффекты.

Сделаем так, чтобы при запуске проекта раздавалась музыка (а если вы умеете с микрофона записывать свой голос в файл — то и ваш голос). Звуковой файл с музыкой или вашим голосом уже должен находиться на жестком диске или на компакт-диске. Вы можете прекрасно прослушивать файлы в форматах MID, WAV, а в большинстве случаев и MP3 и некоторых других. Кстати, в Интернете и на компьютерных компакт-дисках подавляющая часть музыки имеет формат MP3. Этот формат становится все более популярным, так как позволяет уместить на диск в десять раз больше музыки, чем, скажем, WAV. Если вы не Знаете ни одного звукового файла, то могу подсказать, что несколько десятков их хранятся в вашем компьютере по адресу C: \Windows\Media. Пусть мы хотим воспроизвести один из них — файл Canyon.mid.

Проверьте настройки вашей звуковой карты в программе «Микшер». Для этого в среде Windows нажмите Пуск —> Программы —> Стандартные —> Развлечения —> Регулятор громкости. В возникшем окне снимите флажки (галочки) выключения канала и установите максимальный уровень у каналов Wave (для WAV-файлов и МР3-файлов) и MIDI (для MID-файлов и RMI-файлов). Для работы с микрофоном зайдите в «Свойства», затем в закладку «Запись», установите флажок включения канала и установите максимальный уровень у канала «Микрофон».

Чтобы воспользоваться звуковым файлом, вам нужно расположить на форме элемент управления Microsoft Multimedia Control 6.0. Но его нет в стандартном наборе на панели Toolbox. Сначала его нужно туда поместить. Для этого: Projects —> Components —> вы находите его в длинном списке и ставите против него галочку —> ОК. Он появился в Toolbox. Теперь им можно пользоваться обычным образом.

Поместим его на форму. Дадим ему имя (например, Плеер). Вы видите, что у него есть клавиши. Чтобы все нужные вам клавиши были работоспособны в режиме [run], установите соответствующие свойства в окне свойств, но проще так: щелкните по Плееру правой клавишей мыши —> Properties —> Controls —> поставьте по две галочки против каждой нужной вам клавиши.

Для того, чтобы музыка зазвучала, Visual Basic должен выполнить следующие операторы:

Плеер. DeviсеТуре = "Sequencer"

Плеер. FileName = "c: \Windows\Media\Canyon.mid"

Плеер. Command = "Open"

Плеер. Command = "Play"

Пояснения: Первая строка выбирает тип устройства (DeviceType) внутри вашей звуковой карты, которое будет проигрывать ваш звуковой файл. Для файлов с расширением mid, rmi используется устройство Sequencer. Для файлов с расширением wav, mp3 используется устройство WaveAudio.

Вторая строка объясняет компьютеру, откуда брать звуковой файл.

Третья строка дает команду (Command) на открытие (Open) файла. Это необходимо для дальнейшей работы с ним.

Четвертая строка дает команду на начало воспроизведения (Play) файла и вы слышите музыку.


Мы привыкли, что все, что ни происходит в проекте, происходит при нажатии кнопок. Потому что все процедуры, которые мы писали до этого, объясняли компьютеру, как реагировать на одно-единственное событие — щелчок мышкой по кнопке. Как сделать, чтобы вышеприведенные 4 оператора выполнялись сразу же при запуске проекта без нажатия каких бы то ни было кнопок? Существуют ли какие-либо другие события, не сводящиеся к щелчкам мыши? Да, и их много (например, нажатие клавиши на клавиатуре или факт изменения текста в текстовом поле). Но мы их раньше не замечали, так как Visual Basic на них никак не реагировал. Одно из них — загрузка формы (Form_Load) — наступает автоматически при запуске проекта (конечно, если вы этому специально не воспрепятствуете) и кроме всего прочего имеет следствием появление формы на экране. Оно-то нам и нужно.

Сделаем двойной щелчок по форме. Возникнет заготовка новой процедуры:

Private Sub Form_Load()

End Sub

Ее заголовок можно вольно перевести так: "Что делать, когда загружена форма", а для нас это фактически означает "Что делать, когда запущен проект".

Естественно, в эту процедуру мы записываем наши 4 оператора. Музыка готова. Пока не запускайте проект.

Если вы хотите, чтобы ваше музыкальное сопровождение правильно работало, нужно позаботиться, чтобы звуковой файл после окончания воспроизведения своевременно закрывался командой "Close". В нашем случае других звуковых файлов не используется, поэтому закрытие файла можно отложить на самый последний момент — момент завершения работы проекта. С ним связано событие Form_Terminate. Вот ваши следующие три строки:

Private Sub Form_Terminate()

Плеер. Command = "Close"

End Sub

Помните, что событие Form_Terminate наступает только тогда, когда мы завершаем работу проекта, щелкнув по крестику в правом верхнем углу формы, а не кнопкой End на панели инструментов.

Проверьте, как работает наша музыка, запустив проект.


Музыка в кнопках

Поставим задачу — сделать так, чтобы при нажатии на калькуляторе каждой из четырех клавиш арифметических действий раздавался какой-нибудь короткий мелодичный звук, причем для каждой клавиши свой. Таких звуков много по адресу C: \Windows\Media. Там они записаны в файлах, имеющих расширение wav. Выберем из них Chime.wav, Notify.wav, Tada.wav и Logoff.wav.

Разместим в проекте еще один элемент Microsoft Multimedia Control 6.0. Дадим ему имя Звук. Его клавиши нам не нужны, нам ни к чему управлять короткими звуками. А раз так, то сделаем объект Звук невидимым. Для этого его свойству Visible придадим значение False.

Устройством для воспроизведения Wav-файлов является WaveAudio. Чем раньше мы объясним это компьютеру, тем лучше. Поэтому поместим соответствующий оператор.

Звук. DeviсеТуре = "WaveAudio"

в процедуру, которая выполняется раньше всех — в Form_Load.

В каждую из четырех процедур кнопок поместим четыре новых оператора следующего вида:

Звук. FileName = "c: \Windows\Media\. wav"

Звук. Command = "Open"

Звук. Command = "Sound"

Звук. Command = "Close"

Пояснения: В нашем случае команда "Sound" имеет то же действие, что и команда "Play", но отличается от нее тем, что задерживает выполнение остальных операторов проекта до тех пор, пока не закончится воспроизведение звукового файла. Вы можете убедиться в этом, когда запустите готовый проект. Пока при помощи команды "Play" воспроизводится длинная мелодия Canyon.mid, вы можете спокойно пользоваться калькулятором, нажимая на кнопки. Когда же при помощи команды "Sound" воспроизводится звук Chimes.wav, весь проект ненадолго "замерзает".

Замечание: Если ваша звуковая карта достаточно хорошего качества, то вы сможете одновременно услышать и Canyon.mid и Wav-файлы.

Вот так будут выглядеть в окне кода ваши процедуры, связанные со звуком:

Private Sub Кл_сложения_Сlick ()

Звук.FileName = "с: \Windows\Mediа\Chimes.wav"

Звук.Command = "Open"

Звук.Command = "Sound"

Звук.Command = "Close"

Результат.Text = Val(Число1.Text) + Val(Число2.Text)

End Sub


Private Sub Кл_вычитания_Сliск()

Звук.FileName = "c: \Windows\Media\Notify.wav"

Звук.Command = "Open"

Звук.Command = "Sound"

Звук.Command = "Close"

Результат.Text = Val(Число1.Text) — Val(Число2.Text)

End Sub


Private Sub Form_Load()

Звук.DeviceType = "WaveAudio"

Плеер.DeviceType = "Sequencer"

Плеер.FileName = "c: \Windows\Media\Canyon.mid"

Плеер.Command = "Open"

Плеер.Command = "Play"

End Sub


Private Sub Form_Terminate()

Плеер.Command = "Close"

End Sub


Проигрывание аудиодисков

Элемент управления Microsoft Multimedia Control 6.0 можно использовать и для проигрывания из вашего проекта самых обычных некомпьютерных аудио-компакт-дисков. Разместите этот элемент управления на форме, придайте ему имя "CDPlayer". Вставьте диск в дисковод CD-ROM вашего компьютера. Теперь вам достаточно выполнить такую цепочку операторов:

CDPlayer.DeviсеТуре = "CDAudio"

CDPlayer.Command = "Open"

CDPlayer.Command = "Play"

Вы скажете — Я могу это делать и безо всякого Visual Basic. Это верно. Но из Visual Basic это делать интереснее. В элементе Microsoft Multimedia Control 6.0 имеются возможности тонкого управления проигрыванием, которые вы не найдете в стандартных проигрывателях.


Плеер ваших любимых хитов

Если у вас набралось на диске 5–6 любимых звуковых файлов, то вы уже можете создать проект — плеер, в котором будет соответственно 5–6 кнопок с названиями исполняемых произведений. При нажатии кнопки звучит соответствующее произведение.

Вы можете сделать так, чтобы на форме тут же появлялась и подходящая картинка. Например, если исполняется песня группы "Столбняк", то пусть на форме появляется фотография задумчивых исполнителей этой группы. Для появления картинки подойдет оператор вида

Form1.Picture = LoadPicture("С: \Program Files\Microsoft* Office\Clipart\Popular\Agree.wmf")

Здесь LoadPicture означает Загрузить картинку. В скобках с кавычками указывается адрес картинки на вашем компьютере. Кстати, в указанной папке вы найдете несколько десятков картинок.

Вы также можете сделать, чтобы при проигрывании мелодии вы видели и текстовое описание мелодии или, скажем, биографию композитора. Для этого поместите на форму большую метку (Label) и в подходящие места программы вставляйте операторы вида

Label1.Caption = "Композитор — Гладков. Впервые исполнена в 1970 году."

При работе со звуковыми файлами возникает вопрос — когда закрывать файлы? Если перед открытием следующего файла не закрыть предыдущий, то нормальной работы не получится. Связка

Плеер.Command = "Play"

Плеер.Command = "Close"

не подойдет, так как музыка закончится, не успев начаться. Здесь подойдет такая связка:

Плеер.Command = "Close"

Плеер.FileName = "c: \Windows\Media\Canyon.mid"

Плеер.Command = "Open"

Плеер.Command = "Play"

Здесь команда "Close" выполняется самой первой и закрывает любой файл, который исполнялся или мог исполняться раньше. После этого команда "Open" спокойно открывает нужный файл.

Задание 3: Создайте только-что описанный мною "Плеер

Задание 4: "Ваш собственный музыкальный компакт-диск": Сейчас широко распространены в продаже компьютерные компакт-диски такого рода: вы вставляете его в компьютер, он инсталлирует свою программу, затем вы запускаете ее. На экране появляются красочная заставка типа "Ваши любимые песни" и список песен. Вы выбираете одну из них. Песня звучит, возникают подходящие фото и текст. В любой момент вы можете прервать песню и выбрать другую.

Если у вас или у вашего друга есть устройство записи на компакт-диски CD-RW, то вы вполне можете создать свой собственный компакт-диск, который будет делать то же самое. На диске будут находиться как сами файлы песен, так и инсталляционный пакет программы для их воспроизведения. Вам нужно где-то достать файлы песен, а также, перелистав эту книгу вперед, прочесть в 0, как переносить свою программу на другие компьютеры. В остальном вам достаточно знания предыдущего материала и советов из предыдущей задачи.


Система координат

Чтобы рисовать фигуры, чтобы помещать объекты в нужное место экрана или формы, чтобы при анимации двигать объекты в нужном направлении, вы должны уметь объяснить компьютеру, где, в каком месте экрана или формы вы хотите нарисовать фигуру или поместить объект. Сделать это можно только имея представление о системе координат.

Если вы еще не знаете, что такое система координат, то все же постарайтесь изучить этот раздел, без него дальше будет трудно.

В школе вы привыкли к такой системе координат:



На экране компьютера применяется такая:



Как видите, ось у направлена вниз. Это не очень привычно. Если вас это раздражает, то Visual Basic может вам предложить исправить ситуацию. Однако, редко кто пользуется этой возможностью, поэтому и вам будет полезно привыкнуть к компьютерной системе.


Как нам управлять положением объектов на экране? Выделите любой объект на форме и загляните в его свойства Left и Тор.

Значение свойства Left — это расстояние левого края объекта от левого края формы.

Значение свойства Тор — это расстояние верхнего края объекта от верхнего края формы.

Таким образом, для объектов на форме действует компьютерная система координат с началом в верхнем левом углу формы. Убедитесь в этом — потаскайте любой объект по форме, следя за значениями Left и Тор. Добейтесь:

нуля в одном свойстве

нуля в другом свойстве

нуля в обоих свойствах

максимума в одном свойстве

максимума в другом свойстве

максимума в обоих свойствах

минуса в одном свойстве

минуса в другом свойстве

минуса в обоих свойствах

Единицей измерения расстояния в Visual Basic является твип. Это очень маленькая величина и на пространстве экрана ее нельзя однозначно выразить в долях миллиметра. Ее значение зависит от разрешающей способности видеорежима. В твипах выражаются свойства Left, Top, Width (ширина объекта) и Height (высота объекта). Потаскайте правую и нижнюю границы объекта, следя за значениями Width и Height.

В режиме проектирования мы не можем таскать форму по экрану за заголовок, да это и не нужно. Изменяя свойства Left и Тор формы, мы управляем местом ее появления на экране после запуска проекта. Для формы начало компьютерной системы координат находится в левом верхнем углу экрана

В режиме работы положением и размерами объектов мы управляем просто:

Form1.Left = 2000

Похвальное дело снабжения нашего калькулятора различными "приколами" я вывожу в задание для самостоятельной работы:

Задание 5: Пусть при нажатии на клавишу вычитания эта клавиша прыгает куда-нибудь совсем в другое место калькулятора и на ней вместо минуса появляется текст типа "Я устала вычитать" или "Не трогай меня — я нервная!". Когда это у вас получится, сделайте так, чтобы при нажатии на клавишу СБРОС клавиша вычитания скромно возвращалась на место и принимала свой прежний вид.


Вывод сообщений — MsgBox

Можно заставить компьютер в любой момент выполнения программы выводить нам какое-нибудь сообщение. Например, пусть калькулятор при завершении работы выдает такое окно сообщения:



Для этого подойдет такой новый для нас оператор:

MsgBox ("А теперь считайте в уме!")

Чтобы он выполнился именно при завершении работы, его нужно поместить в процедуру Form_Terminate.

Прочитав сообщение, щелкните ОК.

Вы не забыли, что все, мною сказанное, нужно проверять?



Меню пользователя

Какая же программа без своего меню! Нашему калькулятору оно, вроде бы, ни к чему, но, все равно, интересно и полезно сделать хотя бы простенькое. Пусть оно выглядит так:

Задачу поставим такую: Щелкнув по пункту "Настройка цвета", мы должны увидеть выпадающее меню из двух пунктов. Щелкнув по пункту "Синий" этого выпавшего меню, мы красим калькулятор в синий цвет, щелкнув по пункту "Красный" — в красный.

Щелкнув по пункту "О программе", мы вызываем сообщение описанием программы.

Нам предстоит создать меню, тем заставить его работать.

Создаем меню. Чтобы его создать, достаточно в главном меню Visual Basic выбрать Tools -> Menu Editor. Перед вами возникнет следующее диалоговое окно —>



Начнем с настройки цвета. Введем в поле Caption текст "Настройка цвета". Это для того, чтобы пункт меню с этим текстом появился на форме. По мере ввода этот текст возникает и в поле, расположенном ниже.

Теперь придумаем этому пункту имя, например, пункт_меню_Настройка_цвета, и введем его в поле Name. Это чтобы пункт меню мог заработать. Если хотите вызывать этот пункт не только мышкой, но и с клавиатуры, выберите что-нибудь из списка Shortcut.

Щелкните по кнопке Next и займитесь пунктом "Синий", дав ему имя пункт_меню_Синий.

Щелкните по кнопке Next и займитесь пунктом "Красный", дав ему имя пункт_меню_Красный.

Щелкните по кнопке Next и займитесь пунктом "О программе", дав ему имя пункт_меню_О_программе.

В результате в окне возникает список из 4 пунктов —>



Теперь нужно объяснить компьютеру, что пункты "Синий" и "Красный" входят внутрь пункта "Настройка цвета". Для этого выделим их по очереди и сдвинем направо кнопкой —>. Получается такая картинка —>



Если у вас что-то не получается, то вы все же можете добиться своего, используя все клавиши, показанные на картинке. Стрелки сдвигают выделенный пункт меню, Delete удаляет, Insert вставляет новый пункт.

Все в порядке — внешний вид меню готов. Запустите проект. Вы видите, что меню желаемого вида появилось на калькуляторе. Пощелкайте по пунктам. Естественно, ничего не происходит. Для того, чтобы происходило, нужно заставить меню работать, а для этого нужно для каждого пункта написать свою процедуру.

Заставляем меню работать. В режиме проектирования выберем пункт меню "Синий" и щелкнем по нему. В окне кода появляется заготовка процедуры:

Private Sub пункт_меню_Синий_Сliск ()

End Sub

Вы уже наверняка догадались, что это приглашение объяснить компьютеру, что нужно делать при выборе пункта "Синий". Для этого подойдет парочка операторов:

Form1.Picture = LoadPicture()

Form1.BackColor = vbBlue

Второй оператор красит форму в синий цвет, первый убирает с формы картинку, если она там была (сравните с материалом перед заданием 3 из 0).

Аналогично программируем пункт "Красный". А сообщение о программе обеспечит оператор

MsgBox ("Программа создана в 2000 году")

Запустите проект и проверьте, как он работает.


Средствами Visual Basic можно создавать, преобразовывать и уничтожать меню не только в режиме проектирования, но и в режиме работы. Кроме обычных меню Visual Basic умеет создавать и так называемые контекстные меню. Ни на том, ни на другом я не буду останавливаться.


Кино в проекте

Все есть у нашего калькулятора — и картинки, и звук, и меню, и прыгающие кнопки. Для полного счастья не хватает кино. Нет проблем! Причем их нет двумя способами!

Первый способ. Project->Components->Microsoft Windows Common Controls-2 6.0. Ha Toolbox появится несколько новых элементов управления. Берите из них Animation и размещайте на форме — это ваш экран для кино. Его имя Animation1. Этот элемент управления позволяет прямо в работающем проекте просматривать видеофайлы в формате AVI. Если у вас на компьютере нет порядочного кино в этом формате, то несколько маленьких анимационных роликов вы все-таки найдете в папке Videos, находящейся внутри папки, куда устанавливалась ваша Visual Studio. Скорее всего они находятся по такому адресу: "C: \Program

Files\Microsoft Visual Studio\Common\Graphics\Videos".

Сделайте в проекте кнопку и назовите ее, например, "Видео". Вот процедура, которая при нажатии кнопки "Видео" бесконечно воспроизводит видеоролик FILECOPY.AVI:

Private Sub Bnfleo_Click()

Animation1.Open "C: \Program Files\Microsoft Visual Studio\Common\Graphics\Videos\FILECOPY.AVI"

Animation1.Play

End Sub

Здесь полная аналогия с аудиоплеером, который я рассматривал в 0 Первая строка процедуры открывает файл, вторая его воспроизводит.

Во время демонстрации вы можете выполнять на калькуляторе другие свои дела. Чтобы "заморозить" демонстрацию, нужно выполнить оператор Animation1.Stop, а чтобы совсем прекратить и убрать с экрана — Animation1.Close.

Если вам нужно 3 раза воспроизвести кадры видеофильма с 5 по 12, вы пишете Animation1.Play 3, 5, 12


Второй способ. Используйте нашего старого знакомого — мастера на все руки — Microsoft Multimedia Control 6.0, который тоже позволяет просматривать видеофайлы в формате AVI. Разместите его на форме и назовите, скажем, "Кино". Вот цепочка операторов, приводящая к результату:

Кино. DeviсеТуре = "AVIVideo"

Кино. FileName = "C: \Program Files\Microsoft Visual Studio\Common\Graphics\Videos\ FILECOPY.AVI"

Кино. Command = "Open"

Кино. Command = "Play"

Просмотр идет в отдельном окне, размер и положение которого вы можете мышкой менять в процессе просмотра, что само по себе любопытно. К тому же, вы можете пользоваться управляющими кнопками элемента управления.

Кое-что необходимое напоследок


Комментарии

Комментарии — это пояснения к тексту программы. Зачем они нужны?

Когда человек со стороны посмотрит на вашу программу, например, на эту (из калькулятора):

Private Sub Кл_сложения_Click()

Звук.FileName = "с: \Windows\Mediа\Chimes.wav"

Звук.Command = "Open"

Звук.Command = "Sound"

Звук.Command = "Close"

Результат.Text = Val(Число1.Text) + Val(Число2.Text)

End Sub

он вряд ли поймет, в чем здесь смысл и для какой задачи программа написана. Если Звук, то при чем здесь сложение? Да и все остальное… Ну да ладно, это полбеды, а беда в том, что если через пару лет вам срочно понадобится самому разобраться в этой старой своей программе (так как ее выдвинули на Мобилевскую премию), а вы за это время ни разу не работали со звуком, то вы сами не сможете ничего понять, так как все забыли!

Любой профессиональный программист знает две вещи. Первое — любая старая программа через год забывается напрочь. Второе — почти любая старая программа или ее часть через полтора года бывает вдруг позарез нужна как исходный материал для новой программы и поэтому в ней надо срочно разобраться. Наученный горьким опытом, программист снабжает многие строчки кода собственными комментариями. Получается вот что:

'Процедура, которая объясняет компьютеру, что ему делать, если мы щелкнули

'по клавише сложения калькулятора, а именно: проиграть короткую мелодию

'Chimes.wav на объекте с именем Звук, а затем сложить два числа.

Private Sub Кл_сложения_Click()

Звук.FileName = "c: \Windows\Media\Chimes.wav" 'Указываем адрес звукового файла на диске.

Звук.Command = "Open" 'Перед проигрыванием файл нужно обязательно открыть.

Звук.Command = "Sound" 'Включить воспроизведение.

Звук.Command = "Close" 'После проигрывания файл нужно обязательно закрыть.

Результат.Text = Val(Число1.Text) + Val(Число2.Text) 'Складываем числа, причем Val преобразует текст в число

End Sub

Компьютеру комментарий не нужен, он его не поймет, а если начнет понимать, то ничего хорошего из этого не выйдет. Так что заглядывать в него компьютеру не нужно. И чтобы ясно показать компьютеру, куда ему не надо заглядывать, программист в каждой строке кода перед комментарием ставит одинарную кавычку. Visual Basic, выполняя очередную строку кода, просматривает ее слева направо, и как только наткнется на кавычку, правее уже не глядит.


Перенос длинного оператора на следующую строку

Иногда оператор получается такой длинный, что не умещается на экране. Это не беда — в окне кода он уместится, так как окно гораздо шире экрана, надо только его прокрутить. Но все равно неприятно, прокручивать не хочется. Оператор можно перенести на другую строку комбинацией пробела и подчеркивания. Например, вместо

Результат.Text = Val(Число1.Text) + Val(Число2.Text)

можно записать

Результат.Text = Val(Число1.Text) _

+ Val(Число2.Text)

или

Результат.Text = _

Val(Число1.Text) _

+ Val(Число2.Text)

Как видите, в конце строк стоит пара символов — пробел и за ним знак подчеркивания.

Запись нескольких операторов в одной строке Visual Basic допускает писать в одной строке несколько операторов, разделяя их двоеточиями, вот так:

Звук.Command = "Open": Звук. Command = "Sound": Звук.Command = "Close"

Это приятно экономит место по вертикали экрана.


Превращаем наш калькулятор в независимую программу

В Windows вы привыкли запускать игры и другие программы двумя способами: щелкнув по значку программы на рабочем столе Windows (или в папке или в проводнике) или выбрав программу в стартовом меню на панели задач. Наш калькулятор запускается пока только из Visual Basic, что, возможно, уязвляет вашу гордость. Что ж, превратим его в независимую программу, которая будет запускаться, как и все, без запуска Visual Basic.

Для этого — File->Make Project1.exe. Затем в открывшемся окне выбираем папку, где будет сохранен будущий файл нашей независимой программы, и задаем ему имя (скажем, Суперкалькулятор). Затем ОК — и ваш файл Суперкалькулятор. ехе готов. Если вы в качестве папки сохранения файла выберете с: \Windows\Paбoчий стол, то ваш калькулятор расположится на рабочем столе Windows, а если вы ярлык этого файла (ярлыков мы не проходили) поместите в папку с: \Windows\Главное меню\Программы\Стандартные, то он будет красоваться в запускающем меню рядом со стандартным калькулятором Windows (это все равно, что сидеть с Биллом Гейтсом в одном Мерседесе).

Однако, если вы попытаетесь скопировать ваш Суперкалькулятор. ехе на другой компьютер и там его запустить, то вас может ждать неудача. Здесь нужны более сложные действия, чем я описал.

Сохранение проекта на диске.


Загрузка проекта с диска

Итак, вы готовы запустить новый проект на выполнение. Во время выполнения может произойти неприятная вещь — Visual Basic может зависнуть[24]. Это означает, что изображение на экране замрет, и никакими клавишами или мышкой вы не сможете вывести Visual Basic из ступора. Придется выходить из Visual Basic "аварийно" — при помощи клавиш Ctrl-Alt-Del. Поскольку ваш проект находится пока только на экране и в оперативной памяти, то при аварийном выходе из Visual Basic он пропадет и вам придется создавать его снова.

Чтобы избежать лишней работы, вы должны перед выполнением проекта записать (сохранить) его на диск.

Для этого в меню File есть опция Save. Как только вы ее выберете, перед вами появится диалоговое окно —>



В списке Save in компьютер предлагает вам выбрать папку, в которую вы хотели бы записать проект. В первый раз он предлагает вам ту папку, в которую сам установлен (на рисунке это папка VB98). Я ни в коем случае не рекомендую с этим соглашаться, так как в этом случае файлы вашего проекта будут перемешаны с рабочими файлами Visual Basic. Прежде чем порекомендовать, в какую папку вам следует сохранить свой проект, я расскажу вам, как, не выходя из нашего диалогового окна, путешествовать по папкам и дискам, как создавать папки и делать другие необходимые вещи.


В большом списке папок и файлов в середине диалогового окна вы видите содержимое папки, выбранной в списке Save in. Вы видите все папки и ни одного файла, хотя их там множество. Чтобы увидеть все файлы, что совершенно не обязательно, выберите в списке Save as type вариант All Files. В противном случае вы будете видеть кроме папок только файлы форм с расширением frm, о чем говорит предлагаемый вам вариант Form Files (*.frm).

Вы можете двойным щелчком мыши войти в любую из папок в большом списке. Тогда именно она появится в списке Save in, а в большом списке появится ее содержимое. Таким образом вы можете продвигаться вглубь папок, как внутрь матрешки. А как продвигаться наружу? Для этого есть кнопка . Щелчком по ней вы выйдете из папки, показанной в списке Save in, в папку, внутрь которой она входит. Еще щелчок — еще один шаг наружу. И так далее, пока не окажетесь на рабочем столе (Desktop), на котором расположены и значок Мой компьютер и другие значки. Если хотите опять добраться до дисков, войдите в Мой компьютер.

Щелкнув по черной треугольной стрелке в раскрывающемся списке Save in, вы раскроете список папок в виде части дерева, похожего на дерево Проводника Windows. Это позволит вам быстрее путешествовать по папкам.

Внутри папки, выбранной в списке Save in, вы можете создавать новые папки.

Новая папка будет создана, если вы щелкнете по кнопке — . Тут же вам нужно будет ввести с клавиатуры ее имя.

В приложениях Windows очень удобно пользоваться правой клавишей мыши. Каждый раз, когда вы хотите что-нибудь сделать с папкой, файлом или другим объектом на экране, но не знаете, на какие кнопки для этого нажимать, щелкните по этому объекту правой клавишей мыши. Немедленно из объекта выпадет так называемое контекстное меню, в котором перечислены самые популярные действия над этим объектом. Вам останется только выбрать. Новички! Будьте осторожны. Не выбирайте Cut (вырезать) или Delete (удалить).

Чтобы скопировать файл или папку в другое место, выберите в его контекстном меню опцию Сору (копировать). Затем доберитесь до папки, в которую хотите данный файл или папку скопировать, то есть добейтесь ее присутствия в списке Save in, и щелкните правой клавишей мыши по свободному пространству внутри большого списка папок и файлов. В открывшемся контекстном меню выберите Paste (вставить). Если вы хотите, чтобы копия находилась рядом с оригиналом, в список Save in заходить не нужно.

Чтобы переместить файл или папку в другое место, делайте все то же, что и при копировании, только вместо Сору выберите в контекстном меню опцию Cut (вырезать).

Чтобы переименовать файл или папку, выберите в контекстном меню опцию Rename (переименовать).

Итак, чтобы правильно сохраниться в первый раз, создайте внутри предлагаемой вам папки VB98 папку, в которой вы будете хранить все папки своих проектов, назовите ее как-нибудь, например, "Мои проекты". Затем зайдите в нее и создайте внутри нее папку для своего первого проекта. Затем зайдите в нее. В поле File Name компьютер предлагает вам имя для файла вашей формы Form1.frm. Хотите — оставьте его неизменным, хотите — измените. Нажмите кнопку Save. Visual Basic сохранит файл формы и предложит вам сохранить главный файл вашего проекта. Причем под именем Project1.vbp. Сохраните и его под этим или другим именем.

Таким образом, ваш проект сохраняется в нескольких файлах.

После выполнения проект обычно исправляют и дополняют и перед следующим выполнением опять сохраняют: File —> Save. Но в этот раз диалоговое окно не появляется. Visual Basic, ни о чем вас не спрашивая, стирает с диска весь ваш проект (в том виде, как он был сохранен в последний раз) и на его место записывает с тем же именем его исправленную и дополненную версию, то есть ту, что вы видите на экране. (На усмотрение программиста оставляется решить, а лучше ли новая версия старой и не жалко ли старой версии.) Так поступают все современные программные продукты.

Загрузка проекта с диска. Предположим, вы вчера сохранили свой проект, а сегодня хотите продолжить с ним работу. Вы включаете компьютер, запускаете Visual Basic, затем — File —> Open. На экране появляется диалоговое окно, очень похожее на то, что появляется при сохранении проекта. И действия ваши очень похожи: вы должны отыскать в окне папку вашего сохраненного вчера проекта, для чего вам придется попутешествовать по папкам. Зайдя в папку, откройте главный файл вашего проекта. Ваш проект появляется на экране.

Если ваш новый проект делается на основе старого, то чтобы не начинать новый проект с нуля, откройте окно загрузки проекта, скопируйте папку старого проекта и делайте новый проект на основе копии старого. Скопировать папку можно и в Windows, не заходя в Visual Basic.


Окна среды Visual Basic

До сих пор я не рассматривал систематически окна и меню Visual Basic 6.0. И вы, наверное, уже столкнулись в связи с этим с некоторыми проблемами. Для дальнейшего движения вперед необходимо рассмотреть их более подробно.

Начнем с окон. Их в среде Visual Basic довольно много, ведут они себя, как и положено окнам Windows: налезают друг на друга, заслоняют друг друга, часто нужное окно вообще куда-то исчезает. В общем, нужен порядок. Сначала разберемся, какие окна есть вообще. Вот названия окон по-английски:

Object — это окно, имеющее у нас заголовок Project1 — Form1 (Form). Его назначение — служить вместилищем для формы. Саму форму в режиме проектирования двигать мы не можем, так хоть окно подвигаем.

Toolbox — вместилище элементов управления.

Code — окно кода. Сейчас нам нужно научиться заставлять Visual Basic выводить в окно кода заготовку процедуры для обработки любого события. Пока мы умеем только, щелкнув дважды мышкой по кнопке Command1, получить заготовку процедуры Command1_Click. Но с кнопкой связана масса событий, а не только щелчок мышью. Как написать процедуры для других событий?

Пусть в вашем проекте есть такие объекты: форма, Command1 и Text1. Все их вы найдете в списке, находящемся в левой верхней части окна кода, если щелкнете по черной стрелке, раскрывающей этот список. Пусть вам нужно написать процедуру для обработки двойного щелчка мышью (DblClick) по объекту Text1. Выбираете в упомянутом списке Text1, затем раскрываете список, находящийся справа от упомянутого, и находите в нем все события, связанные с Text1. Выбираете из них DblClick — и в окне кода тут же возникает нужная вам заготовка:

Private Sub Text1_DblClick()

End Sub

Один момент: Если вы случайно щелкните по одной из двух маленьких кнопочек в левом нижнем углу окна кода, то часть процедур (или все они) куда-то пропадет. Щелкните по соседней кнопке.

Properties — окно свойств объекта.

Project Explorer — в этом окне мы видим структуру нашего проекта. Пока от него толку нет, так как у нас структура простая — одна форма и связанный с ней код. Сложные проекты могут состоять из многих форм и других элементов, взаимосвязь которых удобно видеть в этом окне.

В верхней части окна Project Explorer можно видеть три кнопки. Левая и средняя из них удобны для быстрого переключения между формой и окном кода.

Если какое-то из описанных выше или ниже окон не открыто, идите в пункт View главного меню, а затем щелкните по имени того окна, что вам нужно. Если окно открыто, но Заслонено другими окнами, то идите в пункт Window главного меню, а затем щелкните по имени нужного окна. Со всеми этими окнами можно делать все, что допускает любое окно Windows.

Form Layout — позволяет вручную задавать позицию формы на экране после запуска проекта.

Object Browser — делится на два вертикальных списка. В левом приведены типы (классы) объектов Visual Basic. Если выделить в нем какой-нибудь объект, например, TextBox, то в правом списке можно видеть свойства этого объекта, события, которые могут происходить с этим объектом, и так называемые методы, ему принадлежащие. Свойств здесь, между прочим, больше, чем в окне свойств, так как здесь приведены и те свойства, которые имеют смысл только в режиме [run]. Например, свойство SelText объекта TextBox, которое выдает фрагмент текста, выделенного нами в текстовом поле. Object Browser — довольно удобный способ увидеть, что "умеет" делать любой объект и что можно делать с ним.

Color Palette — позволяет удобно раскрашивать объекты и текст в режиме проектирования.

Многие окна имеют привычку при сближении состыковываться, "склеиваться" между собой или "прилипать" к краям главного окна Visual Basic. Сделано это для удобства программистов, но поначалу может восприниматься, как неудобство. Вы можете отменить это свойство, зайдя в Tools —> Options->Docking и убрав оттуда флажки.

После запуска проекта ваша форма как бы отделяется от среды и "плавает" по экрану самостоятельно. При этом, если вы неосторожно щелкните мимо формы, то она может пропасть из виду, загороженная другими приложениями Windows, в том числе — главным окном Visual Basic. Чтобы она снова появилась, достаточно щелкнуть по ее значку на панели задач Windows.


Главное меню Visual Basic

А теперь рассмотрим все нужные вам на первых порах пункты главного меню среды. Для понимания дальнейшего отметим, что в среде можно одновременно работать с несколькими проектами.

• File

New Project. Удаляет из среды все открытые проекты и создает новый проект.

Open Project. Удаляет из среды все открытые проекты и открывает для работы один из проектов, сохраненных вами ранее.

Add Project. Если у вас в среде уже открыто несколько проектов, то добавляет к ним или новый или (если вы выберете Закладки Existing или Recent) один из проектов, сохраненных вами ранее. Если ни одного проекта не открыто, то действует, как New Project или Open Project.

Remove Project. Удаляет из среды ваш проект, а если у вас открыто несколько, то один из них, а именно тот, что выделен в окне Project Explorer.

Save Project. Сохраняет ваш проект на диске.

Save Project As. Сохраняет на диске копию вашего проекта.

Print. Распечатывает программу или формы вашего проекта на принтере.

Print Setup. Настройка печати.

Маке Project1.exe. Превращает ваш проект в исполняемый файл.

Ниже этих пунктов расположен удобный список для открытия проектов, которые вы открывали последними.

Exit. Выход из Visual Basic.


• Edit

Undo. Отменить последние действия.

Redo. Вернуть отмененные действия.

Cut, Сору, Paste, Delete. Обычные и привычные для вас команды перемещения, копирования, удаления слов и фрагментов текста вашей программы. Применяются не только к тексту, но и к элементам управления на форме. А с элементами управления вот как. Часто, когда нам нужно иметь на форме несколько совершенно одинаково настроенных элементов управления, удобнее не брать их поодиночке в Toolbox, а разместив один на форме и настроив его нужным образом, затем скопировать его. Копировать можно двумя способами:

Щелчок по копируемому объекту —> Сору —> щелчок по форме —> Paste.

Щелчок по копируемому объекту правой клавишей мыши —> пункт Сору в выпавшем контекстном меню —> щелчок по форме правой клавишей мыши —> пункт Paste в выпавшем контекстном меню.

Аналогично используются Cut (вырезать для переноса в другое место) и Delete (уничтожить).

Find, Find Next, Replace. Команды поиска и замены в тексте вашей программы отдельных слов и фрагментов.


• View

Code, Object, Object Browser, Project Explorer, PropertiesWindow, Form Layout Window, Toolbox, Color Palette — это все названия окон среды Visual Basic, о которых речь была выше. Щелчок по любому из этих пунктов делает соответствующее окно видимым.

Immediate, Locals, Watch — окна, которые нужны для отладки проекта.


• Project

Add Form — добавить форму. Ваша форма в режиме проектирования — это будущее окно в режиме [run]. Если вы выберете этот пункт, то в режиме проектирования у вас будет уже две формы. Это значит, что в режиме [run] вы сможете иметь два окна. Кстати, у каждой формы — свое окно кода, значит, окон кода у вас тоже два. Вы можете добавлять сколько угодно форм.

Remove Form — удалить форму.

Components. Если вы щелкните по закладке Controls, то это пункт позволяет добавить в окно Toolbox нестандартные элементы управления. Если вы щелкните по закладке Insertable Objects, то сможете вставлять в форму окна других приложений Windows. Например, если у вас на компьютере установлен Word, то найдите в списке пункт Microsoft Word Document и поставьте галочку. В окне Toolbox у вас появится значок документа Word. Берите его как обычный инструмент и располагайте на форме. Теперь у вас на форме расположен документ Word и, не выходя из Visual Basic, вы сможете пользоваться многими возможностями Word как в режиме проектирования, так и в режиме [run]. Для этого достаточно сделать двойной щелчок мышкой по документу, размещенному вами на форме.


• Format

Align, Make Same Size и другие — эти пункты имеют дело с размерами, формой и местоположением элементов управления на форме и друг относительно друга, то есть с тем, с чем вы и так прекрасно справляетесь безо всяких меню. Выделите один или несколько объектов на форме и попробуйте применить эти пункты, посмотрите, что получится. Чтобы выделить несколько объектов, щелкайте по ним при нажатой клавише Ctrl или обведите их рамочкой.

Order. Бывает, что в результате вашего проектирования формы некоторые элементы управления перекрываются другими. Для примера поместите на проект две большие кнопки так, чтобы одна частично закрывала другую. Тогда приобретает важность вопрос — какой из объектов ближе к вам, а какой дальше. Управлять этим вы можете, выбрав Bring to Front (выдвинуть на передний план) или Send to Back (задвинуть на задний план)

Lock Controls. Иногда неловким движением мыши вы можете сдвинуть или изменить размер объекта в тщательно созданном вами проекте. Чтобы этого не произошло, и нужен этот пункт. Объекты примерзнут к месту. Когда вы захотите их разморозить, снова выберите этот пункт.


• Debug

Этот пункт нужен для отладки проекта и о нем особый разговор.

Run, Query, Diagram

Эти пункты меню мы не будем затрагивать.


• Tools

Здесь находится Menu Editor, который применяется для создания меню в проекте. Но нам сейчас интересен не он, а пункт Options, который позволяет настраивать среду Visual Basic: Вот его закладки:

Закладка Editor — здесь рекомендую установить все флажки, так как каждый из них обеспечивает те или иные удобства работы в окне кода. Особенно хочу подчеркнуть флажок Require Variable Declaration, который требует обязательного объявления переменных величин. Поле Tab Width регулирует отступ при нажатии клавиши Tab.

Закладка Editor Format — здесь вы можете настроить шрифт, размер шрифта, цвет шрифта и цвет фона в окне кода.

Закладка General — здесь вы, изменяя числа в двух полях, можете настроить расстояние между линиями сетки на форме по горизонтали и вертикали. Флажок Align Controls to Grid требует, чтобы очертания элементов управления проходили только по линиям сетки. Убрав флажок Show Grid, вы сделаете линии сетки невидимыми. Остальные флажки оставьте установленными, переключатель не трогайте.

Закладка Docking — Как я уже говорил, окна среды Visual Basic имеют привычку при сближении состыковываться, "склеиваться" между собой или "прилипать" к краям главного окна Visual Basic. Вы можете установить или отменить это свойство у каждого из окон, установив или убрав флажки.

Закладка Environment — Переключатель When Visual Basic starts определяет, будет ли Visual Basic при своей загрузке предлагать создать или открыть проект (Prompt for project) или без предупреждения создавать новый (Create default project). Переключатель When a program starts определяет, будет ли Visual Basic перед любым запуском проекта на выполнение автоматически сохранять несохраненный проект (Save Changes), предлагать сохранить проект (Prompt То Save Changes) или не сохранять (Don't Save Changes). Беспечным советую первое. Флажки должны быть везде установлены.

Закладка Advanced — пока она нам не нужна.


• Add-Ins

Здесь нам будет интересен Visual Data Manager, применяющийся для работы с базами данных..


• Window

Мало чем отличается от аналогичного пункта в других приложениях Windows. Позволяет разными способами упорядочить сумятицу окон на экране или выдвинуть на передний план спрятавшееся окно.

Split позволяет смотреть на ваш код через два окна, а не через одно, что бывает удобно, когда кода много.


• Help

Когда вы пишете оператор на Visual Basic, вы должны, во-первых, понимать, что он означает и что означает каждая его часть, а во-вторых, вы должны знать правила его записи. Visual Basic чрезвычайно богат, в него входят тысячи элементов — свойств, событий и др. Невозможно запомнить смысл и правила записи каждого элемента. Вот здесь-то и нужен Help — система помощи, которая позволит вам быстро найти информацию по любому элементу. Если, конечно, вы знаете английский.

Если вы хотите узнать подробности о каком-то служебном слове, например, BackColor, вы щелчком мыши ставите на него текстовый курсор и нажимаете на клавиатуре клавишу F1.

Contents представляет вам информацию в слегка систематизированном виде.

Index удобен тогда, когда вы заранее знаете название элемента, который вас интересует (например, FileName).

Система помощи в Visual Basic 6.0 осуществляется через так называемую библиотеку MSDN (MSDN Library), которая инсталлируется или с отдельных компакт-дисков или входит в состав пакета Visual Studio.


Панель инструментов

Предназначена для быстрого доступа к популярным пунктам меню. Задержите мышку на любом значке панели — и он назовет себя. В правой части панели — две пары чисел. Это свойства Left, Top, Width и Height выделенного объекта.

Кроме главной панели инструментов в Visual Basic есть еще несколько. Добраться до них можно так: View —> Toolbars. Там вы найдете, в частности, панель Form Editor, при помощи которой вы сможете делать с элементами управления на форме многое из того, что делается в пункте Format главного меню, но быстрее. Также вам, возможно, пригодится панель Edit для работы с программным текстом в окне кода. Там же вы можете создать собственную панель инструментов или изменить стандартные.


Перенос вашего проекта на другие компьютеры

Когда ваш проект, например, Калькулятор, заработает на вашем компьютере, вам захочется, чтобы он заработал и на компьютерах ваших друзей. Но вот беда — на их компьютерах не установлен Visual Basic. Раньше для решения этой проблемы достаточно было создать исполняемый файл вашего проекта (назовем его Калькулятор.ехе) и скопировать его на компьютер вашего друга. Теперь не то. У новых версий Visual Basic гораздо более солидный и тяжелый подход к переносу программ с компьютера на компьютер. Не копировать, а инсталлировать — вот девиз! В причины отказа от легкой жизни я не буду вдаваться, основная такая — Visual Basic слишком зависит от Windows, а на разных компьютерах Windows разные или настроены по-разному.


Первый этап — подготовка проекта

В вашей программе могут встретиться операторы типа Плеер.FileName = "c: \Windows\Media\Canyon.mid" или

Form1.Picture = LoadPicture("С: \Program Files\Microsoft Office\Clipart\Popular\Agree.wmf")

To есть в режиме работы ваш проект обращается к файлам, находящимся где-то далеко на диске. Вам никогда не приходило в голову, что будет, если кто-то, не подозревая, что эти файлы нужны вашей программе, сотрет их? Ничего хорошего не будет. А если вы к тому же предназначаете ваш проект для чужого компьютера, опасность и морока возрастают вдвойне.

Отсюда совет: Все такие файлы заранее скопируйте в папку вашего проекта, туда, где находятся файлы Project1.vbp и Form1.frm. По принципу "Все мое ношу с собой". Соответственно вам придется переделать и адреса в приведенных выше операторах. Пусть папка вашего проекта находится по адресу "с: \Проекты\Калькулятор". Тогда эти два оператора будут выглядеть так:

Плеер. FileName = " с: \Проекты\Калькулятор\Саnуоn.mid"

Form1.Picture = LoadPicture("с: \Проекты\Калькулятор\Аgrее.wmf")

Однако тут возникает еще одна проблема. Папку вашего проекта вы когда-нибудь можете захотеть перенести в другое место диска, от чего эти адреса сразу станут неправильными. Да и на чужом компьютере ваш проект наверняка попадет в папку с совсем другим адресом. В Visual Basic есть средство справиться с этой проблемой. Итак, вы скопировали файлы Canyon.mid и Agree.wmf в папку вашего проекта. Теперь вам достаточно приведенные выше операторы переписать в следующем виде:

Плеер. FileName = App.Path & "\Canyon.mid"

Form1.Picture = LoadPicture (App.Path & "\Agree.wmf")

Имеется некий объект App, назначение которого — в любой момент выполнения проекта кое-что знать о нем, в частности, его свойство Path как раз имеет значение адреса выполняемого проекта "с: \Проекты\Калькулятор".

Картинки, которые вы загрузили в объекты на этапе проектирования, не нуждаются во всех этих усилиях, так как они уже неявно сохранены в одном из файлов в папке проекта.

Если вы хотите, чтобы исполняемый файл вашего проекта имел собственный значок в Windows, придайте в режиме проектирования значение свойству Icon вашей формы.

Рекомендую с самого начала разработки проекта сохранять его не под предлагаемым именем Project1.vbp, а под уникальным именем, например, Калькулятор.vbp.


Второй этап — компиляция проекта в исполняемый файл

Напоминаю ваши действия: File —> Make Project1.exe —> на экране возникает окно Make Project —> укажите имя исполняемого файла (Калькулятор. ехе) и если хотите, выберите папку, куда он будет записан. Если не станете выбирать, он по умолчанию будет записан в папку проекта (что и рекомендую) —> жмите ОК —> файл готов.

Если исполняемый файл работает плохо, вам придется компилировать сначала. При этом в окне Make Project зайдите в Options->Compile и проверьте, чтобы был установлен флажок Compile to Native Code. Затем зайдите в Advanced Optimizatons и убедитесь, что ни один флажок не поставлен.


Третий этап — создание инсталляционного пакета

Выйдите теперь из Visual Basic в Windows. Инсталляционный (или дистрибутивный) пакет создается при помощи мастера Package & Deployment Wizard, который должен был установиться на ваш компьютер при установке Visual Basic. Добираются до него через стартовое меню Windows. Там он находится недалеко от Visual Basic.

Мастером называется программа, позволяющая пользователю делать сложные вещи с минимальной затратой умственных сил. Обычно работа мастера состоит из нескольких шагов, на каждом из которых мастер задает пользователю вопросы. Переход к следующему шагу осуществляется кнопкой Next. Вернуться назад вы можете кнопкой Back.


Запустите мастер Package & Deployment Wizard. В появившемся окне мастера кнопкой Browse найдите файл вашего проекта Калькулятор.vbp и нажмите кнопку Package. Через несколько секунд работы в качестве следующего шага работы мастера появляется окно Package Туре.

Package Туре. Некоторые шаги начинающие программисты могут без большого вреда пропустить. Такие шаги я объяснять не буду. Выделите верхнюю из двух строк. Теперь нажмите кнопку Next. Следующий шаг — окно Package Folder.

Package Folder. Мастер спрашивает, в какую папку на вашем диске записывать весь дистрибутивный пакет. Рекомендую согласиться с предложением мастера, тогда он создаст внутри папки вашего проекта папку Package и запишет все в нее. Если вам это не нравится, жмите кнопку New Folder. Если нравится, нажмите кнопку Next. Мастер спросит, согласны ли вы на создание папки Package. Отвечайте Yes. Мастер перейдет к следующему шагу:

Included Files. Здесь мастер показывает вам для вашего сведения список несжатых пока файлов, включаемых в инсталляционный пакет. Вы должны позаботиться о том, чтобы добавить в этот список загружаемые во время работы звуковые и другие файлы, речь о которых шла на первом этапе. Для этого нажмите кнопку Add. Поскольку в возникшем окне вам видны не все нужные файлы, настройте фильтр Files of type этого окна в значение All Files. Найдите теперь нужный файл и нажмите Open. Файл окажется в списке. Проделайте то же самое с остальными нужными файлами. Next.

Cab Options. Большинство файлов дистрибутивного пакета будут сжаты внутри так называемых САВ-файлов. Эти файлы могут быть довольно большими, поэтому мастер спрашивает вас, что делать — много маленьких (Multiple cabs) или один большой (Single cab). Если вы хотите создать дистрибутивный пакет на дискетах, то установите переключатель в положение Multiple cabs и выберите размер дискеты. Тогда САВ-файлы будут создаваться такого размера, чтобы умещаться на дискете. Если вас не волнует размер САВ-файла, то выберите Single cab. Next.

Installation Title. Мастер просит ввести заголовок устанавливаемой программы, который для вящей солидности будет крупным шрифтом отображаться на заднем плане в процессе инсталляции. Next.

Start Menu Items. Настройка стартового меню Windows — в каком его месте и под каким заголовком будет фигурировать ваша программа. Попробуйте разобраться сами. Или просто нажмите Next.

Install Locations. Next.

Shared Files. Next.

Finished!. Finish.

Вслед за этим покажется рапорт мастера о проделанной работе. Можете закрыть его, не читая.

Можете закрыть окно мастера. Дистрибутивный пакет создан.


Находясь в Windows, загляните в папку проекта. Вы обнаружите в ней папку Package. Загляните в нее. Там вы увидите один или несколько САВ-файлов, в которые ужался и ваш проект, и некоторые неведомые вам файлы, необходимые для инсталляции и нормальной работы вашего проекта на чужом компьютере. Кроме САВ-файлов вы увидите файлы Setup.exe и SETUP.LST. Если вы хотите посмотреть на инсталляционные файлы в несжатом виде, загляните в папку Support, находящуюся в той же папке Package. Папка Support не входит в состав инсталляционного пакета. Инсталляционным пакетом являются все файлы, находящиеся в папке Package за исключением файлов из папки Support! На дискеты или на жесткий диск чужого компьютера нужно копировать только инсталляционный пакет файлов.


Четвертый этап — инсталляция

Сначала в качестве эксперимента проведите инсталляцию на своем компьютере. Запустите Setup.ехе.

Первое, что после запуска Setup.exe предлагает программа инсталляции, это выйти из всех запущенных программ. Сделайте это и нажмите ОК.

В следующем окне под заголовком Directory вам предлагается адрес папки, в которую будет устанавливаться ваша программа. Если он вам не нравится, нажмите кнопку Change Directory и выберите нужную папку или впишите адрес в текстовое поле. Когда вы будете довольны адресом под заголовком Directory, щелкните над ним по большой квадратной кнопке.

Теперь вам предлагают выбрать или самому назвать программную группу для вашей программы в стартовом меню Windows. Послушайтесь и нажмите Continue.

Программа установки устанавливает файлы на жесткий диск и рапортует об успешном окончании работы. ОК.

Теперь можете запускать свою программу из стартового меню.

Вам будет полезно заглянуть в папку, куда установилась ваша программа, и посмотреть, что там есть.

Чтобы установить вашу программу на компьютер вашего друга, перепишите дистрибутивный пакет на его компьютер и запустите Setup.exe. Или можете, не переписывая, просто вставить первую дискету с дистрибутивным пакетом (ту, на которой Setup.exe) в его дисковод и запустить установку. Что делать дальше, я уже описал.


ЧАСТЬ II. ПРОГРАММИРОВАНИЕ НА VISUAL BASIC — ПЕРВЫЙ УРОВЕНЬ

Кончилась наша сладкая жизнь. Вернее, в ней наметился большой перерыв. Действительно, калькулятор достался нам без особого напряжения. Работы мало — удовольствия много. Есть ли еще возможности почти без программирования быстренько получать что-нибудь "эдакое"? Есть, и их много. В популярных журналах, посвященных программированию, вы найдете немало программок из двух-трех строчек кода, скопировав которые в свой компьютер, вы получите на экране любопытные вещи. Только вот беда — хоть этих строчек всего две-три, понять их нет никакой возможности. Кто вы в таком случае — программист или переписчик иероглифов? И это тот гранит науки, та скала, которую не объедешь. Придется грызть.


Переменные величины

Чтобы сделать в Visual Basic что-нибудь более существенное, чем примитивный калькулятор или примитивный плеер, нам нужно резко увеличить объем знаний о Visual Basic. Первая ступенька на лестнице набирания знания — переменные величины.


Переменные величины. Оператор присваивания

Понятие переменной величины вам известно из школьной математики. Пусть несколько лет назад ваш рост равнялся 130 см. Обозначим этот факт так: r=130.

Теперь он равен 160 см, то есть r=160. Получается, что величина г изменилась. Поэтому она называется переменной величиной. Числа 130 и 160 называются значениями переменной величины r.

Любой язык программирования умеет обращаться с переменными величинами. Без них он был бы очень слаб и смог бы извлечь из компьютера только возможности калькулятора. Точно так же алгебра без переменной величины превратилась бы в арифметику. Однако, преимущества применения переменных величин нам откроются позже, а пока наша задача — к ним привыкнуть.

Что же мы можем делать с переменными величинами, программируя на Visual Basic? Прежде всего, мы можем задавать компьютеру значение той или иной переменной величины. Это мы можем сделать при помощи оператора, который называется оператором присваивания. Так, если мы хотим сказать, что а имеет значение 6, то должны просто записать а=6. Запись а=6 и называется оператором присваивания. Говорят, что величине а присваивается значение 6. С момента выполнения оператора а=6 компьютер будет помнить, что а равно шести.

В старых версиях Бэйсика оператор присваивания для понятности записывали

Let а = 6 что означало "Пусть а = 6".

Мы широко пользовались оператором присваивания в части I. Например, в операторе

Form1.BackColor = vbRed

мы присваивали свойству "цвет" нашей формы значение "красный". Пока, чтобы не рассеивалось внимание, мы в операторе присваивания не часто будем касаться объектов, их свойств и значений. Ограничимся переменными, имеющими численные значения.

После выполнения следующего фрагмента программы

а=2*3+4

Ь=а

y=a+b+1

компьютер будет знать, что а равно 10, Ь равно 10, у равно 21. Итак, при помощи оператора присваивания вы можете и вычислять тоже. Мы видим, что справа от знака равенства в операторе присваивания можно писать не только числа, но и переменные величины, и выражения. Выражения в Visual Basic могут быть разных типов, но об этом мы будем говорить позже. Пока под выражением будем понимать арифметическое выражение, то есть такое, к которому вы привыкли в школьной математике. Здесь это были 2*3+4, а, а+Ь+1. Любое арифметическое выражение имеет численное значение.

Не надо пока проверять это на компьютере. Пока только читайте.

Теперь чуть-чуть о свойствах объектов. Выражение может включать в себя не только переменные величины, но и свойства объектов, имеющие подходящее значение. Например,

Y = а + b + Form1.Width.

В левой части оператора присваивания также может стоять не только переменная, но и свойство объекта. Например,

Form1.Width = а + Ь + у

В последнем случае действие этого оператора вы сразу увидите на экране.



Еще пара примеров:

Задание 6: Определите устно, какое значение будет присвоено переменной t после выполнения фрагмента: k=1+2: s=2*k: t=6-s?

Необходимо помнить, что если слева от знака равенства стоит переменная величина, то Visual Basic выполняет оператор присваивания "в уме". Имеется в виду, что результат его выполнения не отображается на экране, а только запоминается. Как же увидеть значение переменной величины? Создайте в проекте текстовое поле и дополните программу последнего примера: t = 0: n = 2*t+40: z = — n: Text1.Text=z

Теперь значение величины z, равное -40, вы будете видеть в текстовом поле. Однако, для учебных целей и для отладки программ удобней пользоваться оператором Debug.Print. Так оператор

Debug.Print t, n, z

покажет нам значения всех трех переменных величин. При этом не нужно создавать никаких текстовых полей, результат появляется в услужливо возникающем окне Immediate.


А вот теперь садитесь за компьютер. Создайте новый проект. Ничего реального мы из него делать не будем, он будет служить только для упражнений с переменными величинами. Разместите в нем кнопку, а в окно кода запишите такую программу:

Private Sub Command1_Click()

а = 2 * 3 + 4

b = а

у = а + b + 1

Debug.Print a, b, y, b + у

End Sub

Запустите проект. Щелкните по кнопке Command1 — в окне Immediate должны появиться 4 числа:

10 10 21 31

Вы видите окно Immediate? Если нет, то — View->Immediate Window.

Какая польза от переменных величин?

Самая крохотная и простая польза в том, что с их помощью удобно решать несложные вычислительные задачи. Например, даны стороны прямоугольника: а=27018, Ь=3954. Вычислить его площадь и периметр (напомню, что периметр — это сумма длин сторон прямоугольника).

Создайте проект с кнопкой. Задачу решает следующая программа:

Private Sub Command1_Click()

а = 27018

b = 3954

S = а*b 'Площадь

p=2*a+2*b 'Периметр

Debug.Print S, p

End Sub

После запуска и щелчка по кнопке вы увидите в окне Immediate следующие два числа:

106829172 61944

Первое из них — площадь, второе — периметр. Без применения переменных величин операторы получились бы более громоздкими:

S = 27018*3954 'Площадь

р = 2*27018 + 2*3954 'Периметр

что особенно заметно в больших программах. Есть и масса других преимуществ, которые вы почувствуете в следующих главах.

Продолжаем о переменных величинах

Нужно иметь в виду, что в операторе присваивания слева от знака равенства не может стоять число или выражение. Можно писать с=34, но нельзя писать 34=с. Можно писать z=f-v+990, но нельзя писать f-v+990=z. Правило это принято вот почему. Оператор присваивания устроен так, что сначала смотрит или вычисляет, какое значение имеет правая часть, а затем присваивает это значение тому, что стоит в левой части. То, что справа от знака равенства, присваивается тому, что слева от знака равенства, а не наоборот. Нет смысла присваивать значение числу или выражению.

Обратите внимание еще на один важный момент. Когда школьник видит выражение (например, d+2d), он не обязательно его вычисляет. Он может его преобразовать или, скажем, упростить (получив 3d). Компьютер же, видя выражение, сначала его, может быть, и упростит, но затем обязательно вычислит. А для этого он должен знать численные значения входящих в него величин (в нашем случае это величина d). Таким образом, вычисляя правую часть оператора присваивания (например, у=а+Ь+1), компьютер должен обязательно заранее знать, чему равны переменные, из которых эта правая часть состоит (в нашем случае это а и Ь). Ответственность за это знание лежит полностью на программисте. Пусть забывчивый программист записал такой фрагмент:. а=10: у=а+Ь+1…, нигде в программе не придав Ь никакого значения. Естественно, при вычислении выражения а+Ь+1 компьютер не будет знать, чему равно Ь. В такой ситуации разные языки программирования поступают по-разному. Некоторые "злые" языки просто отказываются вычислять выражения, "вредный" Турбо-Паскаль может подставить вместо Ь какую-нибудь ерунду (и молчок, между прочим), Visual Basic же добрый, он подставляет вместо Ь нуль.

Проверим. Заставим Visual Basic в нашем последнем проекте про прямоугольник не выполнять оператор а = 27018. Для этого его можно просто стереть, но удобнее просто поставить перед ним кавычку, тогда Visual Basic подумает, что это комментарий и выполнять не будет:

’а = 27018

Вот результат:

0 7908

Действительно, все выполнилось так, как если бы а было равно нулю.


Объявление переменных величин InputBox

Как мы можем задать компьютеру какую-нибудь величину? Оператором присваивания — раз. Введя ее в текстовое поле, как мы делали в калькуляторе — два. Есть еще один удобный и приятный способ — InputBox.

В вашем проекте о прямоугольнике вы можете хоть сто раз нажимать на кнопку

— результаты все время будут одинаковые. Это потому что исходные данные а=27018 и Ь=3954 никто не меняет. Скучно. Хорошо бы компьютер при нажатии на кнопку каждый раз спрашивал нас, чему равны стороны прямоугольника. А мы бы ему отвечали. А уж потом он вычислял.

Для этого нам нужно слегка изменить программу:

Private Sub Command1_Click()

а = InputBox("Введите ширину прямоугольника")

b = InputBox("Введите высоту прямоугольника")

S = а*Ь

р = 2*а + 2*Ь

Debug.Print S, р

End Sub

Как видите, заменены первые две строки: а=27018 и Ь=3954.

Конструкция

а = InputBox("Введите ширину прямоугольника")

есть оператор присваивания и означает она приказ компьютеру вывести сначала на экран вот такое окно — >



После чего человек вводит в белое текстовое поле этого окна любое число и нажимает ОК. После этого компьютер присваивает переменной а введенное значение и продолжает работу, то есть переходит к выполнению следующего оператора. Запустите проект и посмотрите, как он работает.

Если вам не нравится строка Project1 в заголовке окна, то вы можете задать свою строку, так дополнив оператор:

а = InputBox("Введите ширину прямоугольника", "Ввод данных")

Результат — >



Почему плохо не объявлять переменные величины

Посмотрим, где Visual Basic дает сбой, если не объявлять переменные величины. Рассмотрим простую задачу:

Даны три стороны треугольника. Вычислить его периметр.

Создаем новый проект с кнопкой для задачи о треугольнике. По аналогии с процедурой о прямоугольнике легко пишем процедуру для треугольника:

неправильная процедура:

Private Sub Command1_Click()

а = InputBox("Введите первую сторону треугольника")

b = InputBox("Введите вторую сторону треугольника")

с = InputBox("Введите третью сторону треугольника")

р = а + Ь + с

Debug.Print р

End Sub

Запускаем проект, вводим стороны — 2, 3, 4 и какой результат мы видим? Вместо 9 мы видим 234! Почему? Здесь тот же случай, что и с калькулятором, там было то же самое, пока мы не применили Val. Почему? Первое: Visual Basic считает содержимое текстового поля окна InputBox (точно так же, как и содержимое обычного текстового поля) текстом, а не числом, если даже оно состоит из цифр. А раз так, то и переменные а, Ь, с, берущие свое значение из текстового поля, он тоже считает текстовыми, а не числовыми. Второе: Visual Basic знает, что по правилам языка знак + имеет несколько смыслов в зависимости от того, к чему он применяется. В частности, при работе с текстом это не приказ складывать, а приказ выстраивать в цепочку. А раз так, то и результат получился тот, что мы видели.

Наши необъявленные переменные, как голодные дворняги, готовы есть все, что им дают. Введите вместо трех чисел три таких текста: Ко, ро, бочка. Результат — Коробочка.

Почему же тогда в примере о прямоугольнике все прошло нормально? Потому что там было еще умножение. Visual Basic знает, что по правилам языка знак умножения * не имеет смысла при работе с текстом. Значит (догадывается умный и услужливый Visual Basic) мой господин — человек не хочет, чтобы переменные а, Ь, с были текстовыми. Значит быть им числовыми! Проверьте: подсуньте компьютеру вместо чисел коробочку — Visual Basic запротестует.

В примере о прямоугольнике Visual Basic догадался правильно, а в примере о треугольнике ума не хватило. Ну что, теперь везде при сложении применять Val? Не хочется, программы будут получаться громоздкими. Да и разве все дело только в сложении? Как узнаешь, где в следующий раз соломки подстелить?

Так вот, чтобы не перенапрягать умственные способности Visual Basic и предохранить себя от неприятностей, нужно все переменные величины объявлять!


Как объявлять переменные величины

Добавим в окно кода нашего проекта, на самый верх, над заголовком процедуры четыре строки. Получится:

правильная процедура:

Dim a As Integer

Dim b As Integer

Dim с As Integer

Dim p As Integer


Private Sub Command1 Click()

а = InputBox("Введите первую сторону треугольника")

b = InputBox("Введите вторую сторону треугольника")

с = InputBox("Введите третью сторону треугольника")

р = а + b + с

Debug.Print а, b, с, p

End Sub


Объявление

Dim а As Integer

переводится так:

Переменная а величина как целое число

то есть вы обязуете Visual Basic обращаться с переменной величиной а как с целым числом и ничем иным. Говорят, что "переменная а имеет тип Integer". Аналогично объявлены и переменные Ь, с, р. Объявления будем пока писать выше процедур.

Запустите проект. Проверьте его работу.

Вместо четырех строк

Dim a As Integer

Dim b As Integer

Dim с As Integer

Dim p As Integer

можно для краткости написать одну:

Dim a As Integer, b As Integer, с As Integer, p As Integer

Но если вы захотите написать еще короче:

Dim а, Ь, с, р As Integer

то Visual Basic неправильно вас поймет.


Типы данных

Много ли прав у Integer? Посмотрим. Попробуем ввести дробное значение первой стороны треугольника — 2,3. Именно так — с запятой, а не точкой. Посмотрим результат. Visual Basic считает а целым числом 2. А теперь — 2,6.

Visual Basic считает а целым числом 3. Все правильно. Наш барон высокомерно отказывается быть дробным числом и поэтому любое число, которое мы ему предлагаем, округляет до целого.

Предположим, мы этим недовольны. Мы желаем, чтобы все числа могли быть дробными. Пожалуйста! Вот так:

Dim a As Single

Dim b As Single

Dim с As Single

Dim p As Single


Private Sub Command1_Click()

a = InputBox("Введите первую сторону треугольника")

b = InputBox("Введите вторую сторону треугольника")

с = InputBox("Введите третью сторону треугольника")

р = а + b + с

Debug.Print а, Ь, с, р

End Sub


Объявление

Dim а As Single

переводится так:

Переменная величина а как десятичная дробь обычной точности

то есть вы обязуете Visual Basic обращаться с переменной величиной а как с десятичной дробью и ничем иным. Десятичная дробь — это любое число, которое может иметь целую и дробную часть (например, 27,3908), в частности это и целое число. Об обычной точности попозже. Говорят, что "переменная а имеет тип Single".

Законный вопрос: зачем нам нужен тип Integer, когда тип Single "гораздо лучше"? Ответ: Не во всем и не всегда он лучше, иначе не стали бы его создавать вообще.

Типов данных в Visual Basic довольно много и каждый полезен по-своему. Рассматривать новые типы я буду по мере надобности. А сейчас отмечу главное — в солидном проекте не объявлять переменные неприлично! Поэтому переменные величины нужно объявлять всегда. А чтобы по нашей человеческой рассеянности какая-нибудь переменная не проскочила необъявленной, поручим компьютеру не пускать таких, то есть прикажем Visual Basic выдавать соответствующее сообщение при нашей попытке запустить проект с необъявленными переменными. Для этого — Tools->Options->Editor->Require Variable Declaration. Отныне в окне кода любого создаваемого вами проекта будет появляться строка Option Explicit, что означает требование обязательно объявлять переменные этого проекта. В общем, "Посторонним В!.." Тем не менее, свобода есть свобода, и вы всегда можете в каком-нибудь проекте стереть строку Option Explicit.

Я сам в примерах этой книги поначалу все, что можно, буду объявлять, но затем для экономии "места и смысла" перестану это делать. Не берите с меня пример!

Вот еще причина, по которой удобно использовать Option Explicit. Как по вашему, что напечатал у меня следующий фрагмент:

х = 2

Debug.Print х

Если вы думаете, что 2, то ошибаетесь. Ничего не напечатал. Потому что в первой строке присутствует латинская буква "икс", а во второй строке я нечаянно написал русскую букву "хэ". Я был в недоумении. Не помогло и объявление переменной "икс" (не помогло бы, между прочим, и объявление "хэ"). Visual Basic не нашел в программе никаких ошибок. И только применение Option Explicit дало намек на истинную причину ошибки.


Переменные величины и память

Полностью механизм работы переменных величин не понять, если не узнать, как они хранятся в оперативной памяти компьютера.

Оперативная память нужна компьютеру для того, чтобы хранить во время выполнения программы саму эту программу и данные, с которыми программа работает.

Как устроена оперативная память (или просто память)? Представьте себе тетрадный листок в клеточку. В каждую клетку вы имеете право записать карандашом какую-нибудь букву или цифру или знак + или вообще любой символ, который можно найти на клавиатуре. А можете и стереть ластиком и записать другой символ. Много ли букв можно записать на листе? Ровно столько, сколько на нем клеток.

Оперативная память компьютера устроена аналогично такому листу. Только клеточек в ней гораздо больше. Каждая клеточка называется байтом. Для запоминания слова КОШКА понадобится 5 байтов. Подробнее о работе памяти см. в Приложении 1.

Значения переменных величин во время выполнения программы компьютер хранит в оперативной памяти (потому что диски для этого слишком медлительны). Для этого он предварительно под каждую переменную отводит в памяти место. При этом компьютер "рассуждает" так: Раз в программе упомянута переменная величина, значит она в каждый момент времени будет иметь какое-то значение, которое, хочешь не хочешь, надо помнить. Лучше, чтобы не спутаться, отвести в памяти определенное место для запоминания текущего значения каждой переменной величины. Будем называть место, отведенное в памяти под данную переменную, ячейкой. Представьте себе город, в котором имеются разные по размерам комнаты и каждому жильцу отведена ровно одна комната. Это тот самый случай.

Теперь о размере комнат. В городе размер комнат меряют в квадратных метрах, в памяти размер ячейки выражают в байтах. Переменной типа Single нужна более вместительная ячейка, чем переменной типа Integer. Так оно и есть на самом деле: под переменную типа Integer в памяти отводится ячейка размером 2 байта, а под переменную типа Single — 4 байта. Только не думайте, что переменная типа Single не может быть длиннее 4 цифр, компьютер для записи чисел в ячейки использует более компактную систему, чем для записи символов.


Что делает оператор присваивания с памятью

Я только что рассказывал о работе оператора присваивания, используя такие выражения, как "компьютер знает", "компьютер помнит". Но нам необходимо более строгое понимание работы этого оператора, понимание "ближе к железу".

Рассмотрим пример программы:

Dim a As Integer

Dim b As Integer

Dim у As Integer


Private Sub Command1_Click()

a = 10: b = 6: y=a+b+1

Debug.Print у + 200

End Sub

В программе встречаются три переменные, поэтому все они объявлены. Компьютер отведет для них в памяти три двухбайтовые ячейки. Вот как будет работать оператор присваивания:

Выполняя оператор присваивания (например, у=а+Ь+1), компьютер сначала смотрит на его правую часть (а+Ь+1). Если в ней встречаются переменные (в нашем случае это а и b), то компьютер перед вычислением ищет их значения в отведенных под них ячейках памяти (и находит там 10 и 6, так как их туда записали операторы а=10 и Ь = 6), подставляет эти значения в правую часть и вычисляет ее. Затем вычисленное значение (17) компьютер записывает в ячейку памяти, отведенную под переменную, поставленную в левой части (у).

Таким образом, когда мы говорим "Компьютер запомнил, что а равно 2", мы подразумеваем "Компьютер записал в ячейку памяти, предназначенную для а, число 2".

А теперь рассмотрим, как будут заполняться информацией ячейки а, Ь, у в процессе выполнения нашей программы. В самом начале выполнения программы в них находятся нули. Первым выполняется оператор а=10. Согласно только что приведенному определению оператора присваивания в ячейку а будет записано число 10. Затем выполняется оператор Ь= бив ячейке Ь появляется шестерка. Затем выполняется оператор у= а+Ь+1. Компьютер смотрит, что находится в ячейках а и Ь, видит там 10 и 6, подставляет их в выражение а+Ь+1, получает 17 и записывает в ячейку у. Наконец выполняется оператор Debug.Print у + 200. Компьютер заглядывает в ячейку у, видит там 17, вычисляет 17+200 и выводит 217 в окно Immediate.

Схематически этот процесс можно изобразить так:



Теперь мы можем также уточнить работу оператора Debug.Print:

Если в операторе Debug.Print встречаются выражения с переменными величинами, то Visual Basic находит в памяти значения этих величин, подставляет их в выражения, вычисляет выражения и результат выводит на экран. В память же ничего не записывается.

Задание 7: Ответьте устно, что произойдет, если поменять местами операторы Ь=6 и у=а+Ь+1?


Режим прерывания. Пошаговый режим выполнения программы

Компьютер выполняет программу со страшной скоростью. Не успели мы нажать кнопку — а результаты уже получены. Пока все идет хорошо, это нас восхищает. Когда же результаты не те, что надо (а ошибок в программе мы не видим), это начинает раздражать. Хотелось бы, чтобы компьютер работал помедленнее и хорошо бы как-нибудь подсмотреть во время работы значения переменных в памяти, это помогло бы найти ошибку. Режим прерывания для этого и предназначен.

Запустите предыдущий проект на выполнение не кнопкой Start, как вы привыкли, а клавишей F8 на клавиатуре. Это горячая клавиша для Debug -> Step Into. Проект начнет выполняться как обычно. Нажмите, как водится, кнопку Command1. И тут вы почувствуете разницу. Вместо того, чтобы полностью выполниться и показать результат, проект остановится на самой первой строке процедуры, а именно, на Private Sub Command1_Click(), в знак чего эта строка окажется подсвечена желтым цветом. Итак, только-только начав выполняться, наш проект замерз до тех пор, пока следующее нажатие F8 его не разморозит. "Мгновение остановилось".

Интересно, чему во время остановки равны значения переменных в памяти компьютера? Для того, чтобы узнать это, достаточно поместить мышиный курсор на обозначение переменной в тексте процедуры в окне кода. Как и положено, "на табло пока одни нули".

Еще раз F8. Ничего не происходит, только полоса подсветки прыгает на следующую строку. В ней находится первый исполняемый оператор вашей процедуры — а = 10.

F8. Visual Basic выполняет а = 10, а следующий оператор подсвечивается. Проверьте, чему сейчас равны а, Ь, у в памяти.

F8. Visual Basic выполняет Ь = 6, а следующий оператор подсвечивается. Проверьте, чему сейчас равны а, Ь, у в памяти.

Итак, правило простое — при нажатии на F8 Visual Basic выполняет очередной оператор программы и подсвечивает тот оператор, которому предстоит быть выполненным.

Обратите внимание, что сменился режим Visual Basic. Мы знаем пока два режима: режим проектирования [design] и режим работы [run]. Теперь в заголовке главного окна Visual Basic вы видите слово [break]. Это означает, что Visual Basic сейчас находится в режиме прерывания. Можно сказать, что режим прерывания — это режим работы с остановками. Вы можете указать Бэйсику, на каких именно операторах останавливаться. Когда же вы нажимаете на F8, вы приказываете Бэйсику останавливаться на каждом операторе. Такая разновидность режима прерывания называется пошаговым режимом.

F8. Visual Basic выполняет у= а+Ь+1, а следующий оператор подсвечивается. Проверьте, чему сейчас равны а, Ь, у в памяти.

F8. Visual Basic выполняет Debug.Print у + 200, а следующий оператор подсвечивается. В окне Immediate возникает число 217.

F8. Подсветка уходит, так как процедура выполнена. Можно снова жать на кнопку Command1.


Замечание об отладке в пошаговом режиме: При отладке в пошаговом режиме вам часто нужно на экране видеть одновременно окно кода, окно Immediate и саму форму. Но при нажатии на F8 то одно, то другое часто пропадает из вида, будучи закрыто другими окнами. Чтобы этого не происходило, еще до начала отладки расположите окно кода и окно Immediate так, чтобы они не перекрывали друг друга, а главное окно Visual Basic уменьшите до части экрана. Затем после запуска отладки форму перетащите на освободившуюся часть экрана. Тогда окно Visual Basic не будет перекрывать форму и проблема исчезнет.

Итак, компьютер сделал все то, что сделал бы при нажатии Start, но только в медленном темпе.

В любой момент пошагового выполнения программы вы можете вместо F8 нажать Start, которая по такому случаю переименовывается в Continue, и программа продолжит выполняться в обычном режиме.

Оператор присваивания меняет значения переменных величин.

Пока я не рассматривал программы, в которых переменные меняют свою величину. Теперь настало время такую программу рассмотреть:

Dim k As Integer

Private Sub Command1_Click()

k = 10: Debug.Print k: k = 25: Debug.Print k: k = 4: Debug.Print k

End Sub

Запишем схематически процесс изменения информации в ячейке к:



Как видите, в процессе работы программы содержимое ячейки к меняется. Так, при выполнении оператора к=25 там вместо значения 10 появляется 25. А куда же девается десятка? Она стирается, то есть компьютер забывает ее безвозвратно. Здесь действует общий принцип работы всех компьютеров:

Если в какое-нибудь место памяти или диска записывается новая информация, то старая информация, записанная там раньше, автоматически стирается, даже если она кому-то и нужна.

Раз теперь вместо 10 в ячейке к находится 25, то оператор Debug.Print к печатает уже 25. (Слова "печатает" и "Print" устарели, они остались от тех времен, когда мониторов еще не было, а вместо них были принтеры. Когда я по старинке говорю, что информация печатается, я подразумеваю, что она появляется на мониторе в том или ином окне.) Следующий оператор к=4 запишет на место 25 четверку, a Debug.Print к ее напечатает. Проверьте.

А что напечатает следующая программа?

Dim f As Integer

Private Sub Command1_Click()

f=30: f=f+4: Debug.Print f

End Sub

Оператор f=30 запишет в ячейку f число 30. А что сделает странный оператор f=f+4? Не думайте, что это уравнение или что-нибудь в этом роде. Это оператор присваивания, а значит и выполнится он согласно определению оператора присваивания, то есть сначала вычислит правую часть f+4, подставив туда вместо f его значение, взятое из ячейки, и получит 34. Затем число 34 будет записано в ячейку, отведенную под переменную, обозначенную в левой части, то есть опять в ячейку f. При этом старое значение 30 будет стерто. Debug.Print f напечатает 34.

Таким образом, оператор f=f+4 просто увеличивает число в ячейке f на четверку или, другими словами, увеличивает f на 4.

Зачем это нужно? Узнаете позже. Очень даже нужно.


Задание 8:

Определите без компьютера, что будет напечатано при выполнении следующих фрагментов программ:

а=100: а=10*а+1: Debug.Print а

а=100: а= — а: Debug.Print а

а=10: b=25: a=b-a: b=a-b: Debug.Print а, b


Еще об именах

Как правильно дать имя объекту, мы говорили в 0. Переменные же величины мы привыкли обозначать буквами (a, s, d…). Большинство языков программирования, в том числе и Visual Basic, позволяет обозначать переменные именами. Вот два равносильных фрагмента программы:

а=3; | Summa=3;

Ь=4-а; | ROBBY=4-Summa;

Debug.Print а, b+50 | Debug.Print Summa, ROBBY+50

В том и другом случае будут напечатаны числа 3 и 51. Очевидно, компьютеру все равно, как мы обозначаем переменные величины или объекты, в смысл имен он не вдумывается и не удивляется, что переменная Summa никакой суммой не является, а просто числом 3.

Многие авторы не рекомендуют использовать в именах русские буквы, говорят, что это опасно. Лично я в связи с этим практически ни разу с большими проблемами не столкнулся. Мой совет: если у вас с английским все ОК, то избегайте русских букв, в противном случае ничего страшного, если вы будете все именовать по-русски.

Примеры правильной записи имен:

a

polnaja_Summmma

tri_plus_dva

s25

а1Ь8 8qqQQQQQQQQQQQQ

oshibka

Это_не_имя

Примеры неправильной записи имен:

polnaja summa — содержится символ (пробел), не являющийся буквой, цифрой или знаком подчеркивания

2as — начинается с цифры

Domby&Son — содержится символ &, не являющийся буквой, цифрой или знаком подчеркивания

Visual Basic игнорирует в именах разницу между строчными и прописными буквами. Так, для него Summa и sUmmA — одно и то же имя. И он присматривает за тем, чтобы в окне кода они были написаны одинаково (но не за всеми русскими именами он так присматривает).


Математика. Запись арифметических выражений

Простые арифметические вычисления лучше делать на калькуляторе, чем на компьютере, а вот сложные — наоборот. В этом разделе вы научитесь правильно вводить в компьютер сложные формулы. Если вы — школьник не самых старших классов, то не все, что здесь написано, будет вам понятно. Не огорчайтесь, при дальнейшем чтении непонятные вещи вам не понадобятся.

Действия арифметики обозначаются в Visual Basic следующим образом:



На уроках математики мы привыкли писать ab+cd, подразумевая: а умножить на b плюс с умножить на d. В Visual Basic это выражение мы обязаны писать так: a*b+c*d. Иначе компьютер подумает, что нужно к переменной, имеющей имя ab, прибавить переменную, имеющую имя cd. Во избежание двусмысленности знак умножения положено писать всегда, в том числе и перед скобками. Например, а * (Ь+с).

Скобки. Ввиду того, что с клавиатуры всю информацию приходится вводить символ за символом в одну строку, ввод двухэтажных выражений, таких как


очень затруднен. Поэтому для обозначения деления и выбрана косая черта. Это выражение на Visual Basic положено записывать так: (а+1)/(Ь+1). Если бы мы не поставили скобок, то выражение получилось бы таким а+1/b+1, а это неправильно, так как компьютер, как и мы, всегда перед сложением и вычитанием выполняет умножение и деление, поэтому в последнем случае он бы сначала разделил 1 на Ь, а затем к результату прибавил а и 1.

Вопрос: когда в выражениях можно ставить скобки? Ответ: всегда, когда у вас возникают сомнения в правильной очередности действий. Лишняя пара скобок не помешает. Пример: записать на Visual Basic выражение:


Его можно было бы записать так:

(1+а/(2+а*Ь))/(3+а)*Ь.

Разберитесь в этой записи. К сожалению, в выражениях разрешается писать только круглые скобки. Квадратные и фигурные запрещены. От этого сложные выражения с большим количеством скобок на глаз воспринимаются с трудом, так как трудно для конкретной скобки увидеть ее законную пару. В этом случае я могу посоветовать идти "от малого к большому", то есть сначала заметить самые малые из взятых в скобки фрагменты выражения (у нас это 3+а и 2+а*Ь). После этого будет уже легче заметить более крупные фрагменты, такие как 1+а/(2+а*Ь), и т. д.

Разобрались? Эта запись меня совсем не удовлетворяет, так как мы не знаем, что Visual Basic будет делать раньше — делить (1+а/(2+а*Ь)) на (3+а) или умножать (3+а) на Ь. А от этого зависит результат. Добавим для верности пару скобок:

((1+а/(2+а*Ь))/(3+а))*Ь

Теперь все в порядке.

Запись десятичных дробей. Путаница с точками и запятыми. Почти во всех языках программирования и уж, конечно, в Visual Basic, в десятичных дробях принято вместо запятой ставить точку. Пример: 62.8 — шестьдесят две целых восемь десятых. Однако, если помните, при вводе дробей в InputBox Visual Basic требовал запятую, да и результаты он выводит с запятой. В чем дело? Visual Basic, являясь приложением Windows, частично воспринимает от нее привычку пользоваться в России запятой. Особой проблемы тут нет. Используйте метод "научного тыка" — пользуйтесь точкой, а если Visual Basic жалуется или начинает делать что-то не то, тогда меняйте ее на запятую.

Математические функции. Кроме нескольких действий арифметики Visual Basic может выполнять и другие математические действия, например, извлечение квадратного корня. На компьютере нет клавиши со значком, поэтому в Visual Basic имеется специальная функция — Sqr. Например, корень из 25 обозначается так — Sqr(25), корень из а+Ь так — Sqr(а+Ь). Здесь Sqr — сокращение от английского выражения Square root — квадратный корень. То, из чего нужно извлечь корень, записывается в скобках.

Приведу неполный список математических функций Visual Basic:



Кроме этого, имеются функции Sin, Cos, Tan (что означает тангенс), Atn (что означает арктангенс), Exp, Log и др.

Примеры:

Выражение (2+1)^2 при вычислении даст 9

Выражение 1+(2+8)^3 при вычислении даст 1001

Выражение 1+Abs(5–8) при вычислении даст 4

Выражение 2^4+Sqr(35+1) при вычислении даст 22

Выражение Sqr(8+Int(41.5)) при вычислении даст 7

Выражение 21\(Round (2.54+1)) при вычислении даст 5


Задание 9: Определите без компьютера, что напечатает данный фрагмент программы: а = (2^2+1)*(20-(2^2)^2)-11:b=11\(а-4): Debug.Print а^2+Ь-1


Типы данных и точность вычислений

Если вы считаете, что компьютер все вычисления выполняет абсолютно точно, то вы ошибаетесь. Компьютер всего лишь очень точен. Очень, а не абсолютно. В этом вы скоро убедитесь.

Integer и Long — целые числа

Создайте проект с кнопкой и введите такую программу:

Dim a As Integer

Dim b As Integer

Private Sub Command1_Click()

a = 100

b = 1

Debug.Print a, b, a + b

End Sub

Работает она нормально. Посмотрим, насколько большие числа способна воспринимать наша программа. Заменим Ь=1 на b=40000. Visual Basic выдает сообщение об ошибке "Overflow", что означает "Переполнение ячейки". В чем дело?

Как вы уже знаете, в Visual Basic принято правило, что если человек объявил переменную, как Integer, то он разрешает ей принимать значения только целых чисел. Число типа Integer занимает в памяти два байта. Значит, под переменные а и Ь компьютер отводит в памяти ячейки по два байта каждая. Два байта — это маленький объем памяти и уместиться в него может лишь небольшое целое число, а именно — число в диапазоне от -32768 до 32767.

Для того, чтобы переменная имела право принимать значения больших целых чисел, она должна быть объявлена не как Integer, а как Long (Длинное Целое). Под переменную типа Long компьютер отводит в памяти 4 байта и поэтому она может принимать значения в диапазоне от -2147483648 до 2147483647.

Зачем нужен Integer, если есть Long? Ну, хотя бы для того, чтобы экономить память, она же не резиновая.


Задание 10: Население Москвы равняется а=9000000 жителей. Население Басюков равняется Ь=1000 жителей. Вся Москва переехала в Васюки. Сколько там стало жителей? Используйте переменные величины.

Single и Double — десятичные дроби

Создайте проект с кнопкой и введите такую программу:

Dim a As Single

Dim b As Single

Private Sub Command1_Click()

a = 100.78656954325: b = 40000.1234567895: Debug.Print a, b, a + b

End Sub

Запустите проект. Вот результат:

100,7866; 40000,13; 40100,91

Как видите, Visual Basic обрезал наши длинные числа до 7 значащих цифр. Сделал он это потому, что 4 байта, отведенные под ячейку памяти для переменной типа Single, не в состоянии вместить больше. Если мы хотим иметь большую точность, то объявляем наши переменные имеющими другой тип — Double — десятичная дробь двойной точности. Под переменную типа Double компьютер отводит в памяти 8 байтов и поэтому она может быть гораздо длиннее.

Dim a As Double

Dim b As Double

Private Sub Command1_Click()

a = 100.78656954325: b = 40000.1234567895: Debug.Print a, b, a+b

End Sub

Запустите проект. Вот результат:

100,78656954325; 40000,1234567895; 40100,9100263327

Здесь максимум — 15 значащих цифр. Если вам интересно задать в программе еще более длинное значение Ь, например, b = 40000.12345678957453457, то у вас ничего не получится, Visual Basic обрежет его прямо в программе, зная, что с такими длинными числами работать он все равно не умеет.

Зачем нужен Single, если есть Double? Ну хотя бы для экономии памяти.


Целые числа или десятичные дроби? Числовой тип Currency

Вы спросите: зачем использовать типы целых чисел Integer и Long, если типы десятичных чисел Single и Double обеспечивают нам работу и с целыми и с дробными числами? Кроме экономии памяти здесь есть еще проблема абсолютной точности вычислений. Дело в том, что при использовании типов десятичных дробей вполне мыслима ситуация, когда дважды два будет не точно 4, а, скажем, 4.00000000000381. Связано это с особенностями представления десятичных дробей в компьютерах. В большинстве реальных задач такая маленькая погрешность несущественна, однако существуют задачи, где точность нужна абсолютная. При использовании же типов целых чисел Visual Basic присматривает за тем, чтобы все числа и результаты были абсолютно точными целыми числами. Конечно, при делении в этом случае приходится округлять.

Если вам нужна абсолютная точность при работе с числами, а величина чисел превышает два миллиарда, тип Long будет слишком узок для вас. Воспользуйтесь типом Currency. Этот тип хоть и имеет дробную часть в размере 4 десятичных знаков после запятой, действия над числами выполняет абсолютно точно. Диапазон представляемых им величин весьма велик — примерно от -900 000 000 000 000 до 900 000 000 000 000.

Совет: Если вам необходимо, чтобы переменная была целым числом и никогда дробным, объявляйте ее целым типом, в противном случае — десятичным.


Не очень устаревшие способы объявления переменных

Вы еще не столкнулись со странной привычкой Visual Basic ставить после чисел в окне кода какие-то значки? Например, вы не объявляли переменную а и собираетесь написать а = 123456789012345, получается же а = 123456789012345#. Ничего страшного, не обращайте внимания, это Visual Basic сообщает вам, что с его скромной точки зрения переменная а имеет тип Double.

У шести типов есть свои значки, по которым их можно узнать (тип String еще не проходили):



Дальше. Если вам лень писать Dim b As Double, вам достаточно в окне кода, там, где переменная b встречается в первый раз, написать b# вместо Ь, например, b# = 5 вместо b=5. Visual Basic будет считать, что вы нормально объявили переменную. Впрочем, этот способ объявления мне не нравится.

Есть еще один способ объявления, совсем страшный. Написав DefInt I — М, вы тем самым объявите компьютеру, что переменнные, имена которых начинаются с букв I, J, К, L, М, N, обязаны иметь тип Integer. Ну и для других типов аналогично: DefLng, DefSng, DefDbl и так далее.


Форматирование результата

Взгляните на такую программу:

Dim a As Double

Dim b As Double

Dim у As Double Private


Sub Command1_Click()

a = 2457642345034.78: b = 0.00000000037645: у = a/b: Debug.Print у

End Sub

Прикиньте без компьютера, каков будет результат. Ясно, что очень большое число, но какое — неясно. Запустите программу. Вот результат:

6,52846950467467Е+21

Что это значит? Это значит, что Visual Basic, видя, что вы работаете с такими гигантскими числами, подумал, что вы большой ученый, и представил вам результат не в нормальном, как для простых смертных, а в так называемом экспоненциальном или научном формате (виде). Но не так страшен черт. Оказывается, это получается шесть целых и сколько-то там дробных и все это умножено на 10 в 21-й степени. Конструкция Е+21 и означает умножение на 1021. По-другому, вам нужно передвинуть запятую на 21 позицию направо — и получится нормальное число, то есть 6528469504674670000000. Кстати, о точности. Обратите внимание, что поделено было неточно. Точно получилась бы бесконечная периодическая дробь, а где ее хранить, бесконечную?

Если бы вместо Е+21 было Е-21, это означало бы умножение на 10-21, то есть деление на 1021, то есть передвижение запятой на 21 позицию налево, то есть очень маленькое число.

Если после этих объяснений вы все еще не полюбили экспоненциальный формат, вы можете приказать компьютеру, чтобы он вас им не утомлял, а показывал результаты по-человечески. Для этого в операторе Debug.Print нужно вместо у написать Format(y, "0.0000"). Получится Debug.Print Format(y, "0.0000"). Конструкция в кавычках состоит из нулей и точки и означает, что вы желаете видеть число в обычном виде, дробную часть числа состоящей ровно из 4 цифр, а остальные пусть Visual Basic вам не показывает. Целую же часть числа Visual Basic покажет вам полностью в любом случае, какова бы она ни была. Вот тот же результат в новом формате:

6528469504674670000000,0000

Вот вам и первое улучшение для калькулятора, ведь он тоже норовит показывать длинные результаты в экспоненциальном формате. Вместо

Результат.Text = Val(Число1.Text) / Val(Число2.Text)

можете написать

Результат.Text = Format(Val(Число1.Text) / Val(Число2.Text),"0.00000000000000000000")

Только имейте в виду — если ваш результат будет такой маленький, что 20 цифр, указанных мной после точки, его "не почувствуют", то ничего, кроме нулей, вы в результате и не увидите, а вот экспоненциальный формат покажет вам настоящий, хоть и непривычный для чтения, результат.


Еще о пользе переменных

Значения переменных величин не обязаны, подобно надписям и значениям текстовых полей, отображаться "на медлительной поверхности проекта". Они спрятаны глубоко в сверхбыстрой оперативной памяти компьютера, там над ними удобно и быстро проводить вычисления и разнообразные логические преобразования. Фактически вся мыслительная работа компьютера проводится над переменными величинами. И лишь иногда, когда человеку понадобится, они показываются "на поверхности" в виде содержимого текстовых полей или как-нибудь еще.

Создавая калькулятор, мы не ведали ни о каких переменных, поэтому вместо изящного

Рез = Чис1 + Чис2 писали громоздкое

Результат.Text = Val(Число1.Text) + Val(Число2.Text)

Вообще, попытки использовать для вычислений вместо переменных текстовые поля напоминает попытку неуклюжих королей-тугодумов (текстовых полей) договориться между собой. После безуспешных попыток они вызывают своих шустрых министров иностранных дел (переменные величины), которые в два счета договариваются и отдают готовый договор на подпись королям (имеется в виду, что результат вычислений показывается в текстовом поле).

С учетом сказанного попробуем улучшить программу калькулятора:

Dim Чис1 As Double 'Переменная, содержащая число из текстового поля Число1

Dim Чис2 As Double 'Переменная, содержащая число из текстового поля Число2

Dim Рез As Double 'Переменная-результат, предназначенный для текстового поля Результат

___________

Private Sub Кл_сложения_Click ()

Чис1 = Число1.Text 'Значения исходных данных переходят в переменные из текстовых полей

Чис2 = Число2.Text

Рез = Чис1 + Чис2 'Обработка переменных для получения результата

Результат.Text = Рез 'Значение результата переходит из переменной в текстовое поле

End Sub

Эта схема, когда информация из текстовых полей (или других средств задания исходных данных) передается в переменные, затем обрабатывается, а затем из переменных передается обратно — в текстовые поля — весьма разумна и я рекомендую ей пользоваться.


Три совета

Дорогой читатель! Если вы сейчас сидите за компьютером, то вот вам три моих совета, по своей силе приближающихся к непререкаемым приказам:

1. Программы, которые вы видите в книге, вам необходимо вводить в компьютер и выполнять их, даже если они кажутся вам почти понятными, и даже если я явно этого не требую. В ряде случаев вы получите неожиданные результаты, из чего сделаете вывод, что программы эти вы поняли не до конца.

2. В каждой из этих программ экспериментируйте, то есть разными способами изменяйте в них то, что я как раз в этот момент объясняю. Например, если я объясняю оператор For i=1 То 5, пробуйте For i=1 То 10.

3. Выполняйте и сверяйте с ответом все задания. Это, конечно, главный совет из трех. Учтите, что сверенная с ответом правильно работающая программа — ваша победа, сверенная с ответом неправильно работающая программа — временное поражение, отказ от сверки — разгром.

Если вы пожалеете времени и пренебрежете этими советами, то через несколько страниц можете обнаружить трудности в понимании материала и вскоре не сможете правильно составить большинство программ.

Порядок создания простого вычислительного проекта

Все, что здесь сказано, полезно не только для вычислительных, но и для всех других проектов.

Задача: Даны размеры спичечной коробки. Вычислить площадь основания коробки, ее объем и полную площадь поверхности.

Порядок создания проекта:

1. Программист сам должен знать решение задачи. Ведь программа — это инструкция по ее решению. Нельзя давать инструкцию, не зная, как решать.

В нашем случае программист должен знать формулы для вычисления всего, что нужно:

площадь основания = ширина х толщину

объем = площадь основания х высоту

периметр основания = две ширины + две толщины

площадь боковой поверхности = периметр основания х высоту

полная площадь поверхности = две площади основания + площадь боковой поверхности

Как видите, я для стройности вычислений ввел периметр основания и площадь боковой поверхности.

2. Нужно придумать имена переменным. Имя переменной должно говорить о ее смысле. Если смыслом является ширина коробки, то не ленитесь и не называйте ее а, потому что через полгода, разбираясь в своей полузабытой программе, вы будете долго тереть лоб и думать — Что, черт возьми, я обозначил через а? Называйте ее Ширина (если вы не знаете английского) или, к примеру, Width (если знаете). Так делают все профессиональные программисты (а они, как известно, терпеть не могут трудиться зря, значит, зачем-то это им нужно).

Удовлетворимся такими именами:

Ширина — ширина

Толщина — толщина

Высота — высота

S_основ — площадь основания

V — объем

Периметр — периметр основания

S_бок — площадь боковой поверхности

3_полн — полная площадь поверхности

3. Нужно определить, какого типа будут переменные. Поскольку нам заранее неизвестно, будут ли исходные данные целыми, объявляем все переменные Double. Первые строки программы будут такими:

'Задача вычисления площади основания, объема и полной площади поверхности

'спичечной коробки по известным ее размерам

'Объявляем переменные величины

Dim Ширина As Double 'ширина

Dim Толщина As Double 'толщина

Dim Высота As Double 'высота

Dim S_основ As Double 'площадь основания

Dim V As Double 'объем

Dim Периметр As Double 'периметр основания

Dim S_бок As Double 'площадь боковой поверхности

Dim S_полн As Double 'полная площадь поверхности

4. Перед вычислениями нужно задать исходные данные решения задачи. Для это го нужно решить, каким способом пользователь будет задавать размеры коробки — при помощи текстовых полей, функции InputBox (0) или как-то по-другому. Выберем InputBox.

Вот следующие строки программы:

Private Sub Command1_Click()

'Ввод исходных данных

Ширина = InputBox("Введите ширину коробки")

Толщина = InputBox("Введите толщину коробки")

Высота = InputBox("Введите высоту коробки")

5. Теперь нужно задать компьютеру действия, которые он должен проделать с исходными данными, чтобы получить результат.

'Вычисление результатов

S_ocнов = Ширина * Толщина

V = S_основ * Высота

Периметр = 2 * Ширина + 2 * Толщина

S_бок = Периметр * Высота

S полн = 2 * S основ + S бок

6. После получения результатов их нужно показать человеку. Действительно, все операторы присваивания компьютер выполняет "в уме". После их выполнения в ячейках памяти будут находиться числовые результаты решения задачи. Чтобы их увидеть, человек может использовать текстовые поля, как это мы только что сделали, улучшая калькулятор. В 0 описывается, как выводить информацию в текстовое поле. Однако, я использую новый для нас оператор Print, который в нашем случае будет печатать результат прямо на поверхности формы (в отличие от Debug.Print, который печатает в окне Immediate):

'Отображение результатов

Print "Площадь основания ="; S_ocнов

Print "Объем ="; V

Print "Полная площадь поверхности ="; S_полн

End Sub

Обратите внимание, что здесь в первом операторе Print — два элемента печати, разделенные точкой с запятой: текстовое пояснение "Площадь основания =" и собственно переменная, значение которой мы хотим увидеть — S_основ. То же самое и в других операторах Print. То же самое можно делать и в Debug.Print.

Запустите проект и убедитесь в его работоспособности. Вы спросите — зачем было так долго трудиться для решения такой простой задачи? Действительно, для простых исходных данных эту задачу быстрее решить в уме. Однако, соблюдение приведенного мной порядка составления программы облегчит вам в дальнейшем программирование реальных задач для компьютера. Этот порядок — начинаем со ввода исходных данных, затем преобразовываем их в переменные величины, затем, обрабатывая переменные величины, получаем результат, затем преобразовываем результат из переменных величин в нечто видимое — общепринят.

Замечание. Попробуйте в режиме работы потаскать форму по экрану, нечаянно затащив часть ее напечатанных результатов за пределы экрана. Вы видите, что эта часть результатов стерлась. Чтобы такого не происходило, в режиме проектирования установите свойству AutoRedraw формы значение True.


Задания 11–13: Написать с использованием переменных программы для решения следующих задач:

Автомобиль 3 часа ехал со скоростью 80 км/час и 2 часа со скоростью 90 км/час. Вычислить среднюю скорость автомобиля (она равна суммарному пути, деленному на суммарное время). Значения переменным задать операторами присваивания, результат напечатать оператором Debug.Print с пояснениями.

В самом углу прямоугольного двора стоит прямоугольный дом. Подсчитать площадь дома, свободную площадь двора и длину забора. Примечание: в углу, где дом, забора, естественно, нет. Размеры дома и двора вводим при помощи InputBox, результаты отображаем в текстовых полях. Все числа целые.

Ввести из текстового поля радиус окружности. Вычислить длину окружности и площадь круга. Результаты с пояснениями печатать с 5 знаками после десятичной точки с помощью оператора Print.


Строковые переменные

Строковые переменные очень важны. Без них, например, невозможен разговор с компьютером. Да и вообще, значительная часть информации, с которой работает компьютер, текстовая (то есть строковая).

Создайте двухкнопочный проект с такой программой:

Dim a As Integer

Dim b As String

_____________

Private Sub Command1_Click()

a = 98

Debug.Print a

End Sub

_____________

Private Sub Command2_Click()

b = "Привет всем!"

Debug.Print b

End Sub

Сравним две процедуры.

Объявление Dim a As Integer говорит о том, что переменная а обязана иметь числовое значение, и поэтому в первой процедуре оператор а=98 записывает в ячейку а число 98.

Объявление Dim b As String говорит о том, что переменная b обязана иметь строковое (текстовое) значение, то есть ее значением будет не число, а произвольная цепочка символов, например, Привет всем! или рпН2Н(*fD6:u. Поэтому во второй процедуре оператор b ="Привет всем!" записывает в ячейку b строку Привет всем!. Оператор Debug.Print b, поскольку он обязан всегда выводить на экран содержимое ячейки Ь, выведет на экран текст Привет всем!

Обратите внимание, что в программе текст должен браться в двойные кавычки, а в памяти он хранится без кавычек и на экран выводится без кавычек.

Информация в ячейке памяти под строковую переменную может в процессе выполнения программы меняться точно так же, как и в ячейке для числовой переменной. Например, при выполнении фрагмента

а="Минуточку!": Debug.Print а: а="3дравствуйте!": а="До свидания!":

Debug.Print а

в ячейке а будут по очереди появляться строки

Минуточку! Здравствуйте! До свидания!

а на экран будут выведены строки:

Минуточку!

До свидания!

Еще пример:

а="Цикл": Debug.Print а: а=а+а: Debug.Print а+а+а +"Конец цикла"

Поскольку знак + по отношению к строкам есть знак соединения, то а+а будет равняться "ЦиклЦикл" и это же — новое значение а. Поэтому здесь на экран будут выведены строки:

Цикл

ЦиклЦиклЦиклЦиклЦиклЦиклКонец цикла

Выражения а+а и а+а+а +"Конец цикла" в последнем примере являются ни чем иным, как строковыми выражениями, по той простой причине, что в них производятся действия, результатом которых является строка.

Строковую переменную можно задавать не только оператором присваивания, но и функцией InputBox. При вводе ставить кавычки тоже не надо. Пример:

Dim a As String

Private Sub Command1_Click()

a = InputBox("Введите какое-нибудь слово")

Debug.Print "Вы ввели слово"; а

End Sub

Обратите внимание на пробел перед второй кавычкой в операторе Debug.Print.

Он нужен для того, чтобы слова при выводе не сливались.

Прежде, чем идти дальше, нужно, конечно, разобраться с хитросплетениями запятых, точек с запятыми, кавычек и пробелов в операторе Print:

Как выводить информацию оператором Print

Будем пробовать, вы тоже пробуйте:



Ага, значит, оператор распечатывает список элементов, разделенных точками с запятой или запятыми. Причем, если перед элементом стоит точка с запятой, он печатается почти вплотную к предыдущему, а если запятая, то подальше, выравниваясь по столбцам. Проверим фрагмент из трех операторов:



Еще:



Что такое элемент? Мы видели, что это может быть число. А еще что? Выражение. Проверим:



В последнем операторе — два элемента.

До сих пор мы печатали только числовые переменные и выражения. Но элемент может быть и строкой:



Как видите, строку мы обязаны брать в двойные кавычки.



Как видите, если между строками стоит точка с запятой, они печатается вплотную друг к другу. Числа же в этом случае все-таки разделяются пробелами.

Как все же отодвинуть собаку от кошки на пару пробелов? Очень просто — поставьте эти два пробела внутри "собачьих" кавычек перед буквой С:



А можно внутри "кошачьих" после буквы а.

Visual Basic не обращает внимания, что написано внутри кавычек, и ничего там не вычисляет. Он просто копирует это на экран, включая пробелы, цифры, знаки арифметических действий и любую ерунду:



Элемент может быть строковой переменной или выражением:



Итак, элемент оператора Print может быть числом, числовой переменной и числовым выражением, а также строкой, строковой переменной и строковым выражением. Есть и другие типы, о них мы пока не говорим.

Вообще, в будущем, объясняя какой-нибудь новый оператор, я часто буду для простоты ограничиваться коротенькими примерами его записи, например, Print 66 или Print "Кошка". Вы должны знать, что почти везде на месте числа может стоять числовая переменная или арифметическое выражение, а на месте строки — строковая переменная или строковое выражение. И вообще, вместо константы данного типа может стоять переменная или выражение этого типа.

Обычно в операторе Print используют вперемешку строковые и числовые данные. Пусть вес поросенка хранится в памяти, в переменной Ves. Тогда распечатать его можно таким оператором:



Здесь вы видите три элемента, разделенные точками с запятой.

Пусть название месяца года хранится в памяти, в переменной Mes. Пусть вы хотите напечатать, что именно этот месяц у вас отпускной. Распечатать это можно таким оператором:



Обратили внимание на пробелы внутри кавычек? Если бы их не было, было вот что:



Мы привыкли, что каждый следующий оператор Print печатает с новой строки. Если в конце оператора Print поставить запятую или точку с запятой, то следующий оператор Print будет продолжать печатать в той же строке, а если не поставить — то начнет со следующей. Проверим фрагмент из четырех операторов:



Проверьте этот пример, запустив его один раз, затем еще раз. Объясните увиденное.

Все, что здесь было сказано, относится и к оператору Debug.Print.

То, что печатать, указывается в самом операторе Print, а вот как печатать и с какого места, зависит от свойств объекта, на котором ведется печать (в нашем случае объект — форма):



Если вы установите в окне свойств формы свойство FontTransparent равным False, то через пространство между буквами не будет просвечивать поверхность формы.

У оператора Print есть еще кое-какие возможности, но, пожалуй, хватит.


Диалог с компьютером

Напишем программу, которая осуществляла бы такой диалог человека с компьютером:

КОМПЬЮТЕР ВЫВОДИТ НА ЭКРАН: Здравствуй, я компьютер, а тебя как зовут?

ЧЕЛОВЕК ВВОДИТ С КЛАВИАТУРЫ: Коля

КОМПЬЮТЕР ВЫВОДИТ НА ЭКРАН: Очень приятно, Коля. Сколько тебе лет?

ЧЕЛОВЕК ВВОДИТ С КЛАВИАТУРЫ: 16

КОМПЬЮТЕР ВЫВОДИТ НА ЭКРАН: Ого! Целых 16 лет! Ты уже совсем взрослый!

Пусть человек вводит свои реплики при помощи InputBox, а компьютер печатает свои с помощью Print. Для хранения в памяти имени человека выдумаем переменную imya, а для возраста — vozrast.

Вот программа:

Dim imya As String

Dim vozrast As Integer

Private Sub Command1_Click()

Print "Здравствуй, я компьютер, а тебя как зовут?"

imya = InputBox("Жду ответа")

Print "Очень приятно, "; imya; ". Сколько тебе лет?"

vozrast = InputBox("Жду ответа")

Print "Ого! Целых"; vozrast; "лет! Ты уже совсем взрослый!"

End Sub

Вам понятно, зачем в операторе Print "Очень приятно, "; imya; ". Сколько тебе лет?" внутри кавычек нужны запятая и точка? Если нет, то попробуйте их убрать и посмотрите на результат.

Диалог будет отличаться только той информацией, которую вводит человек. Так, в другой раз по этой же программе будет осуществлен следующий диалог: КОМПЬЮТЕР: Здравствуй, я компьютер, а тебя как зовут?

ЧЕЛОВЕК: Фантомас!

КОМПЬЮТЕР: Очень приятно, Фантомас!. Сколько тебе лет?

ЧЕЛОВЕК: 100

КОМПЬЮТЕР: Ого! Целых 100 лет! Ты уже совсем взрослый!

Не подумайте, что эта программа очень умная. Она совершенно не анализирует, какую информацию человек ввел с клавиатуры. Поэтому с ней возможен и такой диалог:

КОМПЬЮТЕР: Здравствуй, я компьютер, а тебя как зовут?

ЧЕЛОВЕК: Сгинь с моих глаз!

КОМПЬЮТЕР: Очень приятно, Сгинь с моих глаз!. Сколько тебе лет?

ЧЕЛОВЕК: -2

КОМПЬЮТЕР: Ого! Целых -2 лет! Ты уже совсем взрослый!

Как выводить информацию в текстовое поле

Конечно, оператором присваивания:



Трудность в том, что в операторе присваивания правая часть не может состоять из нескольких элементов, как в операторе Print, это один-единственный элемент, который может быть числом, строкой, числовой или строковой переменной, числовым или строковым выражением, содержимым текстового поля.

Правая часть вычисляется и становится содержимым текстового поля.

Text1.Text="Кошка"+" Собака" (Кошка Собака)

Что же делать, если мы хотим вывести в текстовое поле сразу несколько элементов? Здесь мы должны выстроить их в один элемент. Сделаем же это знаком +. У нас получится одно выражение:

Text1.Text = "Месяц " + Mes + " для меня отпускной." (Месяц май для меня отпускной.)

А вот с примером о поросенке немного посложнее. Попробуем проделать то же самое:

Text1.Text = "Вес поросенка + Ves + "килограммов" (Ошибка "Type mismatch" — Несовпадение типов)

Дело вот в чем. Visual Basic присматривает за тем, чтобы программист не складывал "бочки и селедки". То есть, если складываешь, то уж складывай одни числа, или уж одни строки (как в задаче об отпускном месяце), а строки с числами складывать никак нельзя. Ведь "Вес поросенка =" и "килограммов" это строки, a Ves — это числовая переменная.

Но и здесь есть, конечно, выход. Помните, как в 0 при помощи Val мы приказали компьютеру считать текст числом (другими словами — преобразовали текст в число)? Совершенно аналогично здесь мы прикажем компьютеру считать число текстом (другими словами — преобразуем число в текст). И сделает это функция Str:

Text1.Text = "Вес поросенка =' Str(Ves) + " килограммов" (Вес поросенка = 35 килограммов)


Задание 14: Напишите программу для следующей задачи: Компьютер запрашивает названия двух планет, радиусы их орбит (в миллионах километров) и скорости движения по орбите (в миллионах километров в сутки). После этого он вычисляет продолжительность года на планетах и выдает результат в таком виде: Продолжительность года на планете Земля — 365 суток, а на планете Эоэлла — 12 суток. Результат — в двух вариантах: печать на форме оператором Print и вывод в текстовое поле.

Указание для тех, кто не знает физики и геометрии: Год равен времени одного оборота по орбите, а оно равно длине орбиты, деленной на скорость движения по орбите. Длина орбиты равна , где R — радиус орбиты.


Оглядимся вокруг

Ну вот, с переменными величинами мы разобрались. Узнали что-то. А научились ли мы в результате этого знания делать что-нибудь новенькое и интересное? Вроде, нет. Ничего особенно приятного, за исключением, может быть, диалога с компьютером. Нда-а-а… Зачем же все мучения?


Что такое выбор (ветвление)

У начинающего программиста интерес должен вызывать такой вопрос: как компьютер думает, как он принимает решения, как он выбирает, какое действие из нескольких возможных нужно выполнить в данный момент? Ведь пока компьютер выполнял все, что ему приказывали, не рассуждая. Попробую ответить.

Возьмем игру в воздушный бой. Предположим, самолет на экране летит на автопилоте. Это значит, он должен самостоятельно поддерживать высоту полета между 3000 м и 3200 м. Для этого ему достаточно периодически определять высоту, и если она меньше 3000, лететь вверх, а если больше 3200 — вниз. Естественно, этот выбор делает программа для игры в воздушный бой, сам по себе компьютер ничего выбрать не может. В программе заранее пишутся процедуры для полета вверх и для полета вниз, а выбор между ними делает специальная команда (оператор) выбора, имеющаяся в каждом языке программирования. Вот алгоритм выбора между полетом вверх и вниз:

Определи высоту.

Если высота < 3000, то выполняй процедуру ВВЕРХ.

Если высота > 3200, то выполняй процедуру ВНИЗ.

Продолжай полет.


Здесь команды 2,3 — команды выбора. В общем случае команда выбора содержит условие, от которого зависит, будет ли выполняться какая-нибудь команда или группа команд. Это условие может быть самым разным: нажата или нет любая клавиша, нажата или нет конкретная клавиша, был ли щелчок мышью над таким-то объектом, больше ли одно число другого, правда ли, что с клавиатуры введено такое-то слово и т. д. В нашем случае условие — это высота < 3000 или высота > 3200.

Напишем для примера примитивный алгоритм, позволяющий имитировать вежливое общение компьютера с человеком при включении компьютера:

Покажи на мониторе текст "Здравствуйте, я — компьютер, а вас как зовут?"

Жди ответа с клавиатуры.

Если на клавиатуре человек набрал "Петя" или "Вася", то покажи на мониторе текст "Рад встретиться со старым другом!", иначе покажи на мониторе текст "Рад познакомиться!"

Покажи на мониторе текст "Чем сегодня будем заниматься — программировать или играть?"

Жди ответа с клавиатуры.

Если……………………


Выбор называют ветвлением по аналогии с разветвляющимся деревом (когда мы забираемся на дерево, мы время от времени делаем выбор, по какой из нескольких веток забираться дальше).

Идею разветвления в программе я изложил. Как видите, команды ветвления довольно просты. Как же с помощью таких простых команд запрограммировать сложное поведение компьютера? Ответ вы найдете в материале этой главы. Добавлю только, что вся мыслительная деятельность во всех программах (в том числе и той, что выиграла в шахматы у Каспарова) осуществляется при помощи сложного набора таких вот простых команд ветвления (выбора).


Условный оператор If или как компьютер делает выбор

Теперь посмотрим, как писать разветвляющиеся программы на Visual Basic. Выучим сначала три английских слова:

If читается "иф" переводится "если"

Then читается "зэн" переводится "то"

Else читается "элз" переводится "иначе"

Теперь приведем пример записи нового для вас оператора:

If а=28 Then Print f Else k=44

Переводится он так:

ЕСЛИ а=28 ТО печатай f ИНАЧЕ присвой переменной к значение 44.

Другими словами, мы предлагаем компьютеру сначала подумать, правда ли, что а=28, и если правда, то выполнить оператор Print f, в противном случае выполнить оператор к=44. Таким образом, мы с вами впервые написали оператор,

при выполнении которого компьютер не просто выполняет, что приказано, а сначала думает и делает выбор (пока одного из двух).

Мы видим, что оператор If включает в себя другие операторы, которые выполняются или не выполняются в зависимости от какого-то условия. Тем не менее, вся эта запись считается одним оператором If. Чтобы привыкнуть к оператору If, рассмотрим пару задач.

Задача 1. Компьютер должен перемножить два числа — 167 и 121. Если их произведение превышает 2000, то компьютер должен напечатать текст ПРОИЗВЕДЕНИЕ БОЛЬШОЕ, иначе текст ПРОИЗВЕДЕНИЕ МАЛЕНЬКОЕ. После этого компьютер в любом случае должен напечатать само произведение.

Программа:

Dim a As Integer

Dim b As Integer

Dim у As Integer


Private Sub Form_Load()

a = 167

b = 121

Y = a * b

If Y > 20000 Then Debug.Print "ПРОИЗВЕДЕНИЕ БОЛЬШОЕ"

Else Debug.Print "ПРОИЗВЕДЕНИЕ МАЛЕНЬКОЕ"

Debug.Print у

End Sub

Пояснение: В процедуре 5 операторов, последний — Debug.Print у. Поскольку эти 5 операторов выполняются по порядку, то он выполнится обязательно.

Обязательно выполните эту программу в пошаговом режиме. Обратите внимание, что подсветка после If у > 20000 Then перескакивает на Debug.Print "ПРОИЗВЕДЕНИЕ БОЛЬШОЕ", а затем на Debug.Print у.

Теперь замените в программе а = 167 на а = 1 и снова выполните программу в пошаговом режиме. Обратите внимание, что теперь подсветка после If у > 20000 Then перескакивает на Debug.Print "ПРОИЗВЕДЕНИЕ МАЛЕНЬКОЕ", а затем уже на Debug.Print у.

Задача 2. В компьютер вводятся два произвольных положительных числа — длины сторон двух кубиков. Компьютер должен подсчитать объем одного кубика — большего по размеру.

Обозначим а1 — сторону одного кубика, а2 — сторону другого, bo1 — сторону большего кубика, V — объем кубика. Приведем три варианта программы:

ВАРИАНТ 1

Dim a1 As Double

Dim a2 As Double

Private Sub Command1 Click()

a1 = InputBox("Введите сторону одного кубика")

а2 = InputBox("Введите сторону другого кубика")

If a1 > а2 Then Debug. Print a1 * a1 * a1 Else Debug.Print a2 * a2 * a2

End Sub


ВАРИАНТ 2

Dim a1 As Double

Dim a2 As Double

Dim V As Double


Private Sub Command1 Click()

a1 = InputBox("Введите сторону одного кубика")

а2 = InputBox("Введите сторону другого кубика")

If a1 > а2 Then V = a1 * a1 * a1 Else V = a2 * a2 * a2

Debug.Print V

End Sub


ВАРИАНТ 3

Dim a1 As Double

Dim a2 As Double

Dim bo1 As Double


Private Sub Command1 Click()

a1 = InputBox("Введите сторону одного кубика")

а2 = InputBox("Введите сторону другого кубика")

If a1 > а2 Then bo1 = a1 Else bo1 = a2 Debug.Print bo1 * bo1 * bo1

End Sub

Каждый из вариантов должен быть вами понят. Если возникают трудности, то используйте пошаговый режим и следите за значениями переменных. Для каждого варианта пошаговый режим используйте два раза — когда первый кубик больше и когда второй кубик больше. Как видите, одна задача может решаться разными программами.


Итак, если паровая машина избавила человека от тяжелого физического труда, то оператор if избавил человека от тяжелого умственного труда, в нашем случае — от необходимости решать, какое из двух чисел больше другого.


Оператор If можно записывать и без части Else. Например, If s

Для примера рассмотрим простейшую задачу: В компьютер вводится слово. Компьютер должен просто распечатать его. Однако, если введенным словом будет "колхозник", то компьютер должен напечатать вместо него слово "фермер".

Вот как будет выглядеть наша программа-"цензор":

Dim Slovo As String

Private Sub Command1_Click()

Slovo = InputBox("Введите слово")

If Slovo = "колхозник" Then Slovo = "фермер"

Debug.Print Slovo

End Sub

До сих пор мы после Then и после Else писали только по одному оператору. А если нужно больше?

Задача: Если а не равно 4, выполнить операторы Ь=3 и Print Ь, а в противном случае — операторы Ь=0, а=Ь+5 и с=0.

Вот оператор, решающий эту задачу:

If а <> 4 Then b=3: Print b Else Ь=0: а=Ь+5: с=0

Как видите, после Then и Else можно писать по нескольку операторов, разделенных двоеточиями.


Правила записи однострочного оператора If

Любой оператор Visual Basic нужно записывать по определенным грамматическим правилам, в противном случае Visual Basic выдает сообщение об ошибке. У каждого человеческого языка есть своя грамматика, включающая в себя правила, по которым должны выстраиваться в цепочку слова и другие элементы языка, чтобы получилось правильное предложение. Совокупность этих правил образует часть грамматики, называемую синтаксисом. В языках программирования тоже есть предложения. Такими предложениями здесь являются операторы. Очевидно, у языков программирования тоже должен быть свой синтаксис, который описывает правила, по которым записываются операторы языка и из операторов составляется программа. После того, как человек запускает программу на выполнение, любая порядочная среда программирования прежде, чем действительно выполнять ее, сначала проверит, нет ли в ней синтаксических ошибок, и если есть, то программу выполнять не будет, а выдаст сообщение, указывающее человеку, в чем ошибка. А Visual Basic проверяет программу еще на стадии ввода кода.

У Visual Basic есть две формы оператора If: однострочная и многострочная.

Пока мы пользовались только однострочным If и поэтому приведем правило записи только для него. Приведем это правило в виде синтаксической схемы:

If условие Then операторы Else операторы

Как понимать эту схему? Ее следует понимать, как образец, шаблон записи оператора, указывающий порядок, в котором оператор записывается из отдельных слов. Слова, которые в схеме я записал жирными буквами, при записи оператора просто копируются. Вместо слов, которые в схеме записаны курсивом, нужно при записи оператора подставить то, что они означают. Поясним, что обозначают эти слова.

операторы ∙ любой оператор Visual Basic или группа операторов, разделенных двоеточиями

условие ∙ пока под условием будем понимать два арифметических или строковых выражения, соединенных знаком сравнения

знак сравнения ∙ знаков сравнения шесть: > больше; >= больше или равно; = равно; < меньше; <= меньше или равно; <> не равно

Пример:

If 5*а+4 <= a*b Then Print b Else a=b+5

Здесь

Print b — один оператор,

a=b+5 — другой оператор,

5*a+4 <= a*b — условие,

5*a+4 — одно выражение,

a*b — другое выражение,

<= — знак сравнения.

Вы уже видели, что однострочный оператор If можно записывать в краткой форме. Вот синтаксическая схема для этой формы:

If условие Then операторы

Таким образом, это уже вторая синтаксическая схема, касающаяся одного оператора. Удобно же весь синтаксис оператора иметь перед глазами в одной схеме. Соединим две схемы в одну. Вот эта схема:


Синтаксическая схема однострочного оператора If:

If условие Then операторы [Else операторы]

Квадратные скобки здесь означают, что их содержимое можно писать, а можно и не писать в операторе.

Полезное замечание: Вычисляя выражения, стоящие в условии оператора If, Visual Basic не записывает их значения в память. Например, после выполнения фрагмента — b=6: If b+1>0 Then s=20 — в ячейке Ь будет храниться 6, а не 7. То же относится и к выражениям из оператора Print. Например: Ь=6: Print Ь+1. И здесь тоже в ячейке Ь останется храниться 6, а не 7. И вообще, информация в ячейках памяти не меняется при вычислении выражений без присвоения.

Примеры работы оператора If:



Задания 15–17: Определить без компьютера, что будет напечатано при выполнении следующих фрагментов программ:

k=20: k=k+10: If k+10<>30 Then k=8 Else k=k-1

Print k

k=20: k=k+10: If k+10 = 30 Then k=8 Else k=k-1

Print k

р=1: If р>0 Then р=р+5

If р>6 Then р=р+1

Print р


Задания 18–20: В компьютер вводятся два числа. Если первое больше второго, то напечатать их сумму, иначе — произведение. После этого компьютер должен напечатать текст ЗАДАЧА РЕШЕНА.

В компьютер вводятся длины трех отрезков. Компьютер должен ответить на вопрос, правда ли, что первый отрезок достаточно мал, чтобы образовать с другими двумя отрезками треугольник.

Указание: Для этого его длина должна быть меньше суммы длин двух других отрезков.

Замечание: Пока не думайте о том, что слишком длинными могут быть второй или третий отрезки.

Дракон каждый год отращивает по три головы, но после того, как ему исполнится 100 лет — только по две. Сколько голов и глаз у дракона, которому N лет?


Если в выражения, входящие в условие оператора If, включить свойства объектов, то вы можете заставить компьютер работать с ними. Например, компьютеру нужно определить, правда ли, что форма красная. Делает это такая программа:

Private Sub Command1_Click()

If Form1.BackColor = vbRed Then MsgBox ("Правда") Else MsgBox ("Неправда")

End Sub


Задание 21: Если кнопка на форме слишком высоко, пусть при нажатии на нее она будет пониже на 200 твипов.


Случайные величины

Без случайных величин компьютер всегда бы, как робот, на одинаковые действия человека реагировал одинаково. Но тогда невозможны игры.

Запустите такую программу:

Private Sub Command1_Click()

р = Rnd Debug.Print p

End Sub

Вот результат: 0,7055475. Это случайное число из диапазона от 0 до 1. Вырабатывает это число функция Rnd.

Щелкнем несколько раз по кнопке. Получим серию случайных чисел:

0,7055475

0,533424

0,5795186

0,2895625

0,301948

Завершим работу программы и снова запустим. Получаем ту же серию:

0,7055475

0,533424

0,5795186

0,2895625

0,301948

Выходит, что числа хоть и случайные, но после каждого запуска одинаковые. Не очень-то, получается, случайные. Как сделать их разными от запуска к запуску? Добавим оператор Randomize:

Private Sub Command1_Click()

Randomize

p = Rnd

Debug.Print p

End Sub

Теперь числа и случайные и разные от запуска к запуску.

Как получить случайное число из диапазона от 0 до 20? Так — р = 20 * Rnd.

А из диапазона от 6 до 7? Так — р = 6 + Rnd. А из диапазона от 200 до 210? Так — р = 200 + 10 * Rnd.

Как получить случайное целое число из диапазона от 200 до 210? Так — р = Int(200 + 11 * Rnd). Подумайте, почему я написал 11, а не 10. Если не можете додуматься, запустите такой проект:

Private Sub Command1_Click()

t = 200 + 11 * Rnd

p = Int(t)

Debug.Print t, p

End Sub

Щелкайте по кнопке, наблюдая за значениями t и р, до тех пор, пока не поймете, в чем тут дело.


Задание 22: "Ловля кузнечика или измеритель шустрости". Создайте проект с большой формой и одной маленькой кнопкой. При нажатии на кнопку она должна прыгать в случайное место формы.

Щелкая по кнопке, старайтесь щелкать как можно чаще. Можете засечь, сколько раз вам удалось щелкнуть за 1 минуту. (В дальнейшем вы сможете научить компьютер, чтобы он сам засекал время и сам подсчитывал количество нажатий. Кстати, попробуйте опередить книгу и сами организуйте подсчет. В этом вам поможет оператор вида k=k+1.)

Указание: Чтобы кнопка прыгнула в случайное место формы, вам достаточно задать случайные значения двум свойствам кнопки — Left и Тор. При этом вы должны добиться, чтобы кнопка не "упрыгивала" с формы.

Подсказка: Вам могла бы понадобиться такая, например, случайная величина — Form1.Width * Rnd. Только имейте в виду, что размеры формы больше размеров ее рабочего пространства на размеры заголовка и бордюров. Поэтому указанную формулу надо немного подкорректировать в сторону уменьшения.


Задание 23: "Угадай число или экстрасенс ли вы". Это ваша первая простейшая игра с компьютером. Компьютер загадывает число — 0 или 1. Ваше дело — отгадать. А дело компьютера — сказать "Угадал" или "Не угадал". Некоторые экстрасенсы утверждают, что благодаря сверхчувственному контакту с компьютером они могут из 100 раз угадать 80.

Программа готова? Настройтесь на контакт! Пуск!

Указание: Здесь вам нужно получить целое число из диапазона от 0 до 1. Получается оно по той же методе, что и целое число из диапазона от 200 до 210.

Многострочный If

Вспомним недавнюю задачу: Если а не равно 4, выполнить операторы Ь=3 и Print b, а в противном случае — операторы Ь=0, а=Ь+5 и с=0. Вот одно

строчный оператор If, решающий эту задачу:

If а <> 4 Then b=3: Print b Else Ь=0: а=Ь+5: с=0

Однако, часто количество операторов после Then и Else бывает гораздо большим, да и сами эти операторы бывают гораздо более сложными и длинными. В этом случае строка становится неудобочитаемой, да и вообще не умещается на экране. Для таких случаев создан многострочный (или блочный) оператор If. Вот как решается наша задача с его помощью:

If а <> 4 Then

Ь=3

Print Ь

Else

Ь=0

а=Ь+5

с=0

End If

Конструкция End If означает просто, что в этом месте оператор If заканчивается.

Часть Else может и отсутствовать. Например,

If а <> 4 Then

Ь=3

Print Ь

End If

Самое замечательное в блочном If то, что здесь можно одно за другим проверять несколько условий. Проиллюстрирую на примерах.

Задача: В компьютер вводится целое число а.

Если а<0, то компьютер должен сказать "Число отрицательно".

Если а=0, то компьютер должен сказать "Вы ввели нуль".

Если а>100, то компьютер должен сказать "Число большое".

В остальных случаях компьютер ничего не должен говорить, а только вычислить и напечатать его квадрат.

В любом случае после всего этого компьютер должен сказать "До свидания".

Вот программа:

Private Sub Command1_Click()

а = InputBox("Введите число")

If а < 0 Then

MsgBox ("Число отрицательно")

Elself а = 0 Then

MsgBox ("Вы ввели нуль")

Elself а > 100 Then

MsgBox ("Число большое")

Else

Print а^2

End If

MsgBox ("До свидания!")

End Sub

Elself переводят так — "иначе если". Получается вот что: Если а < 0, то.. иначе если а = 0, то иначе если а > 100, то

Блочный If выполняется так: Сначала проверяется первое условие (а < 0). Если оно не выполняется, то Visual Basic переходит к проверке второго условия(а = 0) и так далее. Наткнувшись наконец на условие, которое выполняется, Visual Basic выполняет операторы, стоящие после его Then и на этом заканчивает работу, даже если ниже есть условия, которые тоже выполняются. Если не выполняется ни одно из условий, Visual Basic выполняет операторы, стоящие за Else.

Вот синтаксис многострочного оператора If:

If условие Then

операторы

операторы

………….

[Elself условие Then

операторы

операторы

…………]

………………….

[Else

операторы

операторы

…………]

End If

Частей Elself может быть сколько угодно или совсем не быть. Часть Else, если она есть, то одна и стоит последней.

Имейте в виду, что у вас нет права, экономя место по вертикали экрана, объединять строки многострочного оператора If, например, так:

If условие Then операторы Elself операторы

и я вам не советую (а часто вы и не сможете) переносить слова Then, Elself и другие со своего законного места, например, так:

If условие

Then операторы

Elself операторы


Задание 24: Компьютер спрашивает пользователя, как его зовут, а затем приветствует его в соответствии с именем: Колю — "Привет", Васю — "Здорово", Джона — "Hi", а остальных — "Здравствуйте". Для Васи, кроме этого, он красит форму в зеленый цвет.

Задание 25: Видоизменить диалог с компьютером, начатый ранее. Пусть компьютер, узнав возраст человека, дальнейшую беседу ведет по двум вариантам. Если возраст больше 17, то компьютер должен задать вопрос: "В каком институте ты учишься?" и получив ответ, глубокомысленно заметить "Хороший институт". Если же возраст меньше или равен 17, то соответственно — "В какой школе ты учишься?" и "Неплохая школа". После этого, каков бы ни был вариант, компьютер должен попрощаться: "До следующей встречи!".


Ступенчатая запись программы

Ступенчатая запись программы — это как правила хорошего тона — можно и не соблюдать, но посмотрят косо.

Возьмем бессмысленную программу и посмотрим, как она записана. Конкретнее — обратим внимание на то, на что не обращает внимания компьютер, а именно на отступы от левого края листа в записи каждой строки.

Private Sub Command1_Click()

а = InputBox("Введите число")

If а > 4 Then

b=3

Print b

Else

b=0

a=b+5

c=0

End If

b=5

MsgBox ("До свидания!")

End Sub

Строки начала и конца процедуры записаны без отступа. Мы видим, что процедура состоит из четырех операторов: а=, If, b= и MsgBox. Все они выполняются по порядку, один за другим, поэтому каждый из них записан с одинаковым отступом. Если оператор сложный, то есть включает в себя другие операторы (мы знаем пока один такой оператор — If), то составляющие его операторы записываются еще правее. Так, у нас операторы Ь=0, а=Ь+5 и с=0 входят в состав оператора If и должны выполняться по порядку один за другим, поэтому их отступ слева одинаков и больше, чем у If.

Сделано все это для удобства чтения программы, для того, чтобы глаз мог сразу же уловить структуру программы, а именно, из каких частей состоит как сама программа, так и каждый из элементов, ее составляющих. Впрочем, вам с первого взгляда может показаться, что такая запись, наоборот, неудобна для чтения. Однако, заметьте, что она принята во всем мире и глаза профессиональных программистов привыкли именно к ней. Настолько привыкли, что программа, записанная без соблюдения ступенчатого стиля, вызывает раздражение.

Конечно, допустимы и некоторые отклонения от ступенчатого стиля. Например, как я уже говорил, несколько коротких похожих операторов вполне можно записать в одну строку:

а=0: b=0: с=0: f=4

Этим мы экономим дефицитное место по вертикали экрана или листа бумаги.


Вложенные операторы If

Согласно синтаксической схеме оператора If, после Then и Else может стоять любой оператор Visual Basic, в том числе и If.

Решим задачу: В компьютер вводится число (пусть для конкретности это будет дальность какого-нибудь выстрела). Если оно находится в интервале от 28 до 30, то напечатать текст ПОПАЛ, иначе — НЕ ПОПАЛ.

Сначала составим алгоритм: Введи число. Если оно меньше 28, то печатай НЕ ПОПАЛ, в противном случае надо еще подумать. А о чем же думать? А вот о чем: Если число меньше 30, то печатай ПОПАЛ, иначе печатай НЕ ПОПАЛ.

А теперь по составленному алгоритму напишем программу:

Private Sub Command1_Click()

а = InputBox("Введите дальность выстрела")

If а < 28 Then

MsgBox ("НЕ ПОПАЛ")

Else

If а < 30 Then MsgBox ("ПОПАЛ") Else MsgBox ("HE ПОПАЛ")

End If

End Sub

Здесь оператор If a < 30 входит в состав оператора If а < 28. Говорят, что он вложен в него.

Эту же программу можно записать и без вложенного If:

Private Sub Command1_Click()

a = InputBox("Введите дальность выстрела")

If a < 28 Then

MsgBox ("HE ПОПАЛ")

Elself a < 30 Then

MsgBox ("ПОПАЛ")

Else

MsgBox ("HE ПОПАЛ")

End If

End Sub

Задание 26: В компьютер вводятся длины трех отрезков. Компьютер должен ответить на вопрос, правда ли, что эти отрезки могут образовать треугольник.

Указание: Для этого каждый отрезок должен быть меньше суммы длин двух других отрезков.


Логические операции

Применение вложенных If создает довольно громоздкую, трудную для понимания программу. Поэтому в Visual Basic есть возможность записывать многие программы короче и понятнее, используя вместо вложенных друг в друга If только один If. Для этого используются так называемые логические операции. Что это такое, разберем на примерах.

Задача "Разборчивая принцесса". В прихожей у принцессы — длинная очередь женихов. Принцессе нравятся только голубоглазые маленького роста. Устав принимать женихов и отбирать из них подходящих, принцесса вместо себя поставила компьютер, написав для него программу, которая говорит ВЫ МНЕ ПОДОЙДЕТЕ тем, у кого цвет глаз голубой и рост меньше 140 см. Остальным программа говорит ДО СВИДАНИЯ.

Вот эта программа:

Dim Tsvet As String 'Цвет

Dim Rost As Integer: 'Рост

Private Sub Command1_Click()

Tsvet = InputBox("Каков цвет ваших глаз?")

Rost = InputBox("Введите ваш рост в сантиметрах")

If Tsvet = "Голубой" And Rost < 140 Then Print "ВЫ МНЕ ПОДОЙДЕТЕ"

Else Print "ДО СВИДАНИЯ"

End Sub

Мы видим, что условие в операторе If уже не такое простое, как мы описывали раньше, а сложное, то есть состоящее из двух условий, соединенных знаком логической операции And (переводится "и"). Весь оператор If можно прочесть так — если цвет глаз голубой И рост меньше 140 сантиметров, то печатай ВЫ МНЕ ПОДОЙДЕТЕ, иначе печатай ДО СВИДАНИЯ.

Знак логической операции And, поставленный между двумя условиями, говорит о том, что должны выполняться сразу оба эти условия.

Поэтому наш оператор If ответит ДО СВИДАНИЯ и высоким голубоглазым, и высоким неголубоглазым, и маленьким неголубоглазым. И лишь маленьким голубоглазым он ответит ВЫ МНЕ ПОДОЙДЕТЕ. В общем, And — строгий знак.

Программа для задачи ПОПАЛ — НЕ ПОПАЛ при использовании логических операций Значительно упростится:

Private Sub Command1_Click()

а = InputBox("Введите дальность выстрела")

If а > 28 And а < 30 Then MsgBox ("ПОПАЛ") Else MsgBox ("НЕ ПОПАЛ")

End Sub


Задача "Неразборчивая принцесса". Неразборчивой принцессе нравятся все маленькие независимо от цвета глаз и все голубоглазые независимо от роста. Программа неразборчивой принцессы будет отличаться от программы разборчивой одним единственным знаком логической операции:

If Tsvet ="Голубой" Or Rost<140 'Если цвет голубой ИЛИ рост<140

Знак логической операции Or переводится "или".

Поставленный между двумя условиями, знак Or говорит о том, что достаточно, если будет выполняться хотя бы одно из них.

Поэтому теперь оператор If ответит ВЫ МНЕ ПОДОЙДЕТЕ и высоким голубоглазым и маленьким голубоглазым и маленьким неголубоглазым. И лишь высоким неголубоглазым он ответит ДО СВИДАНИЯ.

Знаками And и Or можно объединять сколько угодно условий. Например:

If а>2 Or x=b Or с<>1 Then k=99 Else k=33. Здесь выполнится оператор k=99, если верно хотя бы одно из трех условий, и лишь когда все три неверны, будет выполняться оператор к=33.

Кроме логических операций And и Or применяется еще логическая операция Not (переводится "НЕ"). Запись If Not a>b Then… переводится так — ЕСЛИ НЕПРАВДА, ЧТО а больше Ь, ТО…. Вот фрагмент:

а=2: b=3: If Not a>b Then k=1 Else k=0

Здесь выполнится оператор k=1, так как неправда, что 2>3.


Логические выражения

Выражения

а>Ь

а > 28 And а < 30

Tsvet ="Голубой" Or Rost<140

а>2 Or x=b Or с<>1

имеют ту общую черту, что про каждое из них можно сказать, верно оно или нет в каждый момент времени. Такие выражения называются логическими выражениями. Если логическое выражение верно, то говорят, что оно имеет значение True (Правда). Если логическое выражение неверно, то говорят, что оно имеет значение False (Ложь). Любое логическое выражение может стоять в качестве условия в операторе If.

Логические выражения могут быть сложными — содержать одновременно операции And, Or, Not. Например, такое: а>2 And Not b>3 Or s>8

Чтобы его понять, нужно знать порядок действий. В арифметике сначала выполняется умножение, потом сложение. В логических выражениях сначала выполняется Not, затем And, затем Or. Для облегчения понимания не возбраняется расставлять скобки:

(а>2 And (Not b>3)) Or s>8

Это выражение равносильно предыдущему.

Скобки можно расставлять и чтобы изменить порядок действий: а>2 And Not (b>3 Or s>8)


Примеры:



Задание 27: "Замысловатая принцесса". Определите, кто нравится принцессе, по фрагменту из ее программы:

If Tsvet ="Черный" And (Rost<180 Or Rost>184) Then Print "ВЫ МНЕ ПОДОЙДЕТЕ" Else Print "ДО СВИДАНИЯ"

Задание 28: Усложним нашу задачу про ПОПАЛ — НЕ ПОПАЛ: Человек вводит в компьютер число. Если оно находится в интервале от 28 до 30, то нужно напечатать текст ПОПАЛ, если оно больше или равно 30 — то ПЕРЕЛЕТ, если оно находится на отрезке от 0 до 28, то НЕДОЛЕТ, если число меньше нуля — НЕ БЕЙ ПО СВОИМ.

Задание 29: Человек вводит с клавиатуры строку, смысл которой — приветствие при встрече. Компьютер тоже должен ответить приветствием. Отвечать нужно в соответствии со следующей таблицей:



Оператор варианта Select Case

У авторов языков программирования есть похвальное стремление сделать язык попроще, попонятнее. Они с ужасом взирают на многочисленные "иначе если" и логические операции и стараются, где можно, от них избавиться. Возьмем, например, такую задачу: Компьютер спрашивает школьника, какую он получил отметку по физике, и реагирует на нее подходящим текстом. Вот программа без нововведений, использующая If:

Dim Otmetka As Integer

Private Sub Command1_Click()

Otmetka = InputBox("Какую отметку ты получил по физике?")

If Otmetka = 1 Or Otmetka = 2 Then

Print "Кошмар!"

Elself Otmetka = 3 Then

Print "Неважно"

Elself Otmetka = 4 Then

Print "Неплохо"

Elself Otmetka = 5 Then

Print "Молодец!"

Else

Print "Таких отметок не бывает"

End If

End Sub

Здесь может вызвать раздражение слишком часто встречающееся имя Otmetka, а также то, что и в такой простой задаче не обошлось без логических операций. Хорошо бы программу можно было писать попроще, например, так (по-русски): Выбери вариант отметки Вариант 1, 2

печатай "Кошмар!"

Вариант 3

печатай "Неважно"

Вариант 4

печатай "Неплохо"

Вариант 5

печатай "Молодец!"

Вариант остальное

печатай "Таких отметок не бывает"

Конец выбора

И такой оператор варианта был придуман и назван Select Case, что и означает в переводе ВЫБЕРИ ВАРИАНТ. Я просто-напросто переписываю русский вариант программы по-английски:

Dim Otmetka As Integer Private Sub Command1_Click()

Otmetka = InputBox("Какую отметку ты получил по физике?")

Select Case Otmetka

Case 1, 2

Print "Кошмар!"

Case 3

Print "Неважно"

Case 4

Print "Неплохо"

Case 5

Print "Молодец!"

Case Else

Print "Таких отметок

End Select

End Sub

Логика работы Select Case абсолютно такая же, как и у блочного If. В процессе исполнения оператора компьютер сравнивает значение переменной Otmetka по очереди со всеми значениями, перечисленными в вариантах. Наткнувшись на совпадающее значение, он выполняет операторы, стоящие в этом варианте. На этом исполнение оператора Select Case завершается. Если же совпадающего значения так и не нашлось, то выполняются операторы, стоящие в варианте Else (в нашей программе он полезен на тот случай, если ученик болен манией величия и вводит число 6).

Оператор Select Case предоставляет более широкие возможности, чем в только что рассмотренном примере. Проиллюстрируем их на другом примере:

Private Sub Command1_Click()

а = 3

Select Case a * a + 1

Case 8, 4 * a, 26

k = 0

Print k Print a

Case 7, 10, 84 To 90

k = 1

Print k

Case Is < 0, 2, 4, 12 To 18 + a, 44, 68, Is > 100 + a

k = 3

End Select

End Sub

Эта программа напечатает 1. Здесь мы видим несколько новых для нас элементов.

Во-первых, после слов Select Case стоит не переменная, а выражение, поэтому с перечисленными в вариантах значениями будет сравниваться число 10, полученное как 3*3+1. В качестве значений вариантов тоже могут быть выражения, как, например, у нас — 4 * а.

Во-вторых, здесь у нас в двух вариантах не по одному, а по нескольку выполняющихся операторов.

В-третьих — конструкция 84 То 90. Она обозначает то же, что и 84,85,86,87,88,89,90, и служит в нашем случае для сокращения записи.

В-четвертых — конструкция Is < 0. Слово Is служит заменителем выражения а*а+1 и тоже используется для сокращения. Таким образом, Select Case не только сравнивает значения на равенство, но и проверяет неравенства.

В-пятых, здесь отсутствует вариант Else. Это значит, что если бы в нашей программе мы вместо а=3 написали а=0, то оператор Select Case, не найдя совпадения, не выбрал бы ни один из своих вариантов и, не найдя также Else, завершил бы свою работу, так ничего и не сделав.


Чем платим за удобство Select Case по сравнению с If? Что может If такого, чего не может Select Case? Самое главное — условия в If могут быть совершенно произвольны, а в Select Case мы привязаны к а*а+1.


Вот синтаксис оператора Select Case:

Select Case проверяемое выражение

[Case значение, значение……

[операторы

операторы

…………….]]

[Case значение, значение……

[операторы операторы]]

………………………

[Case Else

[операторы

операторы

…………….]]

End Select


Здесь значение — это:

— выражение

— выражение То выражение

— знак сравнения выражение


Выражения могут быть не только числовые, но и строковые. Пример:

Private Sub Command1_Click() а = "Дом"

Select Case а

Case "Домик"

k = 3

Print a

Case "Дом"

k = 0

Print k

End Select

End Sub

Здесь будет напечатан 0.


Задание 30: Ученик вводит с клавиатуры букву русского алфавита. Компьютер должен сказать, какой звук обозначает это буква — гласный, согласный звонкий, согласный глухой или какой-нибудь другой (можно и НЕ ЗНАЮ).

Задание 31: Если у вас есть микрофон и вы можете записывать свой голос в файл, то попробуйте усовершенствовать ваш диалог с компьютером. Пусть компьютер подает вам реплики голосом. Для этого вам заранее придется записать на диск некоторое количество звуковых файлов с репликами компьютера и при помощи оператора Select Case выбирать между ними в зависимости от реплики человека с клавиатуры. Вы сразу же заметите, что компьютер поглупел, но зато стал изъясняться вслух.


Улучшаем калькулятор

Наш калькулятор не предохранен от попыток выполнения арифметических действий над текстом и от деления на ноль. Предохраним его от этого, а также научимся ставить пароль на проект.

Проверка ввода чисел в текстовое поле

Давайте запустим наш калькулятор в том же виде.

Dim Чис1 As Double 'Переменная, содержащая число из текстового поля Число1

Dim Чис2 As Double 'Переменная, содержащая число из текстового поля Число2

Dim Рез As Double 'Переменная-результат, предназначенный для текстового поля Результат

_____________

Private Sub Кл_сложения_Click()

Чис1 = Число1.Text 'Значения исходных данных переходят в переменные текстовых полей

Чис2 = Число2.Text

Рез = Чис1 + Чис2 'Обработка переменных для получения результата

Результат.Text = Рез 'Значения результата переходит из переменной в текстовое поле

End Sub

…………..

Попробуем ввести в верхнее текстовое поле вместо числа какую-нибудь ерунду, например, КУ-КУ. Щелкнем по кнопке сложения. Visual Basic выдает сообщение об ошибке "Туре mismatch" — несовпадение типов числовой переменной Чис1 и вводимой текстовой информации. Все верно.

Теперь подумаем — хорошо ли это, что Visual Basic реагирует на ваши неправильные действия собственными сообщениями об ошибке? Для вас, которые уже что-то умеют в программировании и делают калькулятор исключительно для собственного удовольствия, может быть и хорошо. Ну а представьте, что вы решили похвастаться калькулятором перед своей подругой, которая знакома с программированием только понаслышке, и она, работая на нем, допустила такую же ошибку? Что она подумает, увидев неожиданно возникшее окно с непонятными английскими словами? Вы думаете, она поймет, что это сообщение об ошибке? Скорее всего она подумает, что это сломался компьютер. И на какие кнопки, скажите на милость, ей нажимать? "Ну и гадость твой калькулятор!" — скажет она наконец и будет сто раз права.

Та же проблема стоит и перед всеми профессиональными программистами, которые создают свои продукты для использования людьми, не обязанными ничего знать о программировании. Программист обязан сделать так, чтобы на все неправильные действия пользователя реагировал не Visual Basic своими непонятными сообщениями, а сама программа, причем понятно, по-русски, и тут же давала возможность исправиться.

Для этого в Visual Basic должны быть средства. И они там есть. Что нам нужно сейчас? Нам нужно средство, которое определяло бы, число ли записано в текстовом окне или же все, что угодно, но только не число. Это функция IsNumeric. Ее аргумент может быть любого типа, в том числе и строкой. Функция анализирует строку и если видит, что она состоит из цифр, знака минус и запятой таким образом, что получается число (и больше ничего в строке нет), то функция получает значение True, что означает "Правда", в противном случае — False, что означает "Ложь". Проверим:

Оператор Debug.Print IsNumeric("КУ-КУ") печатает False.

Оператор Debug.Print IsNumeric("-67,3") печатает True.

Раз так, то функцию IsNumeric можно включать в логические выражения и использовать в качестве условия оператора If. Например,

If IsNumeric("-67,3") Then MsgBox ("Это число") Else MsgBox ("Это не число")

что означает: "Если -67,3 — число, то…" Поэтому же совсем не обязательно писать If IsNumeric ("-67,3") = True Then….


Алгоритм работы калькулятора с проверкой звучит примерно так: Если в текстовом поле Число1 введено число и в текстовом поле Число2 введено число, то делай все, что положено, иначе выдавай сообщение "Вводите только числа". Процедура сложения с учетом этого алгоритма будет выглядеть так:

Private Sub Кл_сложения_Сliск ()

If IsNumeric(Число1) And IsNumeric(Число2) Then

Чис1 = Число1.Text

Чис2 = Число2.Text

Результат.Text = Чис1 + Чис2

Else

MsgBox ("Вводите только числа")

End If

End Sub

Здесь я немного сэкономил на переменной Рез. Поскольку мы ее никак не обрабатываем, я обошелся без нее. Процедуры для остальных действий пишутся аналогично.


Запрет деления на ноль

Вторая ошибка, на которую реагирует Visual Basic, это деление на ноль. От нее мы избавимся, если запретим компьютеру делить на ноль, записав вместо оператора

Результат.Text = Чис1/Чис2

такой:

If Чис2 <> 0 Then Результат.Text = Чис1/Чис2 Else MsgBox ("На ноль делить нельзя")

Вот как будет выглядеть теперь процедура деления:

Private Sub Кл_деления_Click ()

If IsNumeric(Число1) And IsNumeric(Число2) Then

Чис1 = Число1.Text

Чис2 = Число2.Text

If Чис2 <> 0 Then Результат.Text = Чис1 / Чис2 Else MsgBox ("На ноль делить нельзя")

Else

MsgBox ("Вводите только числа")

End If

End Sub

Как видите, здесь в состав многострочного If входит однострочный.


Ставим пароль на калькулятор

Ваш калькулятор стал достаточно надежен и удобен. Теперь его не стыдно показать друзьям. Ну а защищаться от врагов будем паролем.

Наша задача — сделать так, чтобы при попытке запустить калькулятор на экране появлялось приглашение ввести пароль, известный только вам. При попытке ввода неправильного пароля, программа должна заканчивать свою работу.

Поскольку приглашение на ввод пароля должно появляться раньше всего остального, то программируем его в процедуре Form_Load, в самом начале. Предварительно объявим строковую переменную для хранения пароля и выдумаем сам пароль, например, "калям".

Dim Parol As String 'Переменная-пароль

Private Sub Form_Load()

Parol = InputBox("Введите пароль")

If Parol <> "калям" Then MsgBox ("Пароль неверный!"): End

End Sub

Новый для вас оператор End делает всего одну вещь — вызывает завершение программы.

Запустите проект и проверьте, как он работает.

То же самое можно было бы запрограммировать короче, без использования переменной:

Private Sub Form_Load()

If InputBox("Введите пароль") <> "калям" Then MsgBox ("Пароль неверный! "): End

End Sub

Вообще, переменные нужны, если нужна неоднократная обработка какой-то информации: складывать что-то, затем сравнивать это что-то с чем-то другим и т. д. В нашем же случае пароль нужен всего один раз, для сравнения, так что можно обойтись и без переменной.

Вы скажете: Кто угодно перед запуском моей программы посмотрит в ее текст и сразу же увидит пароль. Совершенно верно. Чтобы текст программы не был виден, преобразуйте проект в исполнимый файл, как мы это делали.

Сделаем так, чтобы в случае ввода пароля в текстовое поле там появлялись не буквы пароля, а звездочки. В этом случае никто из-за вашей спины не сможет пароль подсмотреть. Для этого достаточно до ввода пароля выполнить строку Text1.PasswordChar = "*"


Функция MsgBox

Ранее я вкратце описал, как пользоваться оператором MsgBox. Здесь я более подробно разберу действие функции MsgBox. Функция отличается от оператора тем, что она встречается в выражениях и в правой части оператора присваивания, и еще тем, что подобно переменной имеет значение. Например, возьмем оператор присваивания: у = MsgBox("Привет!")

При выполнении этого оператора мы увидим на экране точно такое же окно сообщения, как при выполнении оператора MsgBox("Привет!")



Но вдобавок к этому, после того, как мы нажмем на кнопку ОК, переменной у будет присвоено некое значение. Что это за значение и зачем оно нужно, мы сейчас выясним.

Задача: В текстовом поле Visual Basic для нашей пользы печатает, сколько будет дважды два. После чего, заботясь о нашем зрении, он выводит следующее окно сообщения — >



При нажатии на Yes шрифт увеличивается, при нажатии на No ничего не происходит.

Вот программа:

Private Sub Command1_Click()

Text1.Text = 2*2

у = MsgBox ("He мелковат ли шрифт?", vbQuestion + vbYesNo, "Забота о пользователе")

If у = vbYes Then Text1.FontSize = 20

End Sub

Пояснения: Здесь полужирным шрифтом я выделил новые для вас элементы. Константа vbQuestion означает приказ изменить внешний вид окна сообщения, конкретнее — изобразить в нем картинку со знаком вопроса. Константа vbYesNo означает приказ поместить в окне сообщения кнопки Yes и No. Знаком плюс эти константы соединены, так как имеют некие численные значения, о которых вам, впрочем, не обязательно задумываться. После нажатия на кнопку Yes функция MsgBox приобретает значение vbYes. После нажатия на кнопку No функция MsgBox приобретает значение vbNo. Поэтому фрагмент

If y = vbYes…

можно перевести так: "Если была нажата кнопка Yes…"


Вот константы для задания внешнего вида окна сообщения: VbCritical, vbQuestion, vbExclamation, vblnformation.

Вот константы для задания кнопок в окне сообщения: VbOKOnly, vbOKCancel, vbAbortRetrylgnore, vbYesNoCancel, vbYesNo, vbRetryCancel.

Вот константы для задания значения функции MsgBox после нажатия на кнопку: vbOK, vbCancel, vbAbort, vbRetry, vblgnore, vbYes, vbNo.

Поэкспериментируйте со внешним видом окна сообщения. Поведение окна сообщения определяется еще кое-какими константами, но мы на них не будем останавливаться.

Названия кнопок сами по себе не играют никакой роли, их действие полностью определяется кодом, который вы напишете в процедуре. Однако, в среде пользователей и программистов уже утвердились некоторые привычки, которые вам небесполезно знать:

ОК — просто принять сообщение к сведению, Cancel — отменить намечавшееся действие, Abort — прекратить неудавшуюся попытку (например, когда ваша процедура занимается распечаткой документа на принтере и приходит сообщение "Принтер не готов"), Retry — повторить неудавшуюся попытку, Ignore — проигнорировать предупреждение и продолжать, как ни в чем не бывало, Yes-No — ответить да или нет на вопрос, содержащийся в сообщении.


Циклические программы

Идею цикла я поясню на примере движения объектов по экрану. Возьмем игру в воздушный бой. Самолетик по экрану должен двигаться. Но в списках операторов большинства языков программирования, используемых профессиональными программистами для создания игр, нет команды движения. Здесь нужно задаться вопросом — а что такое движение? Рассмотрим иллюзию движения, возникающую на экране кинотеатра. Если вы держали в руках кинопленку фильма, изображающего, скажем, движение автомобиля, то должны были обратить внимание, что она состоит из множества неподвижных слайдов-кадров, на каждом следующем из которых автомобиль находится чуть-чуть в другом месте, чем на предыдущем. Показывая эти кадры один за другим с большой скоростью, мы создаем иллюзию движения автомобиля. Точно так же поступают с созданием иллюзии движения на экране компьютера. Запишем алгоритм движения самолетика по экрану слева направо:


Зададим в уме компьютера позицию самолетика в левой части экрана.

Нарисуем самолетик.

Сотрем его.

Изменим в уме компьютера позицию самолетика на миллиметр правее.

Перейдем к команде 2.


Каждая из приведенных команд алгоритма легко программируется на большинстве языков. Любой компьютер, выполнив очередную команду, автоматически переходит к выполнению следующей. Так, выполнив команду 2, компьютер всегда перейдет к выполнению команды 3, независимо от того, какую команду он выполнял перед командой 2. Однако, если мы захотим, то можем заставить компьютер изменить этот порядок, что мы и сделали в команде 5. Из-за нее компьютер выполняет команды в таком порядке: 1-2-3-4-5-2-3-4-5-2-3-… Таким образом, многократно выполняется последовательность команд 2-3-4-5. Такая многократно выполняемая последовательность называется циклом. Можно сказать, что цикл — это одно из средств заставить компьютер долго работать при помощи короткой программы.

В коротком промежутке времени после выполнения команды 2 самолетик будет появляться на экране и на команде 3 исчезать, но этого достаточно, чтобы человеческий глаз его заметил. Благодаря циклу самолетик будет мелькать каждый раз в новом месте, а поскольку смена "кадров" будет очень быстрой, нам будет казаться, что происходит плавное движение самолетика.

Не нужно думать, что циклы применяются лишь при движении. Они пронизывают все программирование.


Оператор перехода GoTo. Цикл. Метки

Посмотрим, как осуществить цикл в Visual Basic. Предположим, мы хотим, чтобы компьютер бесконечно повторял выполнение следующего фрагмента:

Debug.Print "Это";

Debug.Print "тело";

Debug.Print "цикла";

Debug.Print " ";

в результате чего в окне Immediate мы бы увидели:

Это тело цикла Это тело цикла Это тело цикла Это тело цикла….

Если бы операторы Visual Basic можно было писать по-русски, то для достижения нашей цели было бы естественно воспользоваться такой конструкцией:

метка m1: Debug.Print "Это";

Debug.Print "тело";

Debug.Print "цикла";

Debug.Print " ";

иди к оператору, помеченному меткой m1.

Здесь мы видим новый для нас "оператор" ИДИ, который выполняется после Debug.Print " " и единственная работа которого заключается в том, чтобы заставить компьютер перескочить к выполнению оператора Debug.Print "Это", помеченного меткой ml.

А вот как этот фрагмент выглядит реально на Visual Basic:

Private Sub Command1_Click()

m1: Debug.Print "Это";

Debug.Print "тело";

Debug.Print "цикла";

Debug.Print " ";

Go To ml

End Sub

Здесь GoTo — оператор безусловного перехода, переводится "иди к", m1 — метка.

Метка — это произвольное имя или произвольное не слишком большое целое положительное число. Оператор GoTo можно писать в любых местах процедуры и метку можно ставить перед любым оператором процедуры, заставляя компьютер таким образом перескакивать внутри процедуры откуда угодно куда угодно. Правда, в сложных процедурах и внутри сложных операторов эта свобода перескакивания существенно ограничивается, так что я не советую вам врываться снаружи внутрь вложенных операторов, а вот изнутри наружу — пожалуйста. Метка должна заканчиваться двоеточием (хотя, в случае метки-числа это не обязательно).

А теперь запустите эту программу в пошаговом режиме. Посмотрите, как заполняется окно Immediate. Чтобы оно заполнялось быстрее, нажмите клавишу F8 и не отпускайте.

Зацикливание. Если вы уже запустили эту программу обычным образом (не в пошаговом режиме), то через некоторое время перед вами должен встать жизненно важный вопрос — как же ее остановить? Вы обнаружите, что кнопки не отзываются на нажатие мыши, и вообще, программа никак не реагирует ни на мышку, ни на клавиши клавиатуры. Любопытно, что так поступает любая нормальная программа, выполняя операторы кода. Разница в том, что в нормальной программе исключены ситуации, когда код выполняется бесконечно или на протяжении слишком долгого времени. Если же вы допустили ошибку и в программе выполняется бесконечный цикл, то возникает как раз такая ситуация. Вы вечно будете смотреть на экран, по которому бесконечно бегут непонятные числа или слова или рисуются графические объекты, а возможно и ничего не происходит, экран пустой — все зависит от характера ошибки.

Для прерывания работы программы, в том числе и зациклившейся, существует комбинация клавиш Ctrl-Break. Имеется в виду, что, удерживая нажатой клавишу Ctrl, вы должны щелкнуть по клавише Break. Программа прерывает свою работу, но не заканчивает. Visual Basic переходит в режим прерывания. Оператор программы, на котором она была прервана, выделяется полосой желтого цвета. Если вы снова запустите программу, она продолжит работу с прерванного места. Кстати, продолжить можно и в пошаговом режиме. Чтобы начать сначала, необходимо завершить работу программы обычным образом.

Группа операторов, выполняющихся многократно, называется телом цикла. У нас это все операторы, начиная с Debug.Print "Это " и кончая GoTo m1.

Пример программы:

k = 6

а = 100

GoTo 8

а = а + k

k = 2 * k

Print а

8: а = а + 1

k = k + 10

Print k, а

Эта программа напечатает 16 101. Операторы выполняются в такой последовательности:

k=6

а=100

Go То 8

а=а+1

k=k+10

Print k, а

А операторы а=а+k, k=2*k, Print а выполнены не будут вообще, несмотря на то, что написаны. Цикла здесь нет.

Задание 32: Определить без компьютера, что будет печатать программа: n = 10

k = 0

Debug.Print "Считаем зайцев"

met5: Debug.Print n;

n = n + k

GoTo m1

n = n + 1

m1: Debug.Print "зайцев"

k = k + 1

GoTo met5

Debug.Print "Посчитали зайцев"

He можете определить — посмотрите в пошаговом режиме.

Задача: Бесконечно печатать 200 205 210 215 220 225

Программа:

Private Sub Command1_Click()

n = 200

m1: Debug.Print n

n = n + 5

GoTo m1

End Sub

Задания 33–35: Написать программы для выполнения следующих заданий:

Бесконечно печатать букву А: ААААААААААА

Бесконечно печатать 10000 9999 9998 9997 9996….

Бесконечно печатать 100 50 25 12.5…. с 8 десятичными знаками.

Движение объектов по экрану

Вам уже приходилось заставлять кнопки прыгать по экрану. Попробуем добиться плавного движения объекта. Создайте проект с большой формой и добавьте в него маленький элемент управления Image (изображение). Поместите его в левой части формы. Придайте ему картинку (свойство Picture). Лучше всего, пока вы еще не умеете работать с изображениями, в качестве картинки взять один из файлов значков, находящихся по адресу c: \Program Files\папка, посвященная Visual Basic\Graphics\Icons.

Напишем программу, которая двигала бы изображение плавно направо:

Dim х As Double

Private Sub Command1_Click()

x = Image1.Left 'Компьютер узнает, откуда начинать движение

m1: х = х + 1 'Компьютер увеличивает в уме горизонтальную координату на 1

Image1.Left = х 'Изображение встает на место, указанное гор. координатой

GoTo m1

End Sub

Если движение получилось слишком медленным, то прибавьте шаг — х = х + 2. Если слишком быстрым, то уменьшите — х = х + 0.3.

Не удивляйтесь, что вам не пришлось в цикле рисовать и стирать объект. Когда дело касается объекта, заботы о перерисовке берет на себя Visual Basic. А вот когда вы сами будете рисовать различные фигуры на форме и попытаетесь их двигать, тогда вам придется их и рисовать и стирать.

Задание 36: Заставьте изображение двигаться налево, вниз, вверх.

Пока мы никак не можем влиять на полученное движение. Только можем останавливать компьютер с клавиатуры. Как с помощью мышки или клавиатуры влиять на движение во время движения? Как хотя бы запрограммировать остановку в нужном месте?


Выход из цикла с помощью If

Итак, как нам запрограммировать завершение работы цикла? Для этого нужно

применить оператор GoTo внутри оператора If.

Задача: При помощи цикла напечатать:

Начало счета 3 5 7 9 11 13 15 329 331 333 Конец счета

Для удобства отладки изменим условие задачи — напечатать:

Начало счета 3 5 7 9 Конец счета

Вы уже достаточно опытны в программировании, чтобы догадаться, что программа для измененного условия будет копией программы для исходного, за исключением одного числа.

Вот 4 варианта программы. Первый — самый простой, а остальные нам понадобятся в дальнейшем. Все 4 варианта делают одно и то же, они очень похожи, но чем-то и отличаются. Вот в этом отличии вам и надо разобраться, иначе не будет понятен дальнейший материал.

Создайте проект с 4 кнопками и выполните в пошаговом режиме все 4 варианта (не обращая пока внимания на непонятные слова в заголовках таблиц, эти слова понадобятся чуть позже):



Вот в каком порядке выполняются операторы программы первого варианта:

Debug.Print "Начало счета" f=3 Debug.Print f {печатается 3}

f=f+2 {f становится равным 5} If f<=9 Then GoTo m Debug.Print f

{печ. 5} f=f+2 {f = 7} If f<=9 Then GoTo m Debug.Print f

{печ. 7} f=f+2 {f = 9} If f<=9 Then GoTo m Debug.Print f

{печ. 9} f=f+2 {f = 11} If f<=9 Then GoTo m

Debug.Print " Конец счета"

Здесь оператор GoTo m выполняется три раза. На четвертый раз условие f<=9 оказывается ложным и поэтому выполняется не GoTo m, а следующий за If оператор Debug.Print "Конец счета", то есть программа выходит из цикла и завершает свою работу.



Задача: Напечатать пары чисел — 1 1001 2 1002 3 1003… 100 1100.

Программа:

Private Sub Command1_Click()

f = 1

m: s = f + 1000

Debug.Print f; s

f = f + 1

If f <= 100 Then GoTo m

End Sub


Задания 37–41:

A. Напечатать 1 2 3 4… 99 100

Б. Напечатать 100 99… 3 2 1.

B. Напечатать 1 2 3 4… 99 100 99 … 3 2 1.

"Таблицы Брадиса" или "Таблицы логарифмов" (в те времена, когда не было калькуляторов, были такие напечатанные в виде брошюрок таблицы для школьников и студентов, по которым они могли быстро посмотреть численные значения квадратов, логарифмов и других математических функций). Вычислить и напечатать с 6 десятичными знаками квадраты чисел 0.000 0.001 0.002 0.003… 0.999 1.000.

Для х=2700, 900, 300, 100. и т. д. вычислять и печатать у=х/4+20 и z=2y+0.23 до тех пор, пока yz не станет меньше 1/х.

Пусть движущееся изображение через некоторое время остановится.

Изображение, пройдя немного слева направо, поворачивает вниз и, пройдя немного, через некоторое время останавливается


Операторы цикла Do

Циклы настолько широко применяются в программах, что у программистов давным-давно появилась потребность написать специальный оператор цикла, не использующий оператор GoTo. Последний неудобен хотя бы тем, что у программистов, пишущих большие программы, много времени и внимания уходит на поиск взглядом меток в тексте программы. К тому же GoTo нарушает стройную идеологию так называемого "структурного программирования", когда порядок действий задается не скачками из одной части программы в другую, а цепочкой вложенных друг в друга операторов. В общем, нынче широко использовать GoTo так же неприлично, как не объявлять переменные.

Операторы цикла в Visual Basic делятся на 2 вида: Do и For. Операторы вида Do встречаются в 5 вариантах:



Оператор Do… Loop

Попытаемся составить с использованием 0 варианта оператора Do программу решения задачи о печати чисел 3 5 7 9 из предыдущего параграфа. Для того, чтобы точно определить работу этого варианта оператора Do, приведем ее параллельно с измененным 1 вариантом программы решения этой задачи из того же параграфа. Объяснением любого оператора в правом столбце является оператор, стоящий в той же строчке в левом столбце.



Do можно перевести, как "Делай", а понимать следует просто как метку.

Loop можно перевести, как "Петля" или "Возврат назад", а понимать следует так: "Возвращайся к метке Do".

Порядок работы обеих программ совершенно одинаков, так что можно считать слово Do заменой метки m, а слово Loop считать заменой оператора GoTo m. Обе программы бесконечно печатают 3 5 7 9 11 Прерывается цикл только с клавиатуры. Толку в 0 варианте оператора Do мы видим мало (пока).

Синтаксис оператора Do… Loop:

Do

операторы

операторы

……..

Loop

Строки операторов между Do и Loop называются телом цикла.


Оператор Do… Loop While

Добавьте в ваш проект еще 4 кнопки и выполните в пошаговом режиме программы с вариантами оператора Do 1–4, которые я привел ниже. Вы увидите, что все 4 варианта делают одно и то же и они очень похожи. Вопрос о том, зачем нужно целых 4 похожих варианта, рассмотрим чуть позже. Уверяю, они все нужны.

Составим с использованием 1 варианта оператора Do программу решения задачи о печати чисел 3 5 7 9 из предыдущего параграфа. Для того, чтобы точно определить работу этого варианта оператора Do, приведем ее параллельно с 1 вариантом программы решения этой задачи из того же параграфа. Объяснением любого оператора в правом столбце является оператор, стоящий в той же строчке в левом столбце.



While переводится "Пока".

Значит, Loop While f <= 9 понимать следует так: "Возвращайся к метке Do, пока f <= 9".

Порядок работы обеих программ совершенно одинаков, так что можно считать слово Do заменой метки m, а конструкцию Loop While f <= 9 считать заменой оператора If f <= 9 Then GoTo m.

Синтаксис оператора Do…. Loop While:

Do

операторы

операторы

…………..

Loop While условие продолжения работы цикла


Оператор Do… Loop Until



Until переводится "До тех пор, пока".

Значит, Loop Until f > 9 понимать следует так: "Возвращайся к метке Do до

тех пор, пока не выполнится условие f > 9".

Синтаксис оператора Do… Loop Until:

Do

операторы

операторы

…………..

Loop Until условие завершения работы цикла


Оператор Do While… Loop



Do While f <= 9 понимать следует так: "Пока f <= 9 выполняй нижестоящие

операторы вплоть до Loop".

Синтаксис оператора Do While…. Loop:

Do While условие продолжения работы цикла операторы операторы

операторы

операторы

…………..

Loop


Оператор Do Until… Loop



Do Until f > 9 понимать следует так: "Выполняй нижестоящие операторы вплоть до Loop, до тех пор, пока не выполнится условие f > 9".

Синтаксис оператора Do Until…. Loop:

Do Until условие завершения работы цикла операторы операторы

операторы

операторы

…………..

Loop

Типичная ошибка начинающих — небрежное обращение со знаками сравнения. Многие не видят большой разницы в том, как записать — While f<=9 или While f<9, а затем, «недополучив» результат, удивляются, почему. И здесь лучшим средством для понимания является отладочный режим. Попробуйте ошибочный вариант программы с While f<9 выполнить в пошаговом режиме.

Задача: Компьютер предлагает человеку ввести слово, после чего распечатывает это слово, снабдив его восклицательным знаком. Затем снова предлагает ввести слово и так до тех пор, пока человек не введет слово "Хватит". Распечатав его с восклицательным знаком, компьютер отвечает "Хватит так хватит" и заканчивает работу.

Придумаем строковую переменную, в которую человек будет с клавиатуры вводить слово. Назовем ее Slovo. Выберем подходящий вариант оператора Do, это будет 2-й, и пишем программу:

Dim Slovo As String

Private Sub Command1_Click()

Do

Slovo = InputBox("Введите слово")

Debug.Print Slovo; "!"

Loop Until Slovo = "Хватит"

Debug.Print "Хватит так хватит"

End Sub

Задание 42: Усложним эту задачу. Пусть компьютер перед распечаткой каждого слова ставит его порядковый номер.

Задание 43–44: Выполнить с применением оператора Do задания 38 и 41 из предыдущего раздела.

Задание 45: Если камень бросить горизонтально со 100-метровой башни со скоростью v=20m/c, то его расстояние от башни по горизонтали s будет выражаться формулой s=vt, где t — время полета камня в секундах. Высота над землей h будет выражаться формулой h=100 — 9.81t2/2. Вычислять и печатать t, s и h для t = 0, 0.2, 0.4, 0.6 и так далее до тех пор, пока камень не упадет на землю.


Разница между вариантами операторов Do

Разницы две:

Между While и Until. Здесь соображения удобства. Что вам удобнее, указывать компьютеру, когда цикл нужно продолжать (f <= 9) или когда его нужно заканчивать (f > 9)?

В том, куда поставить условие — после Do или после Loop. В первом случае можно придумать такое условие, когда тело цикла не выполнится ни разу. Напри-

f = 3

Do Until f > 0

Debug.Print f;

f = f + 2

Loop

Во втором случае, каково бы ни было условие, тело цикла хотя бы раз, да выполнится.

Часто эти отличия для начинающих малосущественны, поэтому пока выбирайте оператор по вкусу.


Оператор Exit Do

Оператор Exit Do нужен для того, чтобы выходить из цикла не в начале тела цикла, не в конце, а в середине. Добавим его в тело цикла одного из вариантов программы:

Private Sub Command2_Click()

Debug.Print "Начало счета";

f = 3

Do

Debug.Print f;

Exit Do

f = f + 2

Loop While f <= 9

Debug.Print "Конец счета"

End Sub

Вот результат работы этой программы:

Начало счета 3 Конец счета

Толк от Exit Do будет тогда, когда его поместят внутрь оператора ветвления:

Private Sub Command1_Click()

Debug.Print "Начало счета";

f = 3

Do

Debug.Print f;

If f >= 9 Then Exit Do

f = f + 2

Loop

Debug.Print "Конец счета"

End Sub

Вот результат работы этой программы:

Начало счета 3 5 7 9 Конец счета Устаревший оператор цикла

Имеется оператор цикла While Wend, доставшийся от старых версий Бэйсика.

На тот случай, если вам придется запускать чьи-то старые программы, вот вам его синтаксис:

While условие продолжения работы цикла операторы операторы

операторы

операторы

…………..

Wend

А смысл — тот же, что и у Do While…. Loop


Оператор цикла For

Я говорил, что имеются две разновидности оператора For. Здесь я рассмотрю только одну.

Мы знаем, что выполняя программу печати чисел 3 5 7 9, оператор Do выполнил цикл 4 раза. Обычно, когда мы пишем операторы Do, нам совсем не интересно знать, сколько раз они выполнят цикл. Тем не менее, существует много задач, для решения которых цикл нужно выполнить именно определенное количество раз. В этом случае удобно использовать оператор цикла For.

Задача: 200 раз напечатать слово ФУТБОЛ.

Попробуем сначала решить задачу при помощи оператора GoTo. Начнем с такого фрагмента:

metka: Print "ФУТБОЛ"

GoTo metka

Но здесь цикл будет повторяться бесконечно, а нам нужно только 200 раз. Мы уже видели, что для выхода из цикла оператор GoTo нужно включить в состав оператора If. Кроме этого нужна переменная, меняющая свое значение от одного выполнения цикла к следующему. Придумаем этой величине какое-нибудь имя, скажем i. Проще всего задачу решает такая процедура:

Private Sub Command1_Click()

i = 1

metka: Debug.Print "ФУТБОЛ"

i = i + 1 'увеличение i на 1

If i <= 200 Then GoTo metka

End Sub

Здесь i вначале равно 1, но к каждому следующему выполнению цикла оно увеличивается на 1. В первый раз выполняя оператор If, компьютер проверяет условие 2<=200 и найдя его истинным, выполняет оператор GoTo metka. Во второй раз проверяется условие 3<=200 и т. д. В 199-й раз компьютер проверяет условие 200<=200 и найдя его истинным, выполняет оператор GoTo metka. В 200-й раз компьютер проверяет условие 201<=200 и найдя его ложным, выходит из цикла.

В нашем фрагменте "полезную" работу выполняет только одна строка из четырех — Print "ФУТБОЛ". Остальные три строки заняты тем, что обеспечивают выполнение "полезной" строки ровно 200 раз. Нам пришлось организовать специальную переменную i, значение которой в каждый момент выполнения программы говорит о том, в какой раз выполняется цикл. Переменная с таким свойством называется счетчиком циклов.

А теперь перепишем программу так, чтобы логика ее выполнения более менее соответствовала логике выполнения программы с оператором For, которую я привожу параллельно и поясняю немедленно.



Прогоните правый вариант программы в пошаговом режиме, заменив для удобства число 200 числом 5 и следя за значением переменной i.

Слово For переводится "для". Слово То переводится "до". Конструкция For i=1 То 200 понимается так: Для i, изменяющегося от 1 до 200, выполняй операторы, стоящие ниже вплоть до слова Next. Слово Next говорит о том, что надо увеличивать i на 1 и возвращаться к началу цикла. При первом выполнении цикла i будет равно 1, при втором — 2, и так далее. При последнем — 200. Переменная i называется переменной цикла,

В данном конкретном случае сами по себе значения i не важны, тот же результат мы бы получили и с оператором For i = 501 То 700

Задача: Распечатать пары чисел — 101 1000 102 990 103 980 104 970… 109 920 110 910

Здесь значения переменной цикла важны. Вот программа:

Private Sub Command1_Click()

For a = 101 To 110

Debug.Print a;

Debug.Print 1000 — 10 * (a — 101)

Next a

End Sub


До сих пор переменная цикла менялась с шагом 1. Шаг можно задавать любой и тогда оператор For очень удобно использовать вместо Do — программы получаются короче. Напишем, например, программу для вычисления таблиц Брадиса (задача 38 — напомню, что нужно печатать квадраты чисел от 0 до 1 с шагом 0.001):

Private Sub Command1_Click()

For a = 0 To 1.00001 Step 0.001

Debug.Print Format(a, "0.000"), Format(a * a, "0.000000")

Next a

End Sub

Здесь Step 0.001 означает "Шаг 0.001". Для более аккуратной печати я использовал форматирование. Почему вместо 1 я написал 1.00001, объяснено в ответе к задаче 38.

Если бы мы хотели посчитать таблицы Брадиса в обратном порядке — от 1 до 0, то оператор цикла нужно было бы записать так:

For а = 1 То 0 Step -0.001


Синтаксис оператора For:

For переменная = выражение1 То выражение2 [Step выражение3]

операторы

операторы

……….

Next [переменная]

Переменная здесь должна иметь числовой тип. После Next вы можете ее не писать, но в программах, где много For и Next, я рекомендую это делать для легкости чтения программы, чтобы вам удобней было разобраться, для какого For этот Next.

Пример записи: For j=a+b То 2*s Step k*10

Если шаг не указан, он считается равным 1, то есть переменная на каждом выполнении цикла увеличивается на 1. Если же мы хотим уменьшать ее на 1, нам придется явно указать Step -1.


Работа оператора For при положительном (или нулевом) шаге:

Прежде всего вычисляется выражение1, и переменной цикла (пусть это будет i) присваивается его значение. Затем вычисляется выражение2 и сравнивается с i. Если i > выражения2, то оператор For завершает свою работу, так ничего и не сделав. В противном случае выполняются операторы, стоящие между строками For и Next. После их выполнения значение i увеличивается на значение выражения3 (или при его отсутствии на 1) и снова сравнивается с выражением2. Если i > выражения2, то оператор For завершает свою работу, иначе снова выполняются операторы, снова i увеличивается и т. д.


Работа оператора For при отрицательном шаге:

Прежде всего вычисляется выражение1, и переменной цикла (пусть это будет i) присваивается его значение. Затем вычисляется выражение2 и сравнивается с i. Если i < выражения2, то оператор For завершает свою работу, так ничего и не сделав. В противном случае выполняются операторы, стоящие между строками For и Next. После их выполнения значение i уменьшается на значение модуля выраженияЗ и снова сравнивается с выражением2. Если i < выражения2, то оператор For завершает свою работу, иначе снова выполняются операторы, снова i уменьшается и т. д.


Оператор Exit For

Оператор Exit For — еще один способ выхода из цикла For. Применяется он совершенно аналогично оператору Exit Do, поэтому отсылаю вас туда.

Задание 46: Напечатать с помощью оператора For: Прямой счет: -5 -4 -3 -2 -1 0 1 2 3 4 5 Обратный счет: 5 4 3 2 1 0–1 -2 -3 Конец счета

Оглядимся вокруг

Итак, мы изучили три способа заставить компьютер многократно выполнять часть кода внутри процедуры:

Операторы Do… Loop

Операторы For

Устаревший оператор Goto

Существуют способы заставить многократно выполняться процедуру целиком, среди них:

Использование таймера.

Рекурсия.


Отладка программы

Мы уже добрались до программ, требующих для своей отладки более совершенных средств, чем простой пошаговый режим. Поговорим о них.

Типы ошибок. Сообщения об ошибках.

Сначала перечтите, пожалуйста, материал о сообщениях об ошибках.

Ошибки в программах делятся на те, которые Visual Basic замечает в процессе ввода программы, на те, что замечает в процессе выполнения программы, и на те, что не замечает и в принципе заметить не может.

К первым относятся все синтаксические погрешности. Например, если вы вместо строки Do Until а>0 введете Do Antil а>0 и попытаетесь перейти на следующую строку, Visual Basic выдаст сообщение об ошибке

Expected While or Until or end of statement

что означает

Ждал While или Until или конца строки

Visual Basic недостаточно умен, чтобы точно описать вам вашу ошибку, но он хотя бы говорит вам, что ему от вас нужно.

На стадии выполнения Visual Basic замечает такие ошибки, как Sqr(-25), то есть квадратный корень из -25. На нее он среагирует таким сообщением — >



что означает Неправильный вызов процедуры или неправильный параметр процедуры. В нашем случае это, конечно, недопустимое значение параметра (-25). Чтобы узнать, на какое место программы Visual Basic грешит, нажмите кнопку Debug. Visual Basic переходит в режим прерывания и подсвечивает ошибочную по его мнению строку.

К ошибкам, которые Visual Basic не обнаруживает, относятся смысловые ошибки. Так, если вы, желая увеличить число а на 1, вместо а=а+1 пишете а=а+2, то этого не заметит ни один язык в мире.


Отладка программы. Окна отладки. Режимы отладки.

Ранее я изложил пошаговый способ выполнения программы. Его вполне достаточно для отладки простейших программ. В более сложных случаях можно применять другие способы, с которыми мы сейчас познакомимся. Кстати, зачастую они и более удобны. Итак рассмотрим окна Locals, Watches, Quick Watch, Call Stack и новые способы использования окна Immediate.

На рисунке в окне кода вы видите некую процедуру Command1_Click в процессе отладки:



Выполнившись с начала до конца, эта процедура печатает в окне Immediate такую информацию:

Начало работы

20 3

18 4

16 5

14 6

12 7

10 8

Конец работы

Вообразим, что нас такая печать привела в недоумение, мы по своей бестолковости ожидали, что будет напечатано

Начало работы

20 3

18 4

Конец работы

Чтобы разобраться в случившемся, мы и затеяли отладку.

Окно Locals. Прежде всего при помощи View->Locals Window и View->Immediate Window мы вызвали на экран окна Locals и Immediate. Назначение окна Locals — показывать в режиме прерывания значения локальных переменных выполняемой процедуры. После этого клавишей F8 запустим пошаговый режим выполнения проекта, как это объяснялось ранее. После нескольких нажатий на F8 окна Locals и Immediate примут тот вид, что вы видите на рисунке. Value означает "значение". Правда, мы и без окна Locals в любой момент можем узнать значения а и Ь, просто поместив на них мышиный курсор. Однако применение окна Locals избавляет нас и от этих мизерных трудов. К тому же вы в окне можете видеть информацию о типе переменных. Щелкните по плюсику слева от Me. Форма расскажет вам о текущих значениях своих свойств.

Если вы, выполняя таким образом процедуру, перескочите на другую процедуру, то теперь в окне Locals будут видны именно ее локальные переменные. Если вам другие процедуры не интересны, то работайте в пошаговом режиме не клавишей F8, а комбинацией клавиш Shift-F8. При этом все другие процедуры будут проскакиваться мгновенно.

Точки прерывания (Breakpoints). Когда программа большая или циклов много, жать на F8 приходится слишком часто. Но ведь и нужды-то в этом нет. Обычно вам интересно останавливаться только на некоторых строках программы, мимо остальных можно и пролететь. Visual Basic позволяет вам задать такие строки — точки прерывания (Breakpoints). Щелкните по вертикальной серой полосе в левой части окна кода против строки, на которой хотите прерывать выполнение программы. На полосе появится черная точка и вся строка будет выделена черным (смотри рисунок).



Щелкните так же против всех нужных вам строк. Запускайте проект обычным образом (кнопка Start или клавиша F5). Дойдя до первой же точки прерывания, проект перейдет в режим прерывания. Продолжайте его работу клавишей F5. Проект будет останавливаться только на точках прерывания. Убираются точки прерывания так же, как и ставятся — щелчком мыши.

"Беги до курсора" — Run То Cursor. Это еще один способ остановки в нужной вам строке. Поставьте текстовый курсор в нужную строку и нажмите Ctrl-F8. Программа будет выполняться до тех пор, пока не наткнется на строку с курсором. А теперь поставьте курсор в другую строку и снова нажмите Ctrl-F8. Программа продолжит работу с того места, где остановилась, и будет выполняться до тех пор, пока не наткнется на строку с курсором. И так далее.

В процессе выполнения программы в режиме прерывания вы можете достаточно свободно переключаться между разными способами прерывания. Ставьте и убирайте точки прерывания, переставляйте курсор, нажимайте то F8, то Shift-F8, то Ctrl-F8, то F5. Visual Basic будет вас слушаться.

Описанные в этом разделе возможности отладки и некоторые другие приведены в меню Debug (отладка).

Окно Watches. Вообразим, что окно Locals не заставило нас поумнеть. Нам все кажется, что цикл должен был прерваться уже при значении Ь=5. К тому же, мы устали жать на F8. Хорошо бы программа исполнялась в своем обычном сверхбыстром режиме [run], но в тот момент, когда Ь станет равным 5, перешла в режим прерывания и остановилась, чтобы мы успели посмотреть, что там к чему в этот момент. Итак, нам нужен совсем другой способ остановки — не на заданном операторе, а при выполнении заданного условия. Для этого мы используем окно Watches. Вызовем его так: Debug—>Add Watch. Возникнет диалоговое окно Add Watch, в которое вы вводите логическое выражение Ь=5, которое по нашим расчетам поначалу равно False, но затем в какой-то момент выполнения вроде бы станет равным True. Вот этот самый момент мы и хотим, чтобы Visual Basic поймал и остановил программу. Для этого из трех возможных положении переключателя Watch Туре выбираем среднее. Если бы мы хотели просто присматривать за выражением, то выбрали бы верхнее. Нижнее положение приказывает прерваться при любом изменении значения выражения.



Нажмите ОК. А теперь давайте еще присмотрим за выражением Ь > а. Добавим его в окно Watches аналогично.

Запустите проект на выполнение в обычном режиме. После нажатия на кнопку Command1 процедура будет выполняться до тех пор, пока Ь не станет равным 5, после чего Visual Basic перейдет в режим прерывания и остановится. Этот момент вы и видите на первом из трех рисунков этого раздела. Все описанные мной окна содержат информацию именно на этот момент.

Окно Quick Watch. Кроме этих окон вы видите на рисунке еще одно окно — Quick Watch. Оно понадобилось вот для чего. Иногда в процессе работы в режиме прерывания вам может захотеться узнать, чему равно в настоящий момент значение того или иного выражения из процедуры, например а — 2. Вы можете включить это выражение в окно Watches, но быстрее поступить так: Выделите нужное выражение в окне кода, как это сделано на рисунке, затем Debug->Quick Watch. Окно появляется.

Окно Call Stack. Когда в программе содержится много взаимодействующих процедур, вам при отладке может быть совершенно необходимо разобраться в последовательности их выполнения. В этом случае вам поможет окно Call Stack, которое и покажет вам эту последовательность. Вызывается оно так: View->Call Stack.

Окно Immediate может применяться для следующих полезных вещей, о которых я раньше не говорил. Вы можете в режиме прерывания ввести в это окно текст и наблюдать следующие результаты:

Текст ∙ Смысл

∙ В окне печатается значение переменной а в данный момент

?backcolor ∙ В окне печатается численное значение цвета фона

?text1.Text ∙ В окне печатается содержимое текстового окна

a=44 ∙ Приказ изменить в данный момент по нашему желанию значение переменной а. Таким образом мы можем вмешиваться в ход выполнения программы, чего раньше не делали. Более того, в режиме прерывания вы можете в окне кода на ходу менять операторы программы, так что в начале своего выполнения программа может иметь один облик, а в конце — совсем другой.

form1.BackColor =255 ∙ Приказ изменить цвета фона. Результат вы сразу же обнаружите, посмотрев на форму.

Command1 Clic k ∙ Приказ выполнить процедуру

for i=1 to 10:?i: next ∙ Приказ выполнить оператор. В окне будут напечатаны числа от 1 до 10.


ТИПИЧНЫЕ МАЛЕНЬКИЕ ПРОГРАММЫ

Каждому программисту известны такие слова, как счетчик, сумматор, вложенные циклы и другие подобные понятия, составляющие элементарную технику программирования. Без них не обходится ни одна реальная программа, и если мы хотим идти дальше, то нам без них не обойтись. В этой главе я не буду вводить новых операторов, а покажу, как программировать типичные задачи, в том числе и те, что используют упомянутые понятия.


Вычислительная циклическая программа

Задача: Во дворце 40 залов. Известны длина, ширина и высота каждого зала. Вычислить площадь пола и объем каждого зала.

Сначала напишем фрагмент для одного зала:

Dlina = InputBox ("Введите длину") 'Начало фрагмента

Shirina = InputBox ("Введите ширину")

Visota = InputBox ("Введите высоту")

S = Dlina * Shirina 'Площадь пола

V = S * Visota 'Объем

Debug.Print "Площадь пола="; S, "Объем зала="; V 'Конец фрагмента

Для решения задачи этот фрагмент нужно выполнить 40 раз, для чего вполне естественно вложить его в оператор For:

Private Sub Command1_Click()

For i = 1 To 40

Dlina = InputBox("Введите длину") 'Начало фрагмента

Shirina = InputBox("Введите ширину")

Visota = InputBox("Введите высоту")

S = Dlina * Shirina 'Площадь пола

V = S * Visota 'Объем

Debug.Print "Площадь пола="; S, "Объем зала="; V 'Конец фрагмента

Next i

End Sub

Полужирным шрифтом я выделил новые по сравнению с предыдущим фрагментом строки.

Чтобы программа подходила для любого числа залов, нужно вместо

For i = 1 То 40

написать

N = InputBox("Сколько залов во дворце?")

For i = 1 То N


Задание 47: Даны стороны N кубиков. Вычислить объем каждого.

Роль ошибок

Пусть во дворце три зала размерами 20*15*4, 30*20*5 и 10*5*3. В этом случае, выполняя программу предыдущего параграфа, мы вводим N=3 и оператор For выполняет цикл три раза.

Мы знаем, что по ошибочной программе компьютер выдает ошибочные результаты. Например, если в нашей программе мы вместо V=S*visota напишем V=S+visota, то результаты будут такими:

Площадь пола=300 Объем зала=304

Площадь пола=600 Объем зала=605

Площадь пола=50 Объем зала=53

Если же случайно вместо For i=1 То N написать For i=2 То N то результаты будут такими:

Площадь пола=300 Объем зала=1200

Площадь пола=600 Объем зала=3000

На этом программа закончит работу и не спросит размеров третьего зала. Вам не кажется странным, что она посчитала 1 и 2 залы, а не 2 и 3? Если кажется, то учтите, что пользователь ничего не знает об ошибке в программе, а компьютер не говорит ему, размеры какого по счету зала ему нужно вводить.


Задания 48–49: Определите без компьютера, что напечатает компьютер, если строку For i=1 То N поместить на три строки ниже, а именно — перед строкой S = Dlina * Shirina поменять местами строки Debug.Print и Next

Если задания не получаются, введите программы в компьютер и используйте пошаговый режим.


Счетчики

Счетчик — это переменная величина, в которой вы что-нибудь подсчитываете. Для чего нужны счетчики? Ну хотя бы для того, чтобы подсчитать количество жизней главного персонажа в компьютерной игре.

Задача 1: В компьютер с клавиатуры вводятся числа. Компьютер после ввода каждого числа должен печатать, сколько среди них уже введено положительных.

Фрагмент, решающий задачу:

с=0 'Обнуляем счетчик

m: а = InputBox("Введите очередное число")

If а>0 Then с=с+1

Debug.Print "Из них положительных — ", с

GoTo m

Пояснения: Мы придумали переменную с, которую назвали счетчиком. Она у нас выполняет роль счетчика положительных чисел. Сердце счетчика — оператор с=с+1. Именно он в нужный момент увеличивает счетчик на 1. Но и без If а>0 Then тоже никак нельзя. Если бы его не было, то с подсчитывал бы все числа без разбору, то есть был бы обыкновенным счетчиком циклов. В нашем же фрагменте увеличение с на 1 выполняется не всегда, а лишь при положительном а.

Обязательно прокрутите программу в пошаговом режиме.

В сложных программах не забывайте обнулять счетчик перед входом в цикл, а не то он начнет считать вам не с нуля, а бог знает с чего. Как бы вам понравилось, если бы таксист в начале поездки не обнулил счетчик?

В нашем фрагменте значения счетчика печатаются при каждом выполнении цикла. Изменим задачу.


Задача 2: В компьютер вводится ровно 200 чисел. Компьютер должен подсчитать и один раз напечатать, сколько среди них положительных.

Программа:

Private Sub Command2_Click()

с = 0 'Обнуляем счетчик

For i = 1 То 200

а = InputBox("Введите очередное число")

If а > 0 Then с = с + 1

Next i

Debug.Print "Из них положительных с

End Sub

Пояснения: Путь рассуждений здесь тот же, что и в первой задаче. В результате применения оператора For тело цикла выполняется ровно 200 раз, благодаря чему счетчик с накапливает нужное значение. Оператор Debug.Print выполняется только один раз и печатает последнее накопленное значение, потому что в ячейке с будет находиться именно оно..


Задание 50: Что будет, если Вместо с=0 написать с=10.

Вместо с=с+1 написать с=с+2.

Строки Next и Debug.Print поменять местами.

Строки с=0 и For поменять местами.

Строки For и InputBox поменять местами.

А в следующей программе мы используем уже два счетчика. Изменим задачу. Задача 3: В компьютер вводится ровно 200 чисел. Компьютер должен подсчитать и один раз напечатать, сколько среди них положительных чисел и сколько нулей. Программа:

Private Sub Command3_Click()

с_полож = 0 'Обнуляем счетчик положительных чисел

с_нулей = 0 'Обнуляем счетчик нулей

For i = 1 То 200

а = InputBox("Введите очередное число")

If а > 0 Then с_полож = с_полож + 1

If а = 0 Then с_нулей = с_нулей + 1

Next i

Debug.Print "Из них положительных с_полож, "Нулей с_нулей

End Sub

Как узнать, насколько Лев Толстой любил слово "добро"? Для этого достаточно, используя с минимальными изменениями нижеприведенную программу, ввести в компьютер слово за словом его произведения.


Задача 4: В компьютер один за другим вводятся произвольные символы. Ввод заканчивается символом "/". Подсчитать, какой процент от общего числа введенных символов составляют символ "W" и символ":" по отдельности.

Здесь мы организуем три счетчика одновременно: cW — для подсчета букв W, cDv — для подсчета двоеточий, а также i — счетчик общего числа введенных символов, кроме "/".

Программа:

Private Sub Command4_Click()

Dim i As Integer, cW As Integer, cDv As Integer

Dim procent_W As Integer, procent_Dv As Integer

Dim simvol As String

i = 0: cW = 0: cDv = 0 'Обнуляем все три счетчика

Do

simvol = InputBox("Введи символ")

If simvol <> "/" Then i = i + 1 'Если это не /, то "посчитай" его

Select Case simvol

Case "W" 'Если это W, то

cW = cW + 1 'увеличь счетчик символов W

Case":" 'Если это:, то

cDv = cDv + 1 'увеличь счетчик символов:

Case "/" 'Если это /, то

Exit Do 'завершай работу цикла

End Select

Loop

procent_W = Round(100 * cW / i) 'Вычисляй процент символов W

procent_Dv = Round(100 * cDv / i) 'Вычисляй процент символов:

Debug.Print procent_W, procent_Dv

End Sub


Задание 51: В компьютер вводится N чисел. Подсчитать из них количество положительных, отрицательных и тех, что превышают число 10,

Задание 52: В компьютер вводятся пары целых чисел. Подсчитать, сколько среди них пар, дающих в сумме число 13. Подсчет закончить после ввода пары нулей.


Сумматоры

Сумматор — это переменная величина, в которой вы подсчитываете сумму чего-либо. Если вы поняли идею счетчика, то понять идею сумматора вам будет нетрудно. Посмотрим, как будет работать следующий фрагмент:

s=0 'Обнуляем сумматор. Это не менее важно, чем обнулить счетчик

m: а = InputBox("Введите очередное число")

s=s+a 'Увеличиваем сумматор

Debug.Print "Сумма="; s

GoTo m

В ячейке s накапливается сумма вводимых чисел а, поэтому назовем эту ячейку сумматором. Отличие сумматора от счетчика в том, что счетчик увеличивается на 1 оператором с=с+1, а сумматор — на суммируемое число оператором s=s+a.

Задача: В компьютер вводится N чисел. Вычислить и один раз напечатать их сумму.

Программа:

Private Sub Command2_Click()

N = InputBox("Сколько чисел будем складывать?")

s = 0

For i = 1 То N

а = InputBox("Введите очередное число")

s = s + а

Next i

Debug.Print "Сумма равна"; s

End Sub


Задание 53: Пусть N=2, a=5 и 3. Тогда по этой программе Visual Basic напечатает 8. Что он напечатает, если:

Вместо s=0 написать s=10.

Вместо s=s+a написать s=s+a+1.

Строки Next и Debug.Print поменять местами.

Строки s=0 и For поменять местами.

Строки For и InputBox поменять местами.

Строки s=s+a и Next поменять местами.

Вместо For i=1 То N написать For i=2 То N.


Задания 54–56: Написать программы для следующих задач:

Во дворце 40 залов. Известны длина и ширина каждого зала.

Вычислить площадь пола всего дворца.

Вычислить средний балл учеников вашего класса по физике.

Вычислить произведение N произвольных чисел. Подсказка: Несмотря на то, что произведение — не сумма, эта программа будет отличаться от программы суммирования всего двумя существенными символами (какими?), а структура обеих программ совершенно одинакова.


Вложение циклов в разветвления и наоборот

Реальная процедура на Visual Basic может представлять собой сложную мозаику из циклических и разветвляющихся частей, вложенных друг в друга. Мы уже видели, как в оператор цикла были вложены операторы ветвления. В свою очередь в них могут быть вложены операторы цикла, и так до бесконечности.

Для тренировки определите, что напечатает следующий фрагмент:

Private Sub Command1_Click()

For i = 1 To 5

a = 9

If i * i = a Then

For k = 5 To 8

Debug.Print k;

Else

Debug.Print 1997

End If

Next i

End Sub

Здесь внутрь For i = 1 To 5 вложен If i * i = a,a внутрь него вложен For к = 5 To 8.

Ответ:

1997

1997

5 6 7 8 1997

1997


Вложенные циклы

Вложенные циклы или цикл внутри цикла — весьма распространенная конструкция при программировании.

Поставим себе задачу — напечатать таблицу умножения. В следующем виде:



Начнем с малого — пусть нужно напечатать

1*1=1

Вот фрагмент программы:

Фрагмент 1

а=1

Ь=1

proizv = а * b

Print а, "*",Ь, "=",proizv

Здесь в операторе Print 5 элементов:

сомножитель а,

символ знака умножения "*",

сомножитель b,

символ "=",

значение произведения proizv


Усложним задачу. Попробуем заставить компьютер напечатать первую строку таблицы:



Замечаем, что здесь нам нужно решить 9 элементарных задач на вычисление произведения, первую из которых решает фрагмент 1. Все они очень похожи и различаются лишь значением второго сомножителя. Таким образом, для решения каждой из 9 задач подошел бы наш фрагмент 1, если бы в нем в операторе Ь=1 вместо единицы стояла нужная цифра. В данном случае идеально подходит оператор For:


Фрагмент 2

а = 1

For b = 1 То 10

proizv = а * Ь

Print а; "*"; Ь; proizv;

Next b

Прокрутите программу в пошаговом режиме.

Следующая ступень усложнения — последняя — напечатать не одну строку таблицы, а девять. Для этого фрагмент 2 должен быть выполнен 9 раз, каждый раз — с новым значением а. Чтобы этого достичь, "обнимем" фрагмент 2 оператором For точно так же, как мы обнимали фрагмент 1.

Фрагмент 3

For а = 1 То 10

For b = 1 То 10

proizv = а * Ь

Print а; "*"; Ь; "="; proizv;

Next b

Next a

Прокрутите программу в пошаговом режиме, для удобства заменив 9 на 4.

Печатается все, что надо, но в одну строчку. Добавим в нужное место пустой Print, чтобы после окончания очередной строки печать начиналась с новой:


Фрагмент 4

For а = 1 То 10

For b = 1 То 10

proizv = а * Ь

Print а; "*"; Ь; "="; proizv;

Next b

Print

Next a

Прокрутите программу в пошаговом режиме. Прочувствуйте то, что пустой Print мы поместили именно в нужное место, строчкой выше или ниже он все бы испортил.

Печатает фрагмент 4 плохо. Акуратных столбцов не получается. Мы не будем добиваться идеальной картинки. Просто поменяем точку с запятой в конце оператора Print на запятую, чтобы результаты были выровнены по столбцам. Столбцы расположены на расстоянии 14 символов друг от друга. Поменяем шрифт (свойство Font) формы на Courier, потому что у этого шрифта в отличие от многих других символы имеют одинаковую ширину.

В целом программа иллюстрирует идею вложенных циклов, когда один, внутренний, цикл вложен внутрь другого, внешнего. У нас тело внешнего цикла выполняется 10 раз, а тело внутреннего — 100 раз, так как на каждое выполнение внешнего цикла он выполняется 10 раз.


Задание 57: Распечатать все возможные сочетания из двух цифр — первая цифра может быть любой от 3 до 8, вторая — любой от 0 до 7. Например, 36, 44, 80.

Распечатать все возможные сочетания из четырех цифр, каждая из которых может принимать значения 1,2,3. Например, 2123, 3312, 1111.

Подсчитать количество таких сочетаний.

Подсчитать из них количество неубывающих сочетаний, то есть таких, где каждая следующая цифра не меньше предыдущей — 1123, 1223, 2222 и т. п., но не 3322. Распечатать все такие сочетания.


Поиск максимального из чисел

Задача программисту: Найти максимальное из вводимых в компьютер чисел. Задача рыбаку: Принести домой самую большую из выловленных рыб.

Решение рыбака: Рыбак приготовил для самой большой рыбы пустое ведро. Первую пойманную рыбу рыбак не глядя бросает в это ведро. Каждую следующую рыбу он сравнивает с той, что в ведре. Если она больше, то он бросает ее в ведро, а ту, что была там раньше, выпускает в реку.

Решение программиста: Программист приготовил для самого большого числа ячейку и придумал ей название, скажем, max. Первое число программист не глядя вводит в эту ячейку. Каждое следующее число (назовем его chislo) он сравнивает с шах. Если оно больше, то он присваивает переменной шах значение этого числа.

Напишем программу для определения максимального из 10 вводимых чисел:

Private Sub Command1_Click()

Max = InputBox("Введите число") 'первую рыбу — в ведро

For i =2 То 10 'ловим остальных рыб:

chislo = InputBox("Введите число") 'поймали очередную рыбу

If chislo > Max Then Max = chislo 'и если она больше той, что в ведре, бросаем ее в ведро

Next i

Debug.Print Max 'несем самую большую рыбу домой

End Sub

Задание 58: Найти из N чисел минимальное. Каким по порядку было введено минимальное число? Указание: для номера минимального числа тоже нужно отвести специальную ячейку.

Задание 59: У вас есть данные о росте ваших одноклассников. Правда ли, что рост самого высокого отличается от роста самого низкого больше, чем на 40 см.?


ГРАФИКА

Графикой у компьютерщиков принято называть все то, что связано с рисунками и изображениями.

Прежде чем рисовать, познакомимся с некоторыми новыми понятиями.


Объекты. Их свойства, их события, их методы

То, что у каждого объекта есть свойства, мы уже усвоили. Так, у формы Form1 есть свойство BackColor (цвет фона), а у метки Label8 есть свойство Caption (надпись). У кнопки Command2 тоже есть свойство Caption, но оно у ней свое. Принадлежность свойства указывается через точку — Label8.Caption, Command2.Caption, Text1.Width.

Что вы можете делать со свойствами объектов? Вы можете их устанавливать и менять вручную в режиме проектирования. Вы можете запрограммировать их автоматическое изменение в режиме работы.

Что касается событий, я как-то не акцентировал, кому они принадлежат. Создавалось впечатление, что они, вроде, сами по себе, не относятся ни к какому объекту. Нет же. Посмотрите на процедуры, написанные нами ранее. Кроме процедуры Command1_Click, мы встретились с такими процедурами, как Form_Load и Form_Terminate. Вы видите, что в заголовке процедуры справа от знака подчеркивания мы указываем событие, а слева — объект, к которому это событие относится. Таким образом, события принадлежат объектам и принадлежность события указывается через знак подчеркивания в заголовке процедуры.

Событий в Visual Basic огромное количество и многие из них мы изучим. Чтобы посмотреть, какие события могут случиться с таким-то объектом, нужно запустить так называемый Object Browser ("перелистыватель объектов" — его найдете в меню View) — >



В окне Object Browser в левом списке вы кроме всего прочего найдете названия всех элементов управления, находящихся в данный момент в Toolbox. Щелкните по интересующему вас объекту (я щелкнул по CommandButton) — в правом списке вы увидите свойства, события и так называемые методы данного объекта.

Свойства помечены значком в виде руки, что-то нажимающей на каком-то пульте (вы можете видеть на картинке свойство Caption). События помечены значком в виде зигзага молнии, методы помечены непонятным значком, по-моему это летящий кирпич. Щелкните по интересующему вас элементу правого списка (я щелкнул по событию Click) — в нижней части окна Object Browser появится краткое описание этого элемента.

Кстати, в Object Browser вы найдете много свойств, которых нет в знакомом вам окне свойств, потому что существуют свойства, которые нельзя задавать в режиме проектирования.

Что вы можете делать с событиями? Вы можете программировать в соответствующих процедурах реакцию компьютера на них, а в режиме работы вы можете многие из них вызывать мышкой или с клавиатуры.

Кроме свойств и событий у объектов есть так называемые методы. Метод — это кое-что из того, что умеет делать данный объект.

Для знакомства с методами Visual Basic выберем метод SetFocus. Чтобы его понять, сначала нужно узнать, что такое фокус. Создайте проект с двумя кнопками и двумя текстовыми полями. Запустите его. Щелкните по одной кнопке, по другой, по одному полю, по другому. Ничего, конечно, не происходит, но если последний раз вы щелкнули по кнопке, то она имеет несколько другой, чем раньше, "нажатый" вид. А если последний раз вы щелкнули по текстовому полю, то именно в нем мигает курсор. Таким образом, можно сказать, что из множества объектов на форме один какой-то выделяется, то есть находится в фокусе. Этим объектом оказывается как раз тот объект, которым вы пользовались последним. Говорят, что объект обладает фокусом.

У объектов, способных иметь фокус, имеется два события: GotFocus, которое возникает в момент приобретения объектом фокуса, и LostFocus, которое возникает в момент потери фокуса.

Запишите в окно кода такие процедуры:

Private Sub Text1_GotFocus()

Debug.Print "Text1 получил фокус"

End Sub


Private Sub Text2_GotFocus()

Debug.Print "Text2 получил фокус"

End Sub


Private Sub Text1_LostFocus()

Debug.Print "Text1 потерял фокус"

End Sub


Private Sub Text2_LostFocus()

Debug.Print "Text2 потерял фокус"

End Sub

Пощелкайте по текстовым полям. Понаблюдайте, что появляется при этом в окне Immediate и в какой последовательности.

Фокус можно переводить на объект и программным путем. Дополним наш проект двумя процедурами:

Private Sub Command1_Click()

Text1.SetFocus

End Sub


Private Sub Command2_Click()

Text2.SetFocus

End Sub

Запустите проект. Щелкните по кнопке Command1. Фокус, вопреки ожиданиям, переместился не на кнопку Command1, а в поле Text1. Произошло это благодаря оператору Text1.SetFocus, который можно перевести так — "Установи фокус в объект Text1". Щелкните по кнопке Command2. Фокус переместился в поле Text2. Метод SetFocus принадлежит объекту и отделяется от своего хозяина точкой. Дело его простое — переводить фокус на своего хозяина.

Не все объекты обладают методом SetFocus. Например, у метки его нет. Зачем Бэйсику нужен фокус, мы узнаем позже.

Мы раньше уже познакомились с одним методом — это Print. Объект, обладающий этим методом, печатает информацию на своей поверхности. Поместите в проект элемент управления PictureBox (с именем Picture1) и выполните оператор Picture1.Print "Hello!". Текст будет напечатан не на форме, а на самом объекте.

Если хозяина метода мы не указываем, то есть пишем просто Print, то по умолчанию считается, что хозяином является форма. То же относится и к свойствам. Например, оператор Width = 5000 устанавливает ширину именно формы, а не чего-нибудь другого.

Всё ли умеют делать методы, которые мы видим в Object Browser? Нет, далеко не всё, и даже мало что. Гораздо более богатые результаты мы достигаем, меняя свойства объектов или программируя реакцию на события, как все время делали раньше. Но вот когда мы научимся создавать собственные объекты, тогда мы будем писать для них методы сами, и уж тогда от нас самих будет зависеть, насколько богаты они будут.


Три способа рисовать

В Visual Basic есть три основных способа использовать графику:

Не входя в Visual Basic, в каком-нибудь графическом редакторе вы можете нарисовать то, что вам нужно, или найти на диске готовый файл с подходящим рисунком. Затем, войдя в Visual Basic, придать этот рисунок форме или другому объекту.

В Toolbox имеется два элемента управления: Line (Линия), имеющий вид отрезка прямой различного цвета, толщины и стиля, и Shape (Фигура), принимающий вид прямоугольников, окружностей и эллипсов тоже различного цвета, толщины и стиля. Если их на этапе проектирования поместить на форму и придать им нужные размеры и прочее, то можно получить, в общем, любую картинку по принципу "Точка, точка, огуречик, вот и вышел человечек".

Форма, элемент управления PictureBox и некоторые другие объекты обладают методами, работа которых заключается в том, чтобы рисовать на поверхности своего хозяина точки, отрезки, прямоугольники, окружности, эллипсы, дуги и сектора, в общем, все то, что достигалось предыдущим способом. Эти методы будем называть графическими. Основное отличие от предыдущего способа в том, что здесь все надо программировать, а там все делалось вручную. У каждого из этих способов есть и другие преимущества и недостатки, о чем позже.

Есть и другие, более продвинутые, сложные и громоздкие способы, но ими пользуются только тогда, когда цели нельзя достигнуть указанными тремя. Рассмотрим по очереди все три способа.


Первый способ — Загрузка в Visual Basic готовых изображений

Рассмотрим первый способ использования графики в Visual Basic.

Придать объекту картинку можно, установив его свойство Picture: в режиме проектирования — вручную, в режиме работы — использовав функцию LoadPicture. Например,

Form1.Picture = LoadPicture("С: \TEMP\Rockies.bmp")

Здесь в скобках в кавычках пишем адрес файла с картинкой на диске.

Если у вас в проекте несколько объектов, имеющих свойство Picture, то картинку можно мгновенно "скопировать" с одного объекта на другой так:

Image4.Picture = Form1.Picture

Если вы хотите удалить картинку с объекта:

в режиме проектирования вы должны буквально стереть значение свойства Picture из окна свойств.

в режиме работы вы должны написать оператор такого вида:

Form1.Picture = LoadPicture("")

Типы графических файлов

Visual Basic 6.0 поддерживает (воспринимает и работает с ними) графические файлы следующих типов:

Расширение файла ∙ Краткое описание

BMP, DIB ∙ Фотографии и любые другие растровые изображения.

ICO ∙ Значки (пиктограммы, иконки) — очень маленькие

CUR ∙ Значки курсоров — очень маленькие

WMF, EMF ∙ Метафайлы Windows — векторные изображения

GIF ∙ Растровые изображения, применяются в Интернете

JPG, JPEG ∙ Растровые изображения (часто пониженного качества, зато экономные), применяются в Интернете

Где взять все эти файлы? Многие из этих типов вы найдете в папке Graphics, находящейся в папке, посвященной Visual Basic. Многие — в папке Clipart из папки Microsoft Office. В папке Windows вы найдете большую картинку Облака.bmp. Красивые картинки типа JPG находятся по адресу C: \Program Files\Plus!\Themes. Если вы умеете в Windows запускать поиск файлов по расширениям, то поищите, что-нибудь обязательно найдете. Если у вас есть любимая фотография или картинка в журнале, попросите своего знакомого, у которого есть сканер, отсканировать ее и записать на вашу дискету. Дело пяти минут. На дискете при обычном сканировании уместятся 3–4 фотографии, а в формате JPG — 30–40. Ну а если у вас есть Интернет, то тут и говорить не о чем.


Регулировка размеров изображений

Рассмотрим, как размещаются и умещаются ли картинки в объектах нашего проекта.

Сначала испытаем форму. Загрузим в нее любой растровый файл и попробуем изменять размеры формы. Мы видим, что и в режиме проектирования и в режиме работы эти изменения никак не влияют на саму картинку — если форму совсем уменьшить, то мы будем видеть лишь часть картинки, если слишком увеличить — справа и снизу формы останутся пустые места. Сама картинка не увеличится и не уменьшится. А вот если загрузить векторную картинку, то она будет автоматически растягиваться и сжиматься по размерам формы.

А теперь испытаем элемент управления PictureBox. Он специально предназначен для размещения картинок. Проверьте и убедитесь, что по отношению к ним он ведет себя так же, как форма. Зачем он тогда нужен? Для многого.

У него есть, например, свойство AutoSize, которое, если установить его в True, заставляет PictureBox в режиме работы подстраивать свои размеры под размеры картинки. (А что происходит в режиме проектирования, вряд ли нас должно интересовать, правда?) Получается вот что —>



В этом случае даже векторная графика перестает быть послушной и заставляет PictureBox (в режиме работы, а не проектирования!) подстраиваться под свои размеры.

А теперь испытаем элемент управления Image. Он тоже специально предназначен для размещения картинок. Проверьте, установлено ли его свойство Strech в False, и убедитесь, что по отношению ко всем видам графики объект Image в режиме работы подстраивает свои размеры под размеры картинки. В чем же тогда его отличие? Вот в чем.

Установите свойство Strech в True, это заставит уже картинку в режиме работы подстраивать свои размеры под размеры Image, а не наоборот. Любую картинку, в том числе aise и растровую. Получается вот что — >



Выходит, что свойство Strech — переключатель того, что подо что "прогнется" — Image под картинку или картинка под Image.

А теперь самостоятельно испытайте кнопку — CommandButton. Но перед испытанием обязательно придайте ее свойству Style значение Graphical, иначе никаких картинок на кнопке не будет видно. Кроме свойства Picture у кнопки есть еще, например, такое свойство — DownPicture. Оно определяет другую картинку, а именно ту, которую мы видим, нажав кнопку и не отпуская ее.

Задание 60: Вы профессиональный продавец автомобилей. Вы приезжаете к покупателю, достаете портативный компьютер, на экране — несколько десятков кнопок, на каждой — маленькая фотография одного из продаваемых автомобилей. Покупатель говорит: "Вот этот покажите, пожалуйста". Вы нажимаете кнопку и на экране возникает та же фотография, но увеличенная.

Помощь: Если вы собираетесь в качестве кнопок использовать элементы управления CommandButton, то уменьшенные фото вам придется предварительно сделать в каком-нибудь графическом редакторе и сохранить их в отдельные файлы, постаравшись, чтобы эти маленькие картинки на экране были примерно одинаковых размеров. Но можно и избежать такой потери времени. Ведь кнопками могут служить объекты Image! Потому что у объекта Image тоже есть событие Click! Создайте на форме несколько маленьких Image и один большой и в маленькие впишите фото. По щелчку мыши по маленькому Image большой Image пусть копирует в себя его картинку.

Необязательное усложнение для тех, кто не боится системы координат: Если у вас все получилось, то вы уже обратили внимание на одну проблему. Проблема в том, что размеры и форма исходных фото разные: одни продолговатые, другие квадратные (а если у вас одинаковые, то сделайте разными, а то неинтересно). Бог с ними, с кнопками (хотя с ними та же самая проблема), нам хочется, чтобы хоть большие-то картинки располагались на экране симметрично как по горизонтали, так и по вертикали, и имели максимально возможный размер. Вот этой цели я и хочу, чтобы вы достигли. Для этого вам придется использовать оператор ветвления, а также свойства, задающие размер и местоположение объектов.

Проверьте, чтобы форма была распахнута на весь экран. После щелчка мыши по кнопке компьютер должен сделать следующее: Настроить большой Image, чтобы он подстраивался под размеры картинки, установив сами знаете какое свойство.

Пусть большой Image копирует в себя картинку из маленького. На форме появится более-менее большое фото неискаженных пропорций, но не по центру. Все это у вас уже давно готово. Задача — увеличить фото еще больше, и чтобы оно было по центру.

Поделить ширину формы на ее высоту, чтобы узнать ее "продолговатость". (Это надо бы пораньше, да ладно.)

Поделить ширину Image на его высоту, чтобы узнать "продолговатость" картинки.

Если продолговатость картинки больше, чем продолговатость формы, то в идеале при максимальном увеличении картинка должна почти упереться левым и правым краем в края формы, а сверху и снизу должно остаться одинаковое пространство. Для этого нужно выполнить несколько операторов присваивания, увеличивающие размер и изменяющие местоположение Image, да так, чтобы продолговатость Image равнялась продолговатости картинки, а затем заставить картинку принять размеры Image.

Если продолговатость картинки меньше, чем продолговатость формы, то в идеале при максимальном увеличении картинка упрется верхним и нижним краем в края формы, а слева и справа должно остаться одинаковое пространство. Здесь тоже нужно выполнить несколько аналогичных операторов.

Таким образом, при щелчке по кнопке на форме возникает фото и сразу же за этим вместо него — оно же, но увеличенное и по центру. Если вам не нравится такое мелькание, поэкспериментируйте в программе со свойством Visible объекта Image. Гарантирую прекрасные результаты.


Другие полезные сведения

Если вы загружаете картинку в объект в режиме проектирования, то Visual Basic сохраняет ее в одном из файлов, из которых состоит ваш проект. Это резко увеличивает размеры вашего проекта на диске и время загрузки проекта, зато теперь вы можете безнаказанно стереть исходный графический файл с диска. Если вы загружаете картинку в объект в режиме работы, то все наоборот.

Преимущество формы и PictureBox в том, что вы при помощи их методов можете печатать информацию прямо на их картинке и рисовать по ней (например, пририсовать кому-нибудь очки).


Второй способ — Объекты Line и Shape

Рассмотрим второй способ использования графики в Visual Basic.

Возьмем в Toolbox объект Line (Линия) и проведем наискосок мышкой по форме. На форме разместится отрезок прямой. Мы можем его перемещать за маркеры или ухватившись острием мышиного курсора за середину. Поэкспериментируйте со следующими свойствами линии:

Свойство ∙ Смысл

BorderWidth ∙ Толщина линии

BorderColor ∙ Цвет линии

Borderstyle ∙ Стиль линии (сплошная, штриховая и т. п.). Предварительно сделайте толщину = 1.

X1, Y1, X2, Y2 ∙ Координаты крайних точек отрезка

Возьмем в Toolbox объект Shape (Фигура) и проведем наискосок мышкой по форме. На форме разместится прямоугольник. Он может превратиться в квадрат, овал (эллипс), круг, может закруглить углы, все это в зависимости от значения его свойства Shape (да-да, одинаковые названия у объекта и его свойства). Поэкспериментируйте со следующими свойствами фигуры:

Свойство ∙ Смысл

BorderWidth ∙ Толщина линии

BorderColor ∙ Цвет линии

Borderstyle ∙ Стиль линии (сплошная, штриховая и т. п.). Предварительно сделайте толщину = 1.

Сейчас пространство внутри фигуры прозрачное. В этом легко убедиться, если на форму загружена какая-нибудь картинка. Предположим, вы хотите, чтобы пространство внутри фигуры было не прозрачным, а залито краской или заполнено узором. Для этого давайте разберемся в устройстве фигуры. Удобно представлять, что фигура — это оконная рама со вставленными в нее двумя прозрачными стеклами. Одно стекло — подальше от наших глаз, другое поближе. Прозрачностью дальнего стекла управляет свойство BackStyle, а цветом — свойство BackColor. На дальнем стекле узоров не бывает. Прозрачностью и узором ближнего стекла управляет свойство FillStyle, а цветом — свойство FillColor. Поэкспериментируйте.

Метку тоже можно сделать прозрачной, как и фигуру, если ее свойство BackStyle задать равным Transparent.


Взаимное перекрытие объектов. Метод ZOrder

На рисунке вы видите несколько объектов, размещенных на форме и частично перекрывающих друг друга. Это линии, фигуры, Image (маленькое фото), PictureBox (рамка с маленьким крестиком в углу), текстовое поле, кнопка, метка. По какому принципу они перекрывают друг друга? Почему текстовое поле перекрывает линию и фигуру, а не наоборот? Рассмотрим эту механику.



Все объекты расположены в трех слоях и мы не можем менять местами слои и перемещать объект из одного слоя в другой.

Самый дальний от наших глаз слой — это сама форма со своей картинкой и с тем текстом и изображениями, которые мы можем на ней получить при помощи ее методов.

В среднем слое помещаются объекты Line, Shape, Image, метка.

В ближнем к нам слое помещаются все неграфические объекты и PictureBox.

Мы можем перемещать объекты в пределах своего слоя ближе или дальше от глаз:

В режиме проектирования — выделить интересующий нас объект —>Format—>Order—> далее нужно выбрать одну из двух команд: Bring to Front (перенести на передний план) или Send to Back (отослать на задний план).

В режиме работы — использовать метод ZOrder. Так, чтобы перенести на передний план текстовое поле, мы пишем оператор:

Text1.ZOrder (0)

а чтобы отослать его на задний план:

Text1.ZOrder (1)

Цвет в Visual Basic

Как до сих пор мы придавали цвет какому-нибудь элементу Visual Basic:

В режиме проектирования мы устанавливали соответствующее свойство в окне свойств. Для этого в закладке Palette выбирали один из нескольких десятков цветов.

В режиме работы пользовались операторами типа Form1.BackColor = vbRed. Имеется всего 8 цветов, представленных этим способом:

vbBlack ∙ Черный

vbRed ∙ Красный

vbGreen ∙ Зеленый

vbYellow ∙ Желтый

vbBlue ∙ Синий

vbMagenta ∙ Фиолетовый (неточный перевод)

vbCyan ∙ Голубой (неточный перевод)

vbWhite ∙ Белый

Но в Visual Basic существует 16 миллионов цветов с лишним (точнее 16777216)! Мы должны научиться ими управлять. Есть несколько способов. Так, цвет можно указывать просто числом от 0 до 16777215. Например,

Form1.BackColor = 12456743

Недостаток этого способа — по числу трудно угадать, что за цвет.

Мне нравится такой способ: Вспомним, что любую краску можно получить, смешав в определенной пропорции красную (Red), зеленую (Green) и синюю (Blue) краски. В Visual Basic каждой краски в смесь можно положить от 0 до 255 единиц. Смешивает краски специальная функция RGB (название — по первым буквам цветов). Пусть мы хотим покрасить форму краской, в которую мы положили и смешали 100 единиц красной, 200 единиц зеленой и 50 единиц синей краски. Для этого пишем такой оператор:

Form1.BackColor = RGB (100, 200, 50)

Чем меньше каждой краски мы положим, тем темнее будет цвет, чем больше — тем светлее:

RGB (70, 90, 88) Темный цвет (потому что числа маленькие)

RGB (210, 250, 202) Светлый цвет (потому что числа большие)

RGB (0, 0, 0) Черный цвет

RGB (255, 255, 255) Белый цвет

Если каждой краски положить поровну, получится серый цвет:

RGB (90, 90, 90) Темно-серый цвет

RGB (220, 220, 220) Светло-серый цвет

RGB (255, 255, 0) Желтый цвет

Результатом работы функции RGB является число, обозначающее цвет. Кстати, для любознательных. Посчитайте-ка, сколько всего цветов можно получить, перебрав все возможные в Visual Basic сочетания красного, зеленого и синего.


Задание цвета в режиме проектирования

Хорошо. В режиме работы мы научились задавать все цвета. А в режиме проектирования? Мы видим, что цвета в окне свойств закодированы строкой из каких-то непонятных значков, например: &H008ОC0FF&

Эту строку вы можете вручную изменять, ставя на место одних значков подходящие другие, и таким образом задавать любой из 16 миллионов цветов. Попробуем разобраться, что означают значки этого кода:



Количество каждой краски закодировано в так называемой шестнадцатиричной системе счисления. К сожалению, я не могу из-за ограниченного объема книги дать вам здесь прочное понятие о системах счисления, попытаюсь только дать способ разобраться в кодировке.

В отличие от привычной нам десятичной системы счисления, где 10 цифр (0, 1, 2…, 9), в шестнадцатиричной системе 16 цифр (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, А, В, С, D, Е, F). Не очень удобно, что старшие цифры обозначены буквами, но другие значки еще неудобнее.

Если человек, привыкший кодировать все числа в 16-й системе[25], скажет, что он видит 7 предметов, то обычный человек, глядя на них, тоже скажет, что их 7. Если тот скажет, что он видит А предметов, то обычный человек, глядя на них, скажет, что их 10.Если тот скажет, что он видит F предметов, то этот скажет, что их 15.

Когда обычный человек видит наше привычное десятичное число 47, то он говорит, что надо взять 4 раза по десять и еще прибавить 7.

Когда 16-й человек видит 16-е число 29, то он учит обычного человека, что надо взять 2 раза по шестнадцать и еще прибавить 9. Получится 41. Итак, 16-е число 29 означает 10-е число 41.

Когда 16-й человек видит 16-е число АЕ, то он учит обычного человека, что надо взять А раз (то есть 10 раз) по шестнадцать и еще прибавить Е (то есть 14). Получится 174. Итак, 16-е число АЕ означает 10-е число 174.

Максимальное двузначное число в 16-й системе — FF. Убедитесь, что оно равно 255 в 10-й системе. Получается, что для задания количества краски в цвете Visual Basic достаточно двузначного 16-го числа. Такая кодировка и применяется на самом деле.

Теперь вы можете сознательно менять 16-е цифры в окне свойств и наблюдать результат.

А сейчас я хочу вам подсказать, как задавать количество красной, синей и зеленой краски в том самом числе, которое от 0 до 16777215. Для знатоков систем счисления достаточно знать, что переведя это число из 10-й системы в 16-го, вы получите число из шести 16-х цифр, полностью определяющее цвет так, как я это только что описал. Для остальных скажу, что вам достаточно задавать это число таким выражением:

Form1.BackColor = В * 256 * 256 + G * 256 + R

Здесь В, G, R — числовые переменные, имеющие тот же смысл, что и числа в функции RGB. А теперь, знатоки, скажите, не кажется ли вам, что перед вами 256-я система счисления?


3 способ — Рисуем при помощи графических методов

Рассмотрим третий способ использования графики в Visual Basic.

Методами для рисования различных геометрических фигур обладают два объекта: форма и PictureBox. Кстати, те же, что обладают и методом Print, который с полным основанием тоже называют графическим.

Напишем программу, которая рисует на форме точку, прямоугольник, окружность и отрезок прямой в тех местах, где это показано на рисунке:



Вот программа:

Private Sub Command1_Click()

PSet (1000, 2000) 'точка

Line (2000, 1000)-(5000, 3000) 'отрезок прямой

Line (3000, 3000)-(1000, 4000), В 'прямоугольник

Circle (4000, 2000), 1000 'окружность

End Sub

Пояснения: Числа на картинке обозначают горизонтальную и вертикальную координаты на форме (в твипах).

Вы видите, что методы записаны без указания объекта, которому они принадлежат. В этом случае считается, что по умолчанию они принадлежат форме. Если бы вы записали Picture1.Line, то рисование происходило бы на поверхности PictureBox.

Точка рисуется методом PSet. Два числа в скобках — координаты точки на форме, первое число — горизонтальная координата, второе число — вертикальная.

Будем называть величины, указанные в методе, параметрами метода.

Отрезок прямой рисуется методом Line. Мы знаем, что отрезок прямой можно построить, если известно положение двух его крайних точек. Они-то и задаются в обращении к методу. Первая пара параметров — координаты одной точки (любой из двух), вторая пара — другой.

Если дана пара точек, то между ними можно провести не только отрезок прямой, но и прямоугольник. Для этого достаточно в методе Line указать букву В после двух запятых.

Окружность можно построить, если известно положение центра и радиус. Окружность рисуется методом Circle, первые два параметра которого — координаты центра, третий — радиус.

Создайте новый проект и проверьте программу.

Кроме метода Print, в Visual Basic есть следующие графические методы (о тех из них, что нам не знакомы, поговорим чуть позже):

Метод ∙ Смысл

PSet ∙ Точка

Line ∙ Линия или прямоугольник

Circle ∙ Круг, эллипс, дуга, сектор

Cls ∙ Очищает поверхность объекта от нарисованного и напечатанного

Point ∙ Это функция, она сообщает цвет любой точки на объекте

PaintPicture ∙ Копирует с одного объекта на другой прямоугольный кусок изображения


Настройка внешнего вида рисуемых фигур

Фигуры, изображенные методами вашей программы, нарисованы тонкими черными сплошными линиями без заливки внутренних областей. Это скучно. Вы должны уметь управлять толщиной, цветом и другими атрибутами фигур. Для этого есть три способа, которые вы можете применять по одиночке или вперемешку:

В режиме проектирования настроить соответствующие свойства объекта. Эти свойства воздействуют сразу на все методы.

В режиме работы в нужные моменты изменять эти свойства (этот способ бьет предыдущий, то есть в случае конфликта пересиливает его настройки).

В самом методе можно задавать многие атрибуты рисуемой фигуры (этот способ бьет остальные).

Поговорим об этом подробнее.


Свойства объектов, влияющие на графические методы

Поэкспериментируйте со следующими свойствами (сначала в режиме проектирования, а затем в режиме работы):

Свойство ∙ Смысл

DrawWidth ∙ Толщина линии

ForeColor ∙ Цвет линии

DrawStyle ∙ Стиль линии (сплошная, штриховая и т. п.). Предварительно сделайте толщину = 1.

FillStyle ∙ Стиль (узор) заливки и будет ли заливка.

FillColor ∙ Цвет заливки

AutoRedraw ∙ Определяет, будут ли автоматически восстанавливаться графика и напечатанный текст, случайно стертые из-за того, что объект скрылся из вида.

DrawMode ∙ Способ наложения краски. По умолчанию = 13 (Сору Реп), когда краска плотно накладывается и предыдущая картинка через нее не просвечивает. При других значениях новая краска меняет свой цвет или сложно взаимодействует со старой и иногда получается любопытный и полезный результат.


Пример:

PSet (1000, 2000) 'точка — тонкая, черная

Circle (4000, 2000), 1000 'окружность — тонкая, черная

DrawWidth = 20 'меняем толщину линий

ForeColor = RGB(230, 250, 100) 'меняем цвет линий

PSet (1000, 5000) 'точка — толстая, цветная

Circle (4000, 5000), 1000 'окружность — толстая, цветная


Задание 61: В режиме работы нарисуйте снеговика и сделайте на нем надпись шрифтом Times — >



А теперь рассмотрим подробнее графические методы.


Метод Pset

До этого я использовал методы, указывая минимальное число параметров. Теперь я хочу показать все важные параметры, которые можно указывать в методах.

Метод ∙ Результат

PSet (1000, 2000) ∙ Рисуется точка с координатами х=1000, у=2000. Цвет точки определяется свойством ForeColor

PSet (1000, 2000), vbRed ∙ Рисуется красная точка

Параметры метода могут быть выражениями, например:

PSet (х+200, у), RGB(5+а, 90, 80) + 100

Вообще, в дальнейшем я буду для простоты при описании процедур, функций, методов в качестве значения их параметров указывать числа, но вы должны иметь в виду, что почти всегда там, где допустимы числа, допустимы и выражения.

Синтаксис метода PSet:

PSet (х, у), цвет

Здесь все параметры, включая цвет — числовые выражения.

В этой и следующих синтаксических схемах я по возможности воздержусь от квадратных скобок, указывающих на необязательность параметра, иначе схемы будут ими перенасыщены. Также я не буду указывать объект — владелец метода. Также не буду указывать и отложу немного объяснение параметра Step.


Метод Line

Вот объяснение на примерах:

Метод ∙ Результат

Line (2000, 1000)-(5000, 3000) ∙ Отрезок прямой между точкой с координатами (2000, 1000) и точкой с координатами (5000, 3000).

Line (2000, 1000)-(5000, 3000), vbRed ∙ Отрезок красного цвета

Line (2000, 1000)-(5000, 3000), vbRed,В ∙ Прямоугольник красного цвета

Line (2000, 1000)-(5000, 3000), vbRed,BF ∙ Прямоугольник красного цвета, залитый этим же цветом

Line (2000, 1000)-(5000, 3000),B ∙ Прямоугольник. Цвет его определяется свойством ForeColor, так как в операторе там, где должен быть указан цвет, стоит пустота

Нет смысла и запрещено писать одну букву F вместо В или BF.

Заливку можно сделать двумя способами:

Поставив букву F, тогда заливка будет тем же цветом, что и линия.

Не ставя букву F, тогда заливка определяется свойствами FillStyle и FillColor.

Обратите внимание на две стоящие рядом запятые в последнем примере. Это вполне понятный стиль Visual Basic — если в списке необязательных параметров какой-то параметр пропускается, то запятые нужно указывать все равно, а то будет непонятно, какой по порядку параметр вы указали правее.

Синтаксис метода Line:

Line (x1, y1) — (х2, у2), цвет, В | BF

Здесь все параметры, включая цвет — числовые выражения.

Вертикальная черта | означает "или". Имеется в виду, что в этом месте оператора вы можете поставить или В или BF.


Метод Circle

Вот объяснение на примерах:

Метод ∙ Результат

Circle(4000,2000),1000 ∙ Окружность с центром в точке с координатами (4000, 2000) и радиусом 1000

Circle(4000,2000),1000,vbRed ∙ Красная окружность

Circle(4000,2000),1000,1,3 ∙ Дуга окружности, начинающаяся от угла в 1 радиан* и кончающаяся углом в 3 радиана. Угол отмеряется от направления на восток против часовой стрелки

Circle(4000,2000),1000,-1,-3 ∙ Сектор круга, начинающийся от угла в 1 радиан и кончающийся углом в 3 радиана. Угол отмеряется от направления на восток против часовой стрелки

Circle(4000,2000),1000,2 ∙ Эллипс (эллипс — это почти овал) с центром в точке с координатами (4000, 2000). Получен из окружности радиусом 1000 горизонтальным сжатием в 2 раза

Circle(4000,2000),1000,1/3 ∙ Эллипс с центром в точке с координатами (4000, 2000). Получен из окружности радиусом 1000 вертикальным сжатием в 3 раза

Circle(4000,2000),1000,1,3,2 ∙ Дуга эллипса

Circle(4000,2000),1000,-1, —,2 ∙ Сектор эллипса

* Для тех, кто не знаком с радианами, поясню, что в одном радиане 180/pi градусов, где pi=3.14


Синтаксис метода Circle:

Circle (х_центра, у_центра), радиус, цвет, начальный_угол, конечный_угол, сжатие

Здесь все параметры, включая цвет — числовые выражения.

CurrentX, CurrentY, Step

В процессе рисования Visual Basic постоянно меняет свойства формы CurrentX, CurrentY, которые равняются координатам последней нарисованной точки. Для метода Line это та из двух точек, координаты которой указаны в правых скобках, а если дело касается метода Circle — то это координаты центра окружности. Для метода PSet все ясно без объяснений. Метод Print тоже меняет эти координаты, устанавливая их в то место, где должен появиться следующий напечатанный символ. Вы можете отслеживать эти свойства при помощи оператора Debug.Print CurrentX, CurrentY.


Теперь поговорим о Step.

Задача: Нарисовать три точки: одну с координатами (500, 1000), а две другие правее и выше. Расстояние соседних точек друг от друга равно 179 твипов по горизонтали и 40 твипов по вертикали.

Фрагмент программы, решающий дело:

PSet (500, 1000)

PSet (679, 960)

PSet (858, 920)

Здесь нам пришлось вычислять координаты. Есть другой способ, который иногда бывает удобнее:

PSet (500, 1000)

PSet Step(179, -40)

PSet Step(179, -40)

Перед любыми скобками с указанием координат вы имеете право писать слово Step. Тогда числа в этих скобках перестают быть абсолютными координатами, а становятся смещением по горизонтали и вертикали от точки, координаты которой определяются свойствами CurrentX, CurrentY. Положительное смещение по горизонтали — направо, по вертикали — вниз.

Попробуйте без компьютера нарисовать на бумажке, что нарисует такой фрагмент:

Circle (2000, 2000), 1000

Line Step(900, 0)-Step(-900, -900)


Метод Cls

Он просто стирает все нарисованное и напечатанное. Вставьте его в программу

и проверьте в пошаговом режиме:

Circle (2000, 2000), 1000

Print 12345

Cls

Line Step(900, 0)-Step(-900, -900)


Метод Point

Задача: Вы загрузили в форму фотографию морского пляжа и хотите узнать, какого цвета зонтик вот у этой дамы слева.

Решение: Сначала вам нужно узнать координаты хоть какой-нибудь точки на зонтике. Я думаю, вы сами догадаетесь, как это сделать. (Совершенно верно, здесь вам поможет маленькая окружность, координаты которой вы подбираете так, чтобы попасть в зонтик). Пусть окружность Circle (1000, 9000), 100 оказалась прямо на зонтике. Теперь достаточно выполнить процедуру:

Private Sub Command1_Click()

Debug.Print Point (1000, 9000)

End Sub

Цвет вы получите в виде числа, например, 12089756. Да-да, это то самое число от 0 до 16777215. Совершенно неудобоваримое. Для того, чтобы определить, сколько в нем красной, синей и зеленой краски, вам придется провести некоторые арифметические подсчеты, идею которых вам должно подсказать выражение из 0. Это и будет ваше задание 62: Определить цвет заданной точки на форме и выдать одно из трех сообщений:

В этом цвете красной краски больше, чем двух остальных.

В этом цвете зеленой краски больше, чем двух остальных.

В этом цвете синей краски больше, чем двух остальных.

Распознав цвет точки на форме, вы сделали первый шаг к решению великой и не решенной до сих пор человечеством задачи распознавания зрительных образов. Пожалуй, вы уже сейчас в силах написать программу, которая в большинстве случаев правильно отличит фотографию песчаной пустыни от фотографии океана. Но знаете ли вы, что не родился еще гений, способный написать программу, надежно отличающую хотя бы фото собаки от фото кошки? Потому что здесь дело не столько в цвете, сколько в форме. А это уже гораздо сложнее.

Решение задачи распознавания образов — ключ к осуществлению величайшей и самой дерзкой мечты ученых — созданию искусственного интеллекта, электронного разума, равного человеческому или превосходящего его.


Метод PaintPicture

Задача: В объекты Picture1 и Picture2 загружены картинки. Взять прямоугольный кусок из картинки в Picture2 и вставить, немного сжав, в определенное место картинки в Picture1.



Решение: Дело решает одна строка:

Picture1. PaintPicture Piсturе2.Picture, 500, 100, 600, 800, 4500, 1000, 900, 1200

Словесное описание этой строки: В объект Picture1 вставить фрагмент из Picture2.Picture, причем левый верхний угол исходного изображения имеет координаты (4500, 1000), его ширина — 900, высота — 1200. Левый верхний угол результирующего изображения имеет координаты (500, 100), его ширина — 600, высота — 800.

Объектом может служить форма и PictureBox.


Используем в рисовании переменные величины

Если вы нарисовали снеговика, то наверное согласитесь, что для этого вам пришлось основательно потрудиться, хотя сам рисунок получился не слишком богатый, в нем всего-то порядка десяти элементов.

Как заставить Visual Basic короткой программой рисовать множество элементов, сплетая их в красивые узоры? Ответ: применять циклы, используя в обращениях к графическим методам вместо чисел переменные величины и арифметические выражения.

Задача: Нарисовать горизонтальный ряд окружностей радиусом 100 на расстоянии 1000 от верхнего края экрана и с такими горизонтальными координатами 500, 800, 1100, 1400…, 2900.

Как видим, центры соседних окружностей отстоят друг от друга на 300. Вот примитивный фрагмент, решающий эту задачу:

Private Sub Command1_Click()

Circle (500, 1000), 10 °Circle (800, 1000), 100

Circle (1100, 1000), 100

Circle (1400, 1000), 100

Circle (1700, 1000), 100

Circle (2000, 1000), 100

Circle (2300, 1000), 100

Circle (2600, 1000), 100

Circle (2900, 1000), 100

End Sub

При вводе этой программы вас будет раздражать необходимость вводить много раз почти одно и то же. Воспользуйтесь копированием, которое объяснено в Приложений.

Мы видим, что здесь Visual Basic 9 раз выполняет один и тот же метод, причем при каждом следующем обращении первый параметр вырастает на 300.

Придумаем для первого параметра переменную величину, например, х. Немного изменим программу:

Private Sub Command2_Click()

х = 500

Circle (x, 1000), 100 х = х + 300

Circle (x, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

Circle (х, 1000), 100 х = х + 300

End Sub

Здесь последний оператор х = х + 300 я написал только для красоты, от него нет никакой пользы, хотя и вреда тоже особого нет.

Эта программа рисует абсолютно то же самое, что и предыдущая, но она проще нее, так как не пришлось самим вычислять координаты.

Что мы видим? Мы видим, что программа состоит из нескольких одинаковых фрагментов. Это прямое приглашение применить цикл:

Dim х As Long

Private Sub Command3_Click()

x = 500

Do Until x > 2900

Circle (x, 1000), 100

x = x + 300

Loop

End Sub

Эта программа тоже рисует абсолютно то же самое, что и две предыдущие, но она короче. Здесь я перестраховался и объявил переменную х, как целую. Иначе при многократном прибавлении 300 могло бы оказаться, что результат равен не 2900, а, скажем, 2900.0000067 (Такой же случай я рассматривал в 0). А это значит, что последняя окружность не была бы нарисована. Можно было бы перестраховаться по-другому: вместо Do Until х > 2900 написать Do Until х > 2901.

Задание 63: Попробуйте уменьшить расстояние между центрами окружностей, не изменяя их радиуса, нарисовав их плотнее, чтобы они пересекались, еще плотнее, пока они не образуют "трубу".

Задание 64:. Удлините трубу налево и направо до краев формы.

Задание 65: Увеличьте толщину трубы.

Заставим окружности вести себя посложнее. Например, расположим их не по горизонтали, а по диагонали формы в направлении от левого верхнего угла в правый нижний. Для этого организуем еще одну переменную — вертикальную координату у — и заставим ее тоже изменяться одновременно с х.

Private Sub Command4_Click()

х = 500 у = 200

Do Until x > 2900

Circle (x, y), 100

x = x + 300

у = у + 200

Loop

End Sub

Если мы захотим менять радиус, то организуем переменную R.

Задание 66: "Очередь трассирующими". Нарисуйте ряд точек по направлению из левого нижнего угла в правый верхний.

Задание 67: "Круги на воде или радиоволны". Нарисуйте пару десятков концентрических окружностей, то есть окружностей разного радиуса, но имеющих общий центр.

Задание 68: "Компакт-диск" и "Летающая тарелка". Если радиус самого маленького "круга на воде" будет порядка 500, а самого большого — во весь экран, и если радиусы соседних окружностей будут различаться на 10–30 твипов, то на экране вы увидите привлекательный "компакт-диск". Сделайте его золотым (Yellow). Если получилось, то сделайте ему внутренний и наружный ободки другого цвета. А теперь "положите" диск, то есть нарисуйте его не из окружностей, а из эллипсов, сжатых по вертикали. Получится "летающая тарелка".

Задание 69: Не трогая х, а меняя только у и R, вы получите "коническую башню".

Задание 70: Меняя все три параметра, вы получите трубу, уходящую в бесконечность.

Задание 71: Разлинуйте экран в линейку.

Задание 72: А теперь в клетку.

Задание 73: А теперь в косую линейку.

Задание 74: Начертите ряд квадратов.

Чтобы получить интересные и сложные рисунки, нужно использовать богатые возможности Visual Basic: вложенные циклы, ветвление внутри цикла и т. д., например:

Задание 75: Нарисуйте шахматную доску.

Помощь: Здесь основные трудности возникнут при раскраске клеток в шахматном порядке. У Волченкова [См. список литературы] я встретил такую идею, касающуюся того, какие клетки закрашивать, а какие нет: Те клетки, у которых сумма номеров строки и столбца четная — закрашивать, остальные — нет.

Задание 76: "Ковер" или "Кольчуга". В задании 62 вы рисовали горизонтальный ряд пересекающихся окружностей. Теперь нарисуйте один под другим много таких рядов.

Указания: Здесь вам понадобятся вложенные циклы. Если центры соседних окружностей отстоят друг от друга на одинаковое расстояние как по горизонтали, так и по вертикали, и если удачно подобраны остальные числа, то у вас получится красивый ковер во весь экран с аккуратными краями.

Задание 77: Пусть у этого ковра будет вырезан левый нижний угол.

Задание 78:… и вдобавок вырезан квадрат посередине.


Использование случайных величин при рисовании

Со случайными числами и функцией Rnd мы с вами познакомились. Попробуем нарисовать "звездное небо". Для этого достаточно покрасить форму в черный или синий цвет и в случайных местах формы нарисовать некоторое количество разноцветных точек (скажем, 1000). Точка ставится методом PSet. Как сделать координаты и цвет точки случайными? Тот же Rnd. Ваша форма имеет размеры WidthxHeight, количество цветов равно 16777216, поэтому обращение к методу рисования одной точки случайного цвета будет выглядеть так:

PSet (Width * Rnd, Height * Rnd), 16777216 * Rnd

Этот оператор нужно просто выполнить 1000 раз:

For i = 1 То 1000

PSet (Width * Rnd, Height * Rnd), 16777216 * Rnd

Next

Результат будет ярче, если точки будут иметь случайную толщину (1 или 2). Имейте в виду, что сколько бы раз вы не запускали программу с указанным фрагментом, картина созвездий на экране будет абсолютно одинакова. Если вам нужно, чтобы от запуска к запуску набор значений случайной величины менялся (а значит и созвездия), употребите разик до использования функции Rnd процедуру Randomize.

Задание 79: "Звезды в окне". Звездное небо в пределах прямоугольника.

Задание 80: "Дождь в луже". Заполните форму окружностями или эллипсами радиуса 200 в случайных местах.

Задание 81: "Мыльные пузыри". То же самое случайных радиусов и цветов.

Задание 82: "Сноп света в глаза". То есть пучок лучей, выходящих из одной точки. Реализуется множеством случайных разноцветных отрезков прямых, причем одна точка всех отрезков не случайна, а находится в центре формы.

Задание 83: "Стог сена". Множество случайных разноцветных отрезков прямых преимущественно желтоватых оттенков, причем одна точка любого отрезка находится в случайной точке левой трети стога, другая — в случайной точке правой. Размер стога — 6000 на 6000. Используйте функцию RGB со случайными аргументами.

Задание 84: "Атака абстракциониста". На экране бесконечно рисуется большое количество случайных разноцветных залитых прямоугольников или эллипсов.

Совет: Если ваш компьютер быстрый, то прямоугольники или эллипсы будут сменять друг друга с огромной скоростью, что может вам не понравиться. Чтобы замедлить работу компьютера, обычно используют таймер. Но поскольку вы с ним не знакомы, вставьте для замедления внутрь цикла оператор, который, ничего не изменяя на экране, будет выполняться достаточно долго. Обычно для этих целей используют "пустой цикл":

For j = 1 То 1000000: Next

Пока компьютер досчитает до миллиона, пройдет некая значительная доля секунды.

Задание 85: "Летающие тарелки в космосе". Они получатся, если по нажатии одной кнопки вы будете добавлять на форму очередную порцию звезд, а по нажатии другой — очередную летающую тарелку из задачи 68, но случайного размера и в случайном месте, что нелегко. Подсказка без пояснений: При рисовании тарелки не используйте Rnd внутри цикла, все случайные значения присвойте переменным выше цикла.


ПРОЦЕДУРЫ

До сих пор мы с вами имели дело только с процедурами, задающими реакцию компьютера на те или иные события. Это процедуры типа "Что делать, если…". Настала пора познакомить вас с другими процедурами — процедурами типа "Как". Будем называть их процедурами пользователя. В этой главе я на одном примере проведу вас от процедур пользователя к процедурам с параметрами.


Зачем нужны процедуры пользователя

Задача: Вы записали на диск десяток фотографий, снятых во время каникул, и решили сделать фотоальбом. Поместили на форму десяток кнопок с названиями фотографий и один PictureBox. При нажатии на кнопку нужное фото для всеобщего обозрения загружается в PictureBox, а также печатается дата снимка.

Задача легкая, мы ее уже решали в 0. Вот программа для 4 фотографий:

Private Sub Command1_Click()

Picture1.Picture = LoadPicture("с: \temp\Rockies.bmp")

Picture1.Print, "21.07.2001"

End Sub


Private Sub Command2_Click()

Picture1.Picture = LoadPicture("c: \temp\Porthole.bmp")

Picture1.Print, "28.07.2001"

End Sub


Private Sub Command3_Click()

Picture1.Picture = LoadPicture("c: \temp\Balloons.bmp")

Picture1.Print, "12.08.2001"

End Sub


Private Sub Command4_Click()

Picture1.Picture = LoadPicture("c: \temp\Guitar.bmp")

Picture1.Print, "20.07.2001"

End Sub

Хочу предупредить, что эта программа, постепенно усложняясь, пройдет через всю главу, поэтому разберитесь в ней как следует, иначе важный материал главы будет вам непонятен.

Усложним задачу: Некоторые из фотографий сняли вы, некоторые — ваш друг. Вы хотите, чтобы в знак этого на ваших фото в левом верхнем углу появлялся один значок, а на фото вашего друга другой. Ваш любимый значок такой — >

а у вашего друга такой — >

Пусть они и появляются.

Давайте значки будем рисовать при помощи методов. Ваша программа станет такой:

Private Sub Cornmandl_Click ()

Picture1.Picture = LoadPicture("c: \temp\Rockies.bmp")

'Это ваше фото, рисуем значок:

Picture1.Line (100, 100)-(300, 300), vbBlue, В

Picture1.Line (100, 100)-(300, 300), vbBlue

Picture1.Line (100, 300)-(300, 100), vbBlue

Picture1.Print, "21.07.2001"

End Sub


Private Sub Command2_Click()

Picture1.Picture = LoadPicture("c: \temp\Porthole.bmp")

'Это ваше фото, рисуем значок:

Picture1.Line (100, 100)-(300, 300), vbBlue, В

Picture1.Line (100, 100)-(300, 300), vbBlue

Picture1.Line (100, 300)-(300, 100), vbBlue

Picture1.Print, "28.07.2001"

End Sub


Private Sub Command3_Click()

Picture1.Picture = LoadPicture("c: \temp\Balloons.bmp")

'Это фото вашего друга, рисуем значок:

Picture1.Circle (200, 200), 20

Picture1.Circle (200, 200), 70

Picture1.Circle (200, 200), 120

Picture1.Circle (200, 200), 170

Picture1.Print, "12.08.2001"

End Sub


Private Sub Command4_Click()

Picture1.Picture = LoadPicture("c: \temp\Guitar.bmp")

'Это фото вашего друга, рисуем значок:

Picture1.Circle (200, 200), 20

Picture1.Circle (200, 200), 70

Picture1.Circle (200, 200), 120

Picture1.Circle (200, 200), 170

Picture1.Print, "20.07.2001"

End Sub

Программа работает нормально, но невооруженным глазом виден ее существенный недостаток — резко возросший объем. Недостаток этот особенно будет заметен, когда число фото вырастет до десятка. Это тем более обидно, что в программе есть два повторяющихся фрагмента. Это фрагмент

'Это ваше фото, рисуем значок:

Picture1.Line (100, 100)-(300, 300), vbBlue, В

Picture1.Line (100, 100)-(300, 300), vbBlue

Picture1.Line (100, 300)-(300, 100), vbBlue

и фрагмент

'Это фото вашего друга, рисуем значок:

Picture1.Circle (200, 200), 20

Picture1.Circle (200, 200), 70

Picture1.Circle (200, 200), 120

Picture1.Circle (200, 200), 170

которые в нашей программе встретились по два раза, а когда число фото вырастет, то встретятся многократно.

В этом случае программисты всего мира поступают так. Они придумывают повторяющимся фрагментам имена, например,

Рисуем_мой_значок

и

Рисуем_значок_друга

Затем они вписывают в программу специальную процедуру для каждого фрагмента с придуманным только-что именем, после чего имеют право во всей программе вместо фрагмента писать его имя. Чтобы вам было понятно, посмотрите на получившуюся программу:

Private Sub Рисуем_мой_значок() 'Это одна специальная процедура

Picture1.Line (100, 100)-(300, 300), vbBlue, В

Picture1.Line (100, 100)-(300, 300), vbBlue

Picture1.Line (100, 300)-(300, 100), vbBlue

End Sub


Private Sub Рисуем_значок_друга() 'Это другая специальная процедура

Picture1.Circle (200, 200), 20

Picture1.Circle (200, 200), 70

Picture1.Circle (200, 200), 120

Picture1.Circle (200, 200), 170

End Sub


'Это новый текст программы:

Private Sub Command1_Click()

Picture1.Picture = LoadPicture("c: \temp\Rockies.bmp")

Рисуем_мой_значок Picture1.Print, "21.07.2001"

End Sub


Private Sub Command2_Click()

Picture1.Picture = LoadPicture("c: \temp\Porthole.bmp")

Рисуем_мой_значок Picture1.Print, "28.07.2001"

End Sub


Private Sub Command3_Click()

Picture1.Picture = LoadPicture("c: \temp\Balloons.bmp")

Рисуем_значок_друга Picture1.Print, "12.08.2001"

End Sub


Private Sub Command4_Click()

Picture1.Picture = LoadPicture("c: \temp\Guitar.bmp")

Рисуем_значок_друга Picture1.Print, "20.07.2001"

End Sub

Пояснение того же самого другими словами: У нас добавилось две процедуры. Каждая из этих процедур представляет собой цепочку операторов, из которых состоит упомянутый фрагмент. Сверху цепочки вы пишете заголовок процедуры (Private Sub…), а снизу — конечную строчку процедуры (End Sub). Все операторы, из которых состоит процедура, кроме заголовка и конечной строки, будем называть телом процедуры. Как только эти процедуры написаны, компьютер "узнает", что такое Рисуем_мой_значок и Рисуем_значок_друга. Поэтому в остальных процедурах слова Рисуем_мой_значок и Рисуем_значок_друга используются, как настоящие операторы, и выполняются, как настоящие операторы. Суть их выполнения в том, что когда Visual Basic во время выполнения программы натыкается на оператор Рисуем_мой_значок, он ищет в программе процедуру с именем Рисуем_мой_значок и выполняет тело этой процедуры, после чего возвращается к выполнению программы. Этот процесс называется вызовом процедуры или обращением к процедуре.

Обязательно выполните эту программу в пошаговом режиме! Обязательно обратите внимание, что после выполнения тела вызываемой процедуры (Рисуем_мой_значок) компьютер возвращается в вызывающую процедуру (Command1_Click) к выполнению оператора, следующего за оператором Рисуем_мой_значок (в нашем случае это оператор Print).

Две дописанные нами процедуры называются процедурами пользователя, в отличие от привычных нам процедур обработки событий. Их коренное отличие от последних в том, что вызываются они не наступлением каких-то событий, а упоминанием их имени в других процедурах. Процедуры пользователя и являются "процедурами типа "Как"".

Вы можете сами посчитать, насколько новая программа будет короче старой при де сяти фотографиях.


Есть еще один способ обратиться к процедуре. Вместо оператора

Рисуем_мой_значок

можно написать оператор

Call Рисуем_мой_значок

Смысл их совершенно одинаков. Вторым способом часто пользовались раньше. С английского слово "Call" переводится "Вызов".

Взаимодействие процедур в программе

Вызываемая процедура сама в процессе своей работы может вызвать какую-нибудь другую процедуру. И так далее. Потренируемся:

Определите без компьютера, что напечатает программа:

Private Sub Command1_Click()

Print 1;: A: Print 2;: В: Print 3;

End Sub


Private Sub A()

Print 4;

End Sub


Private Sub B()

Print 5;: С: Print 6;

End Sub


Private Sub С()

Print 7;

End Sub

Работать программа начинает по щелчку по кнопке Command1. Вряд ли вам с непривычки удасться дать правильный ответ. Тогда непременно программу — в компьютер и пошаговый режим. Желтая полоска будет скакать по программе туда-сюда. Перед каждым нажатием на F8 вы обязаны предсказать, куда она прыгнет! Не сможете — нет смысла читать книгу дальше.

Ответ:

1 4 2 5 7 6 3

Начинающим программистам не хочется писать процедуры пользователя, как не хочется им писать длинные имена и соблюдать отступы от левого края окна кода. "Наши программы отлично работают и безо всего этого". Верно, работают. Потому что программы коротенькие.

Запомните еще одно хорошее правило: Размеры любой процедуры не должны превышать одного экрана монитора. Если превышают, то даже если в ней нет повторяющихся фрагментов, все равно разбейте ее по смыслу на два-три фрагмента и каждый сделайте процедурой. Ваша программа будет гораздо легче читаться.

Задание 86: Дополните ваш фотоальбом процедурой пользователя, которая перед показом очередной фотографии воспроизводит один и тот же музыкальный звук, например, "c: \Windows\Media\Chimes.wav".

Операторы Stор,

End и Exit Sub

До сих пор мы писали процедуры, которые выполняли свою работу до конца и заканчивали ее только на операторе End Sub, не раньше. Существуют ли операторы, которые подобно операторам выхода из цикла Exit Do и Exit For заставляют компьютер покинуть процедуру, не доходя до ее конца? Такие операторы существуют.

Оператор End заставляет Visual Basic завершить работу не только процедуры, а всего проекта, не доходя до конечного End Sub. Пример: программа

Private Sub Command1_Click()

Print 1;: Print 2;: End: Print 3;

End Sub

напечатает 1 2. Правда, заметить это вы успеете только в пошаговом режиме, так как End завершает режим работы и проект мгновенно переходит в режим проектирования.

Ненавистник пошагового режима мог бы мечтать: "Хорошо бы существовал специальный оператор паузы, чтобы наткнувшись на него, компьютер приостанавливал выполнение программы, а мы могли бы спокойно посмотреть на результаты и подумать". Такой оператор есть, это Stop. Наткнувшись на него, компьютер переходит в режим прерывания и делает паузу до тех пор, пока вы снова не щелкните на кнопке Start. Тогда он продолжает работу с того места, где остановился. Вот вариант программы, при котором вы успеваете разглядеть результат:

Private Sub Command1_Click()

Print 1;: Print 2;: Stop: End: Print 3;

End Sub

Еще пример: программа

Private Sub Command1_Click()

Print 2;: A: Print 3;: End: Print 4;

End Sub

Private Sub A()

Print 6;: End: Print 7; End Sub

напечатает 2 6.

Оператор Exit Sub не такой решительный, как End. Он не выбрасывает Visual Basic из режима работы, а просто заставляет компьютер выйти из процедуры, в которой он выполнился. Если он выполнился в вызываемой процедуре, то Visual Basic возвращается в процедуру, ее вызвавшую. Если он выполнился в процедуре обработки события, то Visual Basic просто завершает работу этой процедуры.

Пример: Заменим в предыдущей программе оба End на Exit Sub:

Private Sub Command1_Click()

Print 2;: A: Print 3;: Exit Sub: Print 4;

End Sub

Private Sub A()

Print 6;: Exit Sub: Print 7;

End Sub

Эта программа напечатает 2 6 3.


Задание 87: Вот вам программа с процедурами. Вам нужно, не запуская ее, записать на бумажке весь разговор, который ведут герои "Трех мушкетеров".

Private Sub Command1_Click()

Print "Я, король Франции, спрашиваю вас — кто вы такие? Вот ты — кто такой? "

ATOS

Print "А ты, толстяк, кто такой?"

PORTOS

Print "А ты что отмалчиваешься, усатый?"

DARTANIAN

Print "Анна! Иди-ка сюда!!!"

Exit Sub


Print "Аудиенция закончена, прощайте!"

End Sub


Private Sub ATOS()

Print "Я — Atoc"

End Sub


Private Sub ARAMIS()

Print "Это так же верно, как то, что я — Арамис!"

End Sub


Private Sub PORTOS()

Print "А я Портос! Я правильно говорю, Арамис?"

ARAMIS

Print "Он не врет, ваше величество! Я Портос, а он Арамис."

End Sub


Private Sub DARTANIAN()

Print "А я все думаю, ваше величество — куда девались подвески королевы?"

Exit Sub

Print "Интересно, что ответит король?"

PORTOS

End Sub

Сверьте с ответом. Если не сходится, запустите программу в пошаговом режиме.

Теперь вы достаточно знаете о процедурах, чтобы они стали для вас удобными кирпичиками для постройки программ. Более мощным средством являются процедуры с параметрами, о которых вы сейчас узнаете.

Задание 88: В программе для задания 60 из 0 о продавце автомобилей есть два повторяющихся фрагмента. Сам бог велел сделать их процедурами.

Задание 89: Аналогичную вещь можно проделать для калькулятора


Переменные вместо чисел

Наша цель — процедуры с параметрами. Данный раздел — подготовка к взятию этой крепости.

Вернемся к задаче из о фотоальбоме со значками. Вспомним, что мы написали процедуру пользователя для рисования значка. Вот она:

Private Sub Рисуем_мой_значок()

Picture1.Line (100, 100)-(300, 300), vbBlue, В

Picture1.Line (100, 100)-(300, 300), vbBlue

Picture1.Line (100, 300)-(300, 100), vbBlue

End Sub

Значок рисуется в левом верхнем углу фото с отступом в 100 твипов как от левого края фото, так и от верхнего. Предположим, вам разонравился такой отступ и вы решили сделать его поменьше, скажем, 50. Вам нужно в программе в 6 местах поменять число 100 на 50. Вот то-то и неудобно, что в 6, а не в одном. Слишком много труда. В нашей программе это, конечно, пустяк, а вот в больших и сложных программах одна и та же величина может встречаться сотни раз, и чтобы ее изменить, придется вносить сотни исправлений.

Посмотрим, как нам помогут переменные величины. Придумаем переменную величину с именем Otstup. Теперь напишем вариант той же процедуры, но с использованием переменной величины:

Dim Otstup As Integer

Private Sub Рисуем_мой_значок()

Otstup = 100

Picture1.Line (Otstup, Otstup)-(300, 300), vbBlue, В

Picture1.Line (Otstup, Otstup)-(300, 300), vbBlue

Picture1.Line (Otstup, 300)-(300, Otstup), vbBlue

End Sub

Теперь для того, чтобы изменить отступ, достаточно заменить число только в одном месте.

Вторая причина, по которой мы используем переменные, та, что с ними программа становится понятнее, так как имена переменным мы придумываем, исходя из их смысла.

Будем дальше улучшать нашу процедуру. Теперь вы легко можете управлять отступом, но вот беда — правый нижний угол значка остается всегда в одном и том же месте и поэтому размер значка уменьшается с увеличением отступа, а при отступе = 300 значок вообще превращается в точку. Вам хочется так же легко и удобно управлять размером значка, как и отступом. Вы замечаете, что размер квадратного значка равен разнице координат в скобках операторов Line. Вы придумываете переменную с именем Razmer и переписываете программу:

Dim Otstup As Integer

Dim Razmer As Integer


Private Sub Рисуем_мой_значок()

Otstup = 100 Razmer = 200

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), vbBlue, В

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), vbBlue

Picture1.Line (Otstup, Otstup + Razmer)-(Otstup + Razmer, Otstup), vbBlue

End Sub

Последнее, что вам хочется, это управлять цветом. Нет проблем:

Dim Otstup As Integer

Dim Razmer As Integer

Dim Tsvet As Long


Private Sub Рисуем_мой_значок()

Otstup = 100 Razmer = 200 Tsvet = vbBlue

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), Tsvet, В

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), Tsvet

Picture1.Line (Otstup, Otstup + Razmer)-(Otstup + Razmer, Otstup), Tsvet

End Sub

Заметьте, что Tsvet я объявил, как Long, а то 16 миллионов в Integer не уместятся.

Задание 90: Помогите вашему другу менять при помощи переменных отступ, размер и цвет его значка.


Константы

Константами называются те конкретные значения величин, которые мы видим в программе. Например, во фрагменте

а = 1 + 0.25

b = "Амазонка"

Debug.Print "Волга", 10

Form1.BackColor = 15767511

If а > 3 Then Cls

константы это 1 0.25 "Амазонка" "Волга" 10 15767511 3.

Если какая-нибудь константа встречается в программе несколько раз, то удобно, как я уже говорил в предыдущем разделе, придумать ей имя и обозначать этим именем.

Вернемся к примеру из предыдущего раздела. Там мы объявили переменную Otstup и везде в процедуре стали писать вместо константы 100 имя этой переменной. Программист имеет право вместо оператора объявления

Dim Otstup As Integer

написать другой оператор объявления:

Const Otstup = 100

Тогда процедура изменит свой вид:

Const Otstup = 100

Private Sub Рисуем_мой_значок()

Picture1.Line (Otstup, Otstup)-(300, 300), vbBlue, В

Picture1.Line (Otstup, Otstup)-(300, 300), vbBlue

Picture1.Line (Otstup, 300)-(300, Otstup), vbBlue

End Sub

В чем разница? В первом случае величина Otstup — переменная величина. Во втором случае величина Otstup объявлена константой, а это значит, что ей запрещено менять свое значение 100, присвоенное ей при объявлении. При попытке изменить значение константы Visual Basic выдаст сообщение об ошибке. Например, ошибкой завершится выполнение такой программы:

Const а = 5

Private Sub Command3_Click()

а = а + 2

End Sub

Хорошо это или плохо? Это плохо там, где величина по смыслу задачи должна менять свое значение, и хорошо там, где не должна. Например, если в программе

Const Пи = 3.14

Private Sub Command4_Click()

r = 50

Длина_окружн = 2 * Пи * r

Площадь_круга = Пи * r л 2

End Sub

мы по небрежности где-нибудь напишем оператор типа Пи = 2.87, то Visual Basic выдаст сообщение об ошибке и мы будем этому рады, так как число Пи — очень известная константа, равная 3.14, и никто не имеет права менять ее значение.

Таким образом, при помощи объявления констант мы повышаем надежность программирования.

Обратите внимание, что термином "константа" мы обозначаем два близких понятия: с одной стороны число 100, строку "Волга" и т. п., а с другой стороны имена Otstup, Пи и т. п., обозначающие эти величины. Не думаю, что в будущем эта путаница принесет нам какой-нибудь вред.

Кроме перечисленных выше констант существует еще большое число так называемых внутренних констант Visual Basic. Объявлять их не надо, ими можно сразу пользоваться, если знать их имена и смысл. Например, такими константами являются названия цветов — vbRed, vbBlack и т. п. Каждая из таких констант имеет конкретное численное значение (например, vbRed=255), но названия запоминаются легче, чем числа. Имена, смысл и значение внутренних констант вы найдете в Object Browser.


Процедуры с параметрами

Процедуры с параметрами — мощный инструмент программирования и применяется программистами очень широко.

Вообразите, что вы решили фотографии разного с вашей точки зрения качества помечать значками разного отступа, размера и цвета, чтобы по значку легко было догадаться о качестве. Вот ваши предпочтения:



Но как это сделать? Ведь в процедуре Рисуем_мой_значок каждой из этих переменных присвоено одно единственное значение, поэтому, какую бы фотографию ни взять, значок всегда будет одинаковый. Можно было бы написать отдельную процедуру для каждого значка, но делать этого не хочется, потому что процедуры эти будут почти одинаковы. А тогда где экономия?

Выход есть. Заметим, что присваивать значения переменным не обязательно внутри процедуры Рисуем_мой_значок. Вот вариант программы, который будет работать:

Dim Otstup As Integer

Dim Razmer As Integer

Dim Tsvet As Long


Private Sub Рисуем_мой_значок()

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), Tsvet, В

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), Tsvet

Picture1.Line (Otstup, Otstup + Razmer)-(Otstup + Razmer, Otstup), Tsvet

End Sub


Private Sub Command1_Click()

Picture1.Picture = LoadPicture("c: \temp\Rockies.bmp")

'Фото неважное

Otstup = 100

Razmer = 200

Tsvet = vbBlue

'Рисуем_мой_значок

Picture1.Print, "21.07.2001"

End Sub


Private Sub Command2_Click()

Picture1.Picture = LoadPicture("c: \temp\Porthole.bmp")

'Фото хорошее Otstup = 200 Razmer = 400

Tsvet = RGB(100, 250, 150)

'Рисуем_мой_значок

Picture1.Print, "28.07.2001"

End Sub

Как видите, в процедуре Рисуем_мой_значок значения переменным не присваиваются, а присваиваются в процедурах, которые ее вызывают, причем присваиваются непосредственно перед вызовом. Убедитесь в пошаговом режиме, что все работает нормально.


Нормально-то нормально, да вот опять наша программа начала разбухать — в каждой вызывающей процедуре добавилось по три лишних строчки. За красивую жизнь приходится платить. Но и тут создатели языков программирования идут навстречу программистам. Имеется возможность вместо

Otstup = 100

Razmer = 200

Tsvet = vbBlue

Рисуем_мой_значок писать

Рисуем_мой_значок 100, 200, vbBlue

Все так и делают. Значения, идущие после имени процедуры через запятую, называются параметрами процедуры. Но откуда компьютер знает, что, например, Otstup = 100 и Razmer = 200, а не наоборот — Otstup = 200 и Razmer = 100? Компьютеру это объясняют в заголовке процедуры Рисуем_мой_значок, который теперь пишется по-другому:

Private Sub Рисуем_мой_значок (Otstup As Integer, Razmer As Integer,

Tsvet As Long)

Как видите, здесь задаются и порядок параметров и их тип.

Вот как компактно теперь выглядит наша программа. Это и есть ее окончательный вид, к которому мы стремились на протяжении этой главы:

Private Sub Рисуем мой значок (Otstup As Integer, Razmer As Integer, Tsvet As Long)

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), Tsvet, В

Picture1.Line (Otstup, Otstup)-(Otstup + Razmer, Otstup + Razmer), Tsvet

Picture1.Line (Otstup, Otstup + Razmer)-(Otstup + Razmer, Otstup), Tsvet

End Sub


Private Sub Command1_Click()

Picture1.Picture = LoadPicture("c: \temp\Rockies.bmp")

Рисуем_мой_значок 100, 200, vbBlue

Picture1.Print, "21.07.2001"

End Sub


Private Sub Command2_Click()

Picture1.Picture = LoadPicture("c: \temp\Porthole.bmp")

Рисуем_мой_значок 200, 400, RGB(100, 250, 150)

Picture1.Print, "28.07.2001"

End Sub

Обратите внимание, что мы убрали за ненадобностью фрагмент объявлений:

Dim Otstup As Integer

Dim Razmer As Integer

Dim Tsvet As Long

так как эти переменные уже объявлены в заголовке процедуры.

Наткнувшись в процессе выполнения программы на обращение к процедуре (Рисуем_мой_значок 100, 200, vbBlue), Visual Basic присваивает параметрам, приведенным в заголовке процедуры (Otstup, Razmer, Tsvet), указанные значения, а затем выполняет тело процедуры.

В качестве значений параметров в обращениях к процедурам можно писать не только константы, но и переменные, и выражения. Например, вместо Рисуем_мой_значок 100, 200, vbBlue можно было написать а=100

Рисуем_мой_значок а, 2 * a, vbBlue


Типы параметров

Параметры могут иметь не только числовой, но и строковый и многие другие типы. Пример:

Private Sub Печатаем_3_раза(Что_нибудь As String)

Print Что_нибудь

Print Что_нибудь

Print Что_нибудь

End Sub


Private Sub Command1_Click()

Печатаем_3_раза "Кто там? — Это почтальон Печкин!"

Печатаем_3_раза "Дядя Федор"

End Sub

Здесь вы видите процедуру пользователя Печатаем_3_раза и ее параметр — строковую переменную с именем Что_нибудь. При нажатии на кнопку Command1 программа начинает работать и печатает следующий текст:

Кто там? — Это почтальон Печкин!

Кто там? — Это почтальон Печкин!

Кто там? — Это почтальон Печкин!

Дядя Федор Дядя Федор

Дядя Федор

Вот другой пример. Для начала отметим, что величины, которые указываются в скобках функций (например, в Round (5.82716, 3) или LoadPicture("с: \temp\Rockies.bmp")), тоже называются параметрами, хотя их называют также аргументами. Здесь в функции LoadPicture адрес файла взят в кавычки, значит этот параметр является строкой. Можно написать такую программу, которая по нажатии на кнопку Command1 показывает сразу два фото:

Private Sub Показываем_два_фото (Фото_1 As String, Фото_2 As String)

Picture1.Picture = LoadPicture (Фото_1)

Picture2.Picture = LoadPicture (Фото_2)

End Sub


Private Sub Command1_Click()

Показываем_два_фото "с: \temp\Rockies.bmp", "c: \temp\Porthole.bmp"

End Sub

Теперь мы понимаем, зачем в конце заголовка процедуры ставится пара скобок (). Это для параметров, буде они объявятся.


Задание 91: В задании 86 из 0 вы написали процедуру пользователя, которая перед показом очередной фотографии воспроизводит один и тот же музыкальный звук. Пусть теперь перед каждой фотографией будет свой звук. Для этого напишите процедуру с параметром.

Задание 92: В задании 90 вы написали процедуру пользователя, которая рисовала значок вашего друга. Перепишите ее, сделав процедурой с тремя параметрами: отступ, размер и цвет значка.

Задание 93: Среди графических методов Visual Basic нет методов "крестик" и "треугольник". Вы можете возместить этот недостаток, написав две соответствующие процедуры с тремя параметрами: координата х, координата у, размер.

Задание 94: Представьте себе куб, собранный из 16777216 кубиков — по числу цветов в Visual Basic. Его высота — 256 кубиков, ширина и толщина — тоже по 256 кубиков. Каждый кубик покрашен в свой цвет. Цвета не повторяются. Систему раскраски придумать легко. Например, слева направо растет от 0 до 255 красная составляющая в цвете кубиков, сверху вниз — зеленая, от нас вдаль — синяя. Так что самый левый верхний ближний кубик получается абсолютно черным, а самый правый нижний дальний кубик — абсолютно белым. Сразу все кубики видеть мы, конечно, не можем, но мы можем делать срез куба в любом месте параллельно любой из его граней, в результате чего на срезе будем видеть квадрат, состоящий из 256*256 разноцветных квадратиков. Вот эту задачу среза я бы и хотел вам предложить. Программа предлагает пользователю выбрать один из трех основных цветов (это удобно сделать через меню) и его насыщенность (число от 0 до 255). Этим определяется место среза. Затем программа чертит на форме этот разноцветный срез. Конечно, квадратики получатся очень маленькими, но это ничего.

Указание: Используйте процедуру с двумя параметрами: выбранный пользователем цвет (один из трех) и его насыщенность.

Кстати, догадайтесь, из каких цветов составлена главная диагональ куба, проведенная между двумя упомянутыми мной кубиками.


РАБОТА С ТАЙМЕРОМ, ВРЕМЕНЕМ, ДАТАМИ

Мы с вами пока не умеем управлять временем. А это нам необходимо для работы с анимацией, а также для решения полезных и интересных задач.


Тип данных Date

Все вы видели часы в правой части панели задач Windows. Если на них поставить мышь, они покажут дату. Давайте сделаем что-нибудь получше, а именно — большие, красивые часы-будильник, а заодно и секундомер. Для этого нам нужно познакомиться с новым типом данных — типом даты и времени суток — Date. Вы пока знакомы с числовыми и строковым типами. Тип Date тоже, в принципе, числовой, но, сами понимаете, специфический. Если, например, в нем к 0:40 прибавить 0:40, то получится 1:20.

Когда вы пишете в окне кода программу, в ней встречаются числа, строки, а теперь вы должны научиться писать в программе дату и время суток. Чтобы Visual Basic понял, что перед ним число, вы просто пишете число, и он понимает. Чтобы Visual Basic понял, что перед ним строка, вы пишете строку и берете ее в двойные кавычки, и он понимает, что это строка. Чтобы Visual Basic понял, что перед ним дата или время суток, вы правильно записываете дату и время и заключаете их между значками #, и он понимает. Например, так: #2/16/2002#. Это 16 февраля 2002 года. Как правильно записывать дату и время в других случаях, вы поймете из примеров:

Dim D As Date

Dim T As Date

Dim DT As Date

Private Sub Command1_Click()

Debug.Print #6/25/2001# '25 июня 2001 года

Debug.Print #2:22:57 PM# '2 часа 22 минуты 57 секунд после полудня (РМ)

Debug.Print #2/28/1998 10:45:00 PM# '10 часов 45 минут вечера 28 февраля 1998 года

D = #12/25/2044#

Т = #2:00:32 AM# '2 часа 00 минут 32 секунды до полудня (AM)

DT = #1/15/2156 11:59:42 PM#

Debug.Print D, T, DT

End Sub

Эта процедура напечатает такие результаты:

25.06.01 14:22:57

28.02.98 22:45:00

25.12.2044 2:00:32 15.01.2156 23:59:42

Пояснения: Как видите, в окне кода мы обязаны писать дату и время по-американски, то есть месяц писать раньше числа и разделять все это косыми чертами, а в обозначении времени суток обязательно указывать до или после полудня было дело. А вот результаты по этим не нашим данным печатаются все равно по-нашему, вернее, так, как настроена Windows (а у большинства она настроена на Россию). Поэтому же, если вы захотите задавать дату или время компьютеру таким оператором:

D = InputBox("Введите дату")

то вводить ее по-американски нельзя и значки # тоже нельзя ставить.

Есть и другие способы задания дат и времени, но они сложнее и я их пропущу. Скажу только, что если присвоить переменной типа Date обычное число, то оно будет преобразовано в дату и время. Так, фрагмент D = 26.5 Debug.Print D напечатает следующее:

25.01.1900 12:00:00

Пояснения: Число 26.5 считается количеством суток (двадцать шесть с половиной), прошедших с полуночи 30 декабря 1899 года.

Учитывая вышесказанное, вы можете наладить сложение и вычитание дат и времени. Однако, лучше это делать с помощью специальных функций, которые мы сейчас и рассмотрим.

Функции для работы с датами и временем суток

Функция ∙ Результат

Debug.Print Date ∙ Печатается сегодняшнее число (то, что на панели задач Windows)

Debug.Print Time ∙ Печатается сколько сейчас времени

Debug.Print Now ∙ Печатается сегодняшнее число и сколько сейчас времени

Пусть D = # 2/14/2009 4:45:07 РМ # (это суббота), тогда:



Значением функции DatePart является число типа Integer, а не дата.

Все возможные значения строкового параметра для функций работы с датами приведены в последней таблице этого параграфа.



Пусть D1 = #2/14/2009 4:45:07 PM#, D2 = #2/16/2009 11:32:43 AM#, тогда:




Опасные операторы:



Значения строкового параметра для функций работы с датами:

Строковый параметр ∙ Смысл

YYYY ∙ Год

q ∙ Квартал в году

m ∙ Номер месяца в году

Y ∙ Номер дня в году

d ∙ Номер дня в месяце

w ∙ Номер дня в неделе (№ 1 — воскресенье)

ww ∙ Номер недели в году

h ∙ Час в сутках

n ∙ Минута в часе

s ∙ Секунда в минуте

Есть еще кое-какие функции, но пока вам хватит и этих.

Задание 95: Напишите программу, которая, ничего у вас не спрашивая, печатает, какое число будет через 52 недели.

Задание 96: Напишите одну-две строчки кода, которые, спросив у вас дату рождения и не спрашивая, какое сегодня число, печатают, сколько секунд вы живете на белом свете

Задание 97: Напишите программу, которая, спросив у вас дату рождения и не спрашивая, какое сегодня число и был ли у вас в этом году день рождения, печатает, сколько дней вам осталось до следующего дня рождения.

Задание 98: Я знаю, что високосных годов раз в четыре года ученым не хватает. Поэтому, не то где-то раз в много лет вклинивается лишний високосный год, не то иногда где-то в каком-то месяце бывает лишний день. Не знаю. Может быть Visual Basic подскажет?


Таймер

Создайте новый проект. Поместите на форму таймер. Установите его свойство Interval равным 10000. Сделайте двойной щелчок по таймеру. В появившуюся заготовку процедуры впишите одну строчку:

Private Sub Timer1_Timer()

Debug.Print "Процедура сработала"

End Sub

Запустите проект. Подождите немного. Через 10 секунд в окне Immediate появится строчка "Процедура сработала". Еще через 10 секунд появится такая же строчка, через 10 секунд еще одна, и так далее.

Если бы мы установили Interval равным 5000, то строчки появлялись бы каждые 5 с, а если равным 500, то — каждые 0.5 с.

Вывод: Таймер Timer1 — объект, вся работа которого заключается в том, чтобы через каждые Interval секунд создавать событие (импульс), которое запускает процедуру Timer1_Timer.

Таймеров в проекте может быть несколько. Все они работают независимо друг от друга и каждый имеет свою собственную процедуру, которая реагирует только на его импульсы.


Цикл без цикла

В процедуре Timer1_Timer мы можем написать все, что угодно. Например:

Dim i As Long

Private Sub Timer1_Timer()

Debug.Print "Процедура сработала", i

i = i + 1

End Sub

Установите Interval в 1000. Запустите проект. Вы увидите через каждую секунду возникающие строчки:

Процедура сработала 0

Процедура сработала 1

Процедура сработала 2

Процедура сработала 3

……………

Пояснение: Поскольку мы нигде не придали переменной i никакого значения, Visual Basic при первой встрече с ней в операторе Debug.Print посчитал ее равной 0. После первого выполнения процедуры Timer1_Timer переменная i стала равной 1, после второго — 2. И так далее.

Мы видим, что у нас заработал цикл, несмотря на то, что операторов цикла мы не писали! Чуть позже вы догадаетесь, как задавать начальные значения переменным цикла и вовремя делать выход из цикла.

Установим свойство таймера Enabled (по русски — "в рабочем состоянии") в False. Запустим проект. Никаких строк не появляется. Значит таймер выдает импульсы только тогда, когда свойство Enabled установлено в True.

Добавим в проект две кнопки. Допишем две процедуры:

Private Sub Command1_Click()

Timer1.Enabled = True

End Sub


Private Sub Command2_Click()

Timer1.Enabled = False

End Sub

Запустите проект. Вы увидите, что новые строчки начинают появляться только после щелчка по первой кнопке, а после щелчка по второй прекращают.

Что будет, если процедура Timer1_Timer еще не успела закончить работу, а от таймера уже пришел новый импульс? Проверим. Установим Interval равным 100, то есть импульсы от таймера должны посылаться примерно 10 раз в секунду. Напишем простую процедуру Timer1_Timer, которая очень долго работает:

Private Sub Timer1_Timer()

Debug.Print "Процедура таймера начала работу"

For i = 1 То 20000000: Next

Debug.Print "Процедура таймера закончила работу"

End Sub

Здесь долго работает пустой цикл For i = 1 То 20000000: Next. Несмотря на то, что делать ему нечего (тело у цикла отсутствует), у него много времени уходит на то, чтобы просто досчитать до 20 миллионов. На моем компьютере это занимает секунды две, на вашем, наверно, по-другому. Это неважно, а важно то, что за эти две секунды в процедуру врежется порядка 20 импульсов от таймера. И все как об стену горох — процедура на них не реагирует. Пока не завершит свою работу, как положено, оператором End Sub. После этого первый же следующий импульс, которому повезло, снова ее запускает. Вы увидите, что на экране не спеша, где-то раз в две секунды появляется очередная пара строчек.

Точность таймера невелика, а на интервалах меньше 1 секунды вообще никуда не годится. Не ждите, что если вы установили интервал равный 10, то в секунду будет послано 100 импульсов. Причина в том, что таймер вообще не способен выдавать больше 18 импульсов в секунду.

Задание 99: Запрограммируйте с помощью таймера печать чисел от 100 до 110 через 1 секунду.


ПРОЕКТ "БУДИЛЬНИК-СЕКУНДОМЕР"

Вы узнали о Visual Basic вполне достаточно, чтобы рваться в бой. Наверняка у вас в голове зреет идея создать некий элегантный и одновременно вполне "убойный" проект строчек на 200, но человек, мало-мальски разбирающийся в программировании, бросив скучающий взгляд на ваше жалкое детище, спросит: "Юноша, в каком году вы кончали церковно-приходскую школу?" И не потому, что проект работает плохо, он вполне может проделывать на экране что-нибудь любопытное. Но программа! Программа! В ней невозможно разобраться! 200 строк вы осилили, а сколько вы возились? Неделю? А веди могли все сделать за пару дней! Сколько у вас процедур? 8? А нужно было 40! И так далее. Когда придет пора делать проект из 1000 строк, вы не сможете его одолеть никогда!

Что же делать? Все очень просто. Вы ни в чем не виноваты. Ведь я пока только объявил вам, что надо писать много маленьких процедур. Но ведь не научил еще, как это делать правильно. А учиться надо на примерах.

Пришла пора создать проект, "правильно" составленный из процедур. Проект "Калькулятор", написанный нами ранее, не подходит в качестве учебного пособия, потому что логика его работы слишком проста: нажал кнопку — выполнилась соответствующая процедура и все. Нужна более сложная задача. Для ее решения мы создадим совсем небольшую программу из 80 строк, включающую 15 процедур. Поскольку создаваемая программа представляет для многих из вас неведомую страну, я буду применять метод изложения "за ручку", который я уже применял. Повторяйте за мной все, что я буду делать.

Начнем с постановки задачи.


Постановка задачи

Создать часы-будильник следующего вида:



В постановке задачи нужно с максимальной подробностью описать, что должен делать ваш проект с точки зрения пользователя (а не программиста!). Ввиду очевидности того, что изображено на картинке, я поясню только то, чего не видно или может быть неправильно понято:

На верхнем циферблате — текущее время суток (системное время Windows) в часах, минутах и секундах.

Под ним — дата и день недели (02.08.00 означает 2 августа 2000 года) Пользователь имеет возможность редактировать содержимое циферблата установки времени будильника.

При нажатии на кнопку "Выключить будильник" надпись на кнопке меняется на "Включить будильник", а надпись над циферблатом меняется на "Будильник отключен".

При срабатывании будильника раздается какая-нибудь продолжительная мелодия, которая замолкает при нажатии на кнопку "Выключить сигнал".

Секундомер измеряет время с точностью до 0.1 сек. На картинке вы видите секундомер в момент паузы. Если нажать на ПУСК, то отсчет времени продолжится с 1 минуты 15.4 сек, которые вы видите на картинке, а надпись на кнопке сменится на ПАУЗА. Если снова нажать на кнопку, цифры на секундомере снова замрут.

При нажатии на кнопку "Обнулить" секундомер сбрасывается в ноль и останавливается. На циферблате — 0:00:00.0.


Делим проект на части

Нельзя делать сразу весь проект одновременно. То есть было бы фатальной ошибкой сразу все нарисовать и пытаться все сразу программировать. Не пытайтесь ломать весь веник сразу, ломайте по прутикам. Надо разделить проект на части. Это не всегда легко. Некоторые проекты, особенно игры, представляют на первый взгляд единое неразрывное целое, так что нужен некоторый опыт, чтобы увидеть, "из каких кубиков построен домик". В нашем случае все более-менее просто. Три части просматриваются сразу, это

1. Часы (с датой и днем недели)

2. Будильник

3. Секундомер

Отлично! За какую из этих частей браться вначале? Для этого нужно сначала решить, зависят ли друг от друга отдельные части. Здесь очень пригодился бы некоторый опыт программирования. А если его нет, подойдет житейский опыт. Действительно, если бы вы мастерили будильник-секундомер из шестеренок, что бы в нем от чего зависело? Ну, ясно, что будильник не сработал бы без часов, ведь он должен чувствовать, когда время на циферблатах часов и будильника совпадает. А вот часы ходят и без будильника, они от него не зависят. Секундомер же, видимо, представляет собой полностью независимую часть со своим механизмом.

Итак, проект распался на две независимые части:

1. Часы и будильник

2. Секундомер

Какой частью заняться вначале? Дело вкуса. Часы с будильником попроще, поэтому начнем с них. Ну а между ними что выбрать вначале — часы или будильник? Здесь сомнения неуместны — раньше нужно делать ту часть, которая от другой не зависит — это часы.

Итак, мы разделили проект на части и определили порядок выполнения частей:

1. Часы

2. Будильник

3. Секундомер

Беремся за часы. И тут опять пошла дележка. Чем раньше заниматься — временем суток (будем называть это просто часами), датой или днем недели? Шестеренки смутно подсказывают нам, что дата переключается в полночь, а значит момент переключения зависит от часов. Значит дату будем делать позже часов. А день недели, ясно, определяется датой.

Итак, окончательная последовательность такая:

1. Часы (время суток)

2. Дата

3. День недели

4. Будильник

5. Секундомер

Лирическое отступление (утешение): Если вам не удалось разделить ваш проект на части, или вы чувствуете, что разделили неправильно, это не значит, что нужно от проекта отказываться. Программируйте напропалую! В процессе программирования отдельные части постепенно (не без мучений и многократных досадных переделок) встанут на свои места.

Ну что ж, "Задачи ясны, цели определены, за работу, товарищи!", как говорили при социализме[26].


Делаем часы

Создаем новый проект. Первым делом берем элемент управления Shape и рисуем вокруг будущего циферблата часов красивую рамочку. Если вы хотите сделать что-нибудь более выдающееся, чем скромная рамочка на картинке, и украсить часы необыкновенными шедеврами графики, то на здоровье, пожалуйста!. Но не сейчас. Потом. Когда все заработает. Иначе потонете в подробностях и не откопаете в золотых лепесточках нужную вам стальную шестеренку.

Я не дал объекту Shape1 никакого другого имени, потому что не собираюсь упоминать его в программе. Все свойства я ему установил в режиме проектирования и не хочу, чтобы рамочка как-то себя "вела" в режиме работы.

Внутрь рамочки я поместил текстовое поле для того, чтобы компьютер показывал в нем время. Для красоты я свойством BorderStyle убрал у него бордюрчик, а свойство Alignment настроил так, чтобы любой текст внутри поля располагался по центру. Настроил название, размер, стиль и цвет шрифта.

Дадим текстовому полю имя Циферблат_часов. Еще раз предупреждаю: не надо сокращенных имен типа Циф_час. Сэкономив сейчас копейку, вы потом проиграете рубль.


Пришла пора программировать. Прежде всего нужна идея, как сделать так, чтобы часы показывали текущее время. Мы знаем, что есть функция Time, значение которой в любой момент равно текущему времени. Стоит выполнить оператор

Циферблат_часов.Text = Time

и на часах оно будет. Попробуйте. Но как сделать, чтобы оно менялось? Нужно, чтобы этот оператор выполнялся не реже раза в секунду. Может быть, использовать оператор цикла? Но я должен вас предупредить, что на этом пути вас ждут разнообразные трудности, в суть которых не так-то легко вникнуть. Назову только одну. Вот, предположим, у вас заработал оператор цикла для часов. Тут вам захотелось включить секундомер. Значит, нужно, чтобы заработал другой оператор цикла — для секундомера. Значит, нужно выходить из цикла для часов. Так что же — часам останавливаться?

Ввиду вышеизложенного программисты для таких дел используют таймеры. Для часов свой, для секундомера свой.

Поместим на форму таймер и дадим ему имя Таймер_часов. Зададим ему интервал = 2500. Напишем такую программу:

Private Sub Таймер_часов_Тimег()

Циферблат_часов.Text = Time

End Sub

Запустите проект. Вы увидите, что часы показывают правильное время, но обновляется оно раз в две-три секунды. Зададим интервал = 100. В этом случае процедура будет выполняться около 10 раз в секунду и не пропустит момента смены системного времени. Проверьте.

Ну что, все! Часы готовы.


Занимаемся датой

Размещаем на форме рамочку и текстовое поле для даты. Даем полю имя Циферблат_даты. Чтобы там появилась дата, достаточно выполнить оператор

Циферблат_даты.Text = Date

Если его поместить в ту же процедуру таймера часов, то задача будет решена. Но мне жаль компьютер. 24 часа в сутки по 10 раз в секунду он будет спрашивать у Windows, какое нынче число, и стараться вывести в текстовое поле одну и ту же дату, хотя делать это нужно только два раза — при запуске проекта и в полночь. Здесь еще и вопрос экономии: бегая, как белка в колесе, компьютер тратит ресурсы (силы), нужные в это же время для другого дела, для того же секундомера хотя бы. Вспоминаем: при запуске проекта вырабатывается событие FormLoad, а полночь — это когда показания часов равны нулю. Ага. Дописываем программу:

Private Sub Form_Load()

Циферблат_даты.Text = Date 'Это чтобы дата появлялась на циферблате

при запуске проекта

End Sub


Private Sub Таймер_часов_Timer()

Циферблат часов.Text = Time

If Time = 0 Then Циферблат_даты.Text = Date 'Это чтобы дата меня

лась в полночь End Sub

Чтобы проверить, как работает проект, переставьте системные часы Windows на "Двенадцать без пяти". Только потом не забудьте переставить обратно.

Все работает, но мы начинаем допускать погрешности против правильного стиля программирования, которые в будущем могут выйти нам боком:

Первое. Показания часов напрашиваются быть переменной величиной. Ведь они нам еще понадобятся и для будильника. Мы их анализируем, а это лучше делать с переменной величиной, а не со свойством Циферблат_часов.Text или функцией Time. Поэтому придумаем переменную Время_на_часах, объявим ее, как имеющую тип Date и будем пользоваться только ей.

Второе. Как при запуске проекта, так и в полночь нам придется менять не только дату, но и день недели. Я предвижу повторяющийся фрагмент как минимум из двух операторов (пока это только один оператор Циферблат_даты.Text = Date). Поэтому оформим его, как процедуру с именем Смена_даты_и_дня_недели.

Третье. Поскольку у нас появились переменные, поручим Бэйсику при помощи оператора Option Explicit присматривать, не забыли ли мы какую-нибудь переменную объявить.

С учетом всего вышесказанного перепишем программу:

Option Explicit

Dim Время_на_часах As Date


Private Sub Form_Load()

Смена_даты_и_дня_недели End Sub

Private Sub Таймер_часов_Timer()

Время_на_часах = Time

Циферблат_часов.Text = Время_на_часах

If Время_на_часах = 0 Then Смена_даты_и_дня_недели

End Sub


Private Sub Смена_даты_и_дня_недели()

Циферблат_даты.Text = Date

End Sub

В этот момент вы совершенно искренне и с большим чувством можете сказать: "Ну зачем все эти усложнения? Ведь все и так работает!" В ответ на это я могу только отослать вас к началу раздела.


Занимаемся днем недели

Копируем объекты. Нам не хочется трудиться, размещая на форме, а потом еще и настраивая рамку и текстовое поле для дня недели. Замечаем, что они почти такие же, как для даты. Скопируем их, как это принято в Windows. Можно копировать по-отдельности, а удобнее вместе. Для этого обведите их рамочкой, при этом оба объекта выделятся, после чего скопируйте их хотя бы при помощи пунктов Copy, Paste меню Edit. Visual Basic при этом задаст вам про каждый объект вопрос, смысл которого вы поймете позже, а пока он вам не нужен. Отвечайте No.

Даем полю имя Циферблат_дня_недели. Чтобы там появился правильный день недели, нужно выполнить оператор

Циферблат_дня_недели.Text = WeekdayName(DatePart("w", Date, vbMonday))

Попробуйте разобраться в нем сами в качестве упражнения к функциям работы с датами. Если не удалось, то вот вам пояснение:

Сначала хорошенько еще раз разберитесь с функциями WeekdayName и DatePart из 0. А теперь нужно разобраться со скобками. Вы поняли, какая пара скобок к какой функции относится? Если нет, то я перепишу один оператор в два:

А = DatePart("w", Date, vbMonday)

Циферблат_дня_недели.Text = WeekdayName(A)

Здесь А будет равняться номеру дня недели (число от 1 до 7). Функция WeekdayName по номеру дня недели получает строковое название этого дня.

Раз мы организовали процедуру Смена_даты_и_дня_недели, то нам нет нужды вспоминать, в какие моменты времени проект должен менять день недели. Вставляем наш оператор в эту процедуру:

Private Sub Смена_даты_и_дня_недели()

Циферблат_даты.Text = Date

Циферблат_дня_недели.Text = WeekdayName(DatePart("w", Date, vbMonday))

End Sub

В качестве последнего штриха исправим одну неприятную вещь. Дело в том, что наши циферблаты совершенно беззащитны перед шаловливым пользователем. В режиме работы проекта вы можете щелкнуть мышкой внутри текстового окна и с клавиатуры безнаказанно как угодно менять его содержимое. Чтобы прекратить это, воспользуйтесь свойством Locked.

Итак, часы с датой и днем недели готовы.


Знакомимся с типом Boolean

Чтобы грамотно запрограммировать будильник, нам нужно познакомиться с новым типом переменных величин — Boolean. Это так называемый логический тип. Вы уже позакомились с логическими выражениями. Их главная черта в том, что они могут принимать всего два значения — True и False (истина и ложь). Логическая переменная величина отличается той же чертой. Объявляется она так:

Dim С As Boolean

А зачем она нужна, выяснится из следующего параграфа.

Делаем будильник

Поместим на форму все объекты, необходимые для будильника. Дадим им имена:

Meтка_будильника

Циферблат_будильника

Кнопка_включения_выкточения_будильника

Кнопка_выключения_сигнала

В циферблат занесем в режиме проектирования текст 12:00:00. Просто для того, "чтобы было".


Давайте пока забудем о кнопках, метках и прочих подробностях, а возьмем быка за рога и заставим будильник исполнять мелодию при совпадении времени на часах и на будильнике.

Вспомните, как вы занимались музыкой в "Калькуляторе". Поместите на форму Microsoft Multimedia Control 6.0 и дайте ему имя "Плеер". Для работы с мелодией нам нужно 5 операторов:

Плеер. DeviсеТуре = "Sequencer"

Плеер. FileName = "c: \Windows\Media\Canyon.mid"

Эти два достаточно выполнить один раз за время работы проекта при его запуске.

Плеер. Command = "Open"

Плеер. Command = "Play"

Эти два нужно выполнять каждый раз, когда нужно начать воспроизведение сигнала. А этот оператор:

Плеер. Command = "Close"

каждый раз, чтобы его закончить.

Вторая парочка, несмотря на то, что встретится в программе скорее всего только один раз, в глазах программиста просится стать процедурой. Здесь принцип такой: Если группа операторов (или даже один сложный оператор) представляет собой некое единое целое в том смысле, что решает какую-то свою задачу, то оформляйте ее процедурой. Это улучшит понятность и читабельность программы — один из важнейших факторов ее качества.

Вот как дополнился теперь наш проект (я показываю только те процедуры, которых коснулись дополнения):

Private Sub Form_Load()

Плеер. DeviceType = "Sequencer"

Плеер. FileName = "c: \Windows\Media\Canyon.mid"

Смена_даты_и_дня_недели

End Sub


Private Sub Таймер_часов_Timer()

Время_на_часах = Time

Циферблат_часов.Text = Время_на_часах

If Время_на_часах = 0 Then Смена_даты_и_дня_недели

If Время_на_часах = Циферблат_будильника.Text Then Включить_сигнал_будильника

End Sub


Private Sub Включить_сигнал_будильника()

Плеер. Command = "Open"

Плеер. Command = "Play"

End Sub

Запустите проект и установите время на циферблате будильника. Устанавливайте аккуратно, по одной цифре за раз. Не трогайте двоеточия. Почему — скажу чуть позже. Дождитесь, когда будильник зазвонит. Завершите работу проекта, не дожидаясь конца мелодии.


Пора заняться кнопками и меткой. Подумаем вот о чем. Во время работы проекта будильник в каждый момент времени может находиться в одном из двух состояний: установлен или не установлен. Компьютер должен в любой момент времени знать, в каком именно, чтобы принять решение — звонить или не звонить. В таких случаях, когда компьютер должен в любой момент что-то знать или помнить, программист всегда придумывает переменную величину, дает ей подходящее имя и тип и организует хранение в этой переменной нужной компьютеру информации. Так было у нас с переменной Время_на_часах, которая нужна была компьютеру для перестановки дат.

Придумаем переменную и дадим ей имя Будильник_установлен. Каким типом ее объявить? Для этого надо понять, а какие значения будет принимать эта переменная? По смыслу задачи значений два — "да" и "нет". Можно придать ей тип String, но хорошая практика программирования диктует тип Boolean. Вы скоро поймете, что он удобнее.

Теперь попробуем вообразить, что должно происходить при включении будильника. Нужно сообщить компьютеру, что будильник установлен.

Нужно, чтобы текст над циферблатом был такой: "Будильник установлен на: " Нужно, чтобы текст на кнопке был такой: "Выключить будильник".

В соответствии с этим пишем процедуру:

Private Sub Включить_будильник()

Будильник_установлен = True

Метка_будильника. Caption = "Будильник установлен на:"

Кнопка_включения_выключения_будильника. Caption = "Выключить будильник"

End Sub

Теперь попробуем вообразить, что должно происходить при выключении будильника:

Нужно сообщить компьютеру, что будильник не установлен

Нужно, чтобы текст над циферблатом был такой: "Будильник отключен"

Нужно, чтобы текст на кнопке был такой: "Включить будильник"

В соответствии с этим пишем процедуру:

Private Sub Выключить_будильник()

Будильник_установлен = False

Метка_будильника. Caption = "Будильник отключен"

Кнопка_включения_выключения_будильника. Caption = "Включить будильник"

End Sub

Теперь нам удивительно легко написать процедуру щелчка по кнопке включения-выключения будильника:

Private Sub Кнопка_включения_выключения_будильника_Click()

If Будильник_установлен Then Выключить_будильник Else Включить_будильник

End Sub

Обратите внимание, что благодаря удачному выбору имен и структуры программы язык программы по своей понятности приближается к естественному, человеческо-

Поскольку переменная Будильник_установлен имеет логическое значение True или False, ее можно использовать подобно функции IsNumeric в качестве условия оператора If. Поэтому совсем необязательно было писать If Будильник_установлен = True Then…

Процедуру щелчка по кнопке выключения сигнала приведу без пояснений:

Private Sub Кнопка_выключения_сигнала_Click ()

Плеер. Command = "Close"

End Sub

В последних четырех процедурах заключена вся механика работы кнопок и метки. Последнее, о чем надо позаботиться, это о том, чтобы будильник звенел только тогда, когда включен:

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Включить_сигнал_будильника

Будильник готов. Приведу полностью программу всего нашего проекта. Пока не обращайте внимания на строки, касающиеся секундомера.

Option Explicit

Private Enum типРежим_работы_секундомера

считает

пауза

в_нуле

End Enum

Dim Режим_работы_секундомера As типРежим_работы_секундомера

Dim Время_на_часах As Date

Dim Будильник_установлен As Boolean

Dim Время_на_секундомере As Single

Dim Время_запуска_секундомера As Single

Dim Время_на_паузе_секундомера As Single

Dim Цифра_десятых As Long


'НАЧАЛЬНАЯ УСТАНОВКА МЕХАНИЗМА

Private Sub Form_Load()

Плеер. DeviceType = "Sequencer"

Плеер. FileName = "c: \Windows\Media\Canyon.mid"

Смена_даты_и_дня_недели

Выключить_будильник

Секундомер_обнулить

End Sub


'ПРОЦЕДУРЫ РАБОТЫ ЧАСОВ

Private Sub Таймер_часов_Timer()

Время_на_часах = Time

Циферблат_часов.Text = Время_на_часах

If Время_на_часах = 0 Then Смена_даты_и_дня_недели

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Вкточить_сигнал_будильника

End Sub


Private Sub Смена_даты_и_дня_недели()

Циферблат_даты.Text = Date

Циферблат_дня_недели.Text = WeekdayName(DatePart("w", Date, vbMonday))

End Sub


'ПРОЦЕДУРЫ РАБОТЫ БУДИЛЬНИКА

Private Sub Кнопка_включения_выключения_будильника_Click()

If Будильник_установлен Then Выключить_будильник Else Включить_будильник

End Sub


Private Sub Включить_будильник()

Будильник_установлен = True

Метка_будильника. Caption = "Будильник установлен на:"

Кнопка_включения_выключения_будильника. Caption = "Выключить будильник"

End Sub


Private Sub Выключить_будильник()

Будильник_установлен = False

Метка_будильника. Caption = "Будильник отключен"

Кнопка включения выключения будильника. Caption = "Включить будильник"

End Sub


Private Sub Включить_сигнал_будильника()

Плеер. Command = "Open"

Плеер. Command = "Play"

End Sub


Private Sub Кнопка_выключения_сигнала_Сlick()

Плеер. Command = "Close"

End Sub


Private Sub Form_Terminate()

Кнопка_выключения_сигнала_Сlick

End Sub


'ПРОЦЕДУРЫ РАБОТЫ СЕКУНДОМЕРА

Private Sub Таймер_секундомера_Timer()

Время_на_секундомере = Timer — Время_запуска_секундомера + Время_на_паузе_секундомера

Цифра_десятых = Int(10 * (Время_на_секундомере Int(Время_на_секундомере)))

Циферблат_секундомера.Text = DateAdd("s", Время_на_секундомере, #12:00:00

AM#) & & Цифра_десятых

End Sub


Private Sub Кнопка_пуска_паузы_секундомера_С1ick()

If Режим_работы_секундомера О считает Then Секундомер_запустить Else Ceкундомер_остановить

End Sub


Private Sub Кнопка_обнуления_секундомера_Сlick()

Секундомер_обнулить

End Sub


Private Sub Секундомер_запустить()

Время_запуска_секундомера = Timer

Режим_работы_секундомера = считает

Таймер_секундомера. Enabled = True

Кнопка_пуска_паузы_секундомера. Caption = "ПАУЗА"

End Sub


Private Sub Секундомер_остановить()

Время_на_паузе_секундомера = Время_на_секундомере

Режим_работы_секундомера = пауза

Таймер_секундомера. Enabled = False

Кнопка_пуска_паузы_секундомера. Caption = "ПУСК"

End Sub


Private Sub Секундомер_обнулить()

Время_на_паузе_секундомера = 0

Режим_работы_секундомера = в_нуле

Таймер секундомера. Enabled = False

Кнопка_пуска_паузы_секундомера. Caption = "ПУСК"

Циферблат_секундомера.Text = "0:00:00.0"

End Sub

Обратите внимание, что при запуске проекта я в процедуре Form_Load выключаю для удобства будильник, а в процедуре Form_Terminate закрывается звуковой файл, если пользователь не удосужился закрыть его кнопкой. В ней мы обращаемся к процедуре обработки события Кнопка_выключения_сигнала_Click, как к процедуре пользователя. Это вполне допустимо.

Напоминаю, что событие Form_Terminate наступает только тогда, когда мы завершаем работу проекта, щелкнув по кнопке Close (крестику в правом верхнем углу формы), а не кнопкой End на панели инструментов.


Знакомимся с перечислимым типом данных

Чтобы грамотно запрограммировать секундомер, нам нужно познакомиться с новым типом переменных величин. Необходимость в нем в нашем проекте вытекает вот откуда. Если будильник в каждый момент времени может находиться в одном из двух состояний (установлен или не установлен), то секундомер — в трех: считает, стоит в паузе, стоит в нуле. Придумаем переменную и дадим ей имя Режим_работы_секундомера. Объявить ее типом Boolean явно недостаточно, ведь в типе Boolean всего два возможных значения, а нам нужно три. Можно придать ей тип String, но хорошая практика программирования диктует другое.

В Visual Basic нет типа данных, в котором переменная имела бы ровно три значения, зато Visual Basic, как и многие языки, позволяет программисту создавать собственные типы. Наша задача — создать тип, в котором переменная принимает ровно три значения: считает, пауза, в нуле — а затем объявить этим типом переменную Режим_работы_секундомера.

В нашем случае для создания такого типа достаточно записать выше процедур конструкцию:

Private Enum типРежим_работы_секундомера

считает

пауза

в_нуле

End Enum

Это не процедура, хоть и похожа. Слово Enum означает, что тип — перечислимый. Это означает, что мы обязаны были придумать и в этой конструкции перечислить имена всех возможных значений переменной этого типа, что мы и сделали. Поскольку каждый тип должен иметь свое имя (Integer, String…), нам тоже пришлось придумать имя новому типу (типРежим_работы_секундомера) и указать его в заголовке.

Теперь, когда новый тип определен, можно любую переменную объявить этим типом, что мы и делаем:

Dim Режим_работы_секундомера As типРежим_работы_секундомера

Замечание для новичков: Новички с трудом воспринимают смысл строк со стоящими рядом похожими именами, таких, например, как только что написанная. Новичку кажется, что эти имена означают одно и то же. Должен сказать, что профессиональные программисты специально обозначают близкие вещи похожими именами, им так больше нравится (можете себе вообразить?!). Например, у них может встретиться кнопка с именем сmdПодать_сюда_Ляпкина_Тяпкина и в этом же проекте переменная с именем strПодать_сюда_Ляпкина_Тяпкина. Для того, чтобы отличать одно от другого, они начинают каждое имя с префикса, который говорит программисту (не компьютеру!) о том, кому принадлежит имя (кнопке (префикс cmd), строковой переменной (префикс str) или кому-нибудь другому). Со временем вы поймете неизбежность такого подхода, а пока вам придется быть внимательным и не путать близкие имена.


Делаем секундомер

Поместим на форму элементы управления и дадим им имена:

Таймер_секундомера Циферблат_секундомера Кнопка_пуска_паузы_секундомера Кнопка_обнуления_секундомера а также не забудем метку и рамочку.

Будем использовать следующие переменные:

Dim Режим_работы_секундомера As типРежим_работы_секундомера

Dim Время_на_секундомере As Single

Dim Время_запуска_секундомера As Single

Dim Время_на_паузе_секундомера As Single

Dim Цифра_десятых As Long

Обратите внимание, что все переменные времени объявлены, как дробные числовые, а не как Date. Сейчас вам станет ясно, почему.

Давайте по порядку. Таймер нужен секундомеру для того же, для чего и часам, а именно — чтобы вовремя менялись цифры на циферблате, а собственный таймер нужен для того, чтобы не зависеть от часов. Поскольку нам нужно отслеживать десятые доли секунды, установим ему интервал поменьше, например 10 или 5 — не играет роли. Когда секундомер считает, таймер секундомера должен работать: Таймер_секундомера. Enabled = True

а когда он в паузе или в нуле, таймер должен стоять Таймер_секундомера. Enabled = False

Для отсчета времени на секундомере мы будем использовать известную вам функцию Timer (не путайте с элементом управления Timer), потому что она выдает с приемлемой для нас точностью десятые доли секунды (какой же секундомер без десятых). Поскольку она выдает число секунд, прошедших с полуночи, а нам нужно число секунд, прошедших с момента запуска секундомера, да еще с учетом того, что во время паузы на секундомере уже стояли какие-то показания, нам придется поразмыслить, как это сделать.

Засечем в момент пуска секундомера значение функции Timer оператором Время_запуска_секундомера = Timer

Тогда в каждый момент времени после запуска секундомера выражение (Timer — Время_запуска_секундомера) как раз и будет равняться числу секунд, прошедших с момента запуска секундомера. А если нам удастся правильно засечь Время_на_паузе_секундомера (выраженное в секундах, прошедших с момента пуска), то дело решит оператор

Время_на_секундомере = (Timer — Время_запуска_секундомера) + Время_на_паузе_секундомера

Если поместить его в процедуру таймера, то он будет оперативно выдавать нужное Время_на_секундомере. Задача решена.

Теперь займемся внешним видом показаний секундомера. Время_на_секундомере — это дробное число — количество секунд. Например, такое — 67,2. А нам хотелось бы получить его в таком виде — 00:01:07.2. Для этого нам нужно как-то преобразовать число секунд в стандартный формат времени. Дело решает оператор:

Циферблат_секундомера.Text = DateAdd ("s", Время_на_секундомере, #12:00:00 AM#)

Здесь время #12:00:00 AM# обозначает, как ни странно, полночь по-американски. Задача решена.

Но функция DateAdd оставляет за бортом десятые доли секунды. Попробуем выделить их из числа Время_на_секундомере. Для этого мысленно проведем такую цепочку операций с использованием функции Int:

Целая часть = Int (Время_на_секундомере)

Дробная часть = Время_на_секундомере — Целая часть Цифра_десятых = Int (10 * Дробная часть)

Сведем эти три оператора в один:

Цифра_десятых = Int(10 * (Время_на_секундомере

Int(Время_на_секундомере)))

и дополним оператор вывода времени на циферблат секундомера: Циферблат_секундомера.Text = DateAdd ("s", Время_на_секундомере, #12:00:00 AM#) & & Цифра_десятых

Здесь знак & является удобным заменителем знака + для сборки данных в одну строку. Я рекомендую пользоваться именно им, так как компьютер его уж никак не спутает со сложением чисел. Между целой и дробной частью секунд я решил поставить точку. Обратите внимание, что знак & без проблем соединяет данные трех разных типов: функцию DateAdd, строку и число Цифра_десятых.


Ну вот, пожалуй, и все объяснения. В остальном вы сможете разобраться сами, прочитав текст программы, так как ничего нового по сравнению с будильником не обнаружите.

После этого самые дотошные скажут мне, что нечего было огород городить — создавать новый тип данных, когда можно было обойтись логической переменной Секундомер_считает. Верно, но неправильно. Потому что нужно оставлять простор для дальнейшего развития проекта. Например, вы можете захотеть, чтобы во время паузы цифры на секундомере мигали, а в нуле — нет. Отличить одно состояние от другого вам и поможет переменная Режим_работы_секундомера.


Недостатки проекта

Мой проект работает на первый взгляд нормально, я проверял и часы, и будильник, и секундомер. Но делал я это не так тщательно, как положено при тестировании, поэтому в нем вполне возможны ошибки. Вот те, что я сумел заметить, но не стал исправлять, предоставив это вам:

В будильнике, если сигнал завершился сам, без нажатия кнопки "Выключить сигнал", то в следующий раз он не прозвучит, так как файл не закрыт. Справиться с этим недостатком вам поможет событие Плеер_Done, которое возникает при завершении воспроизведения мелодии. А можно, наверное, выкрутиться еще проще, как мы сделали в Калькуляторе.

В будильнике пользователь может изменять время сигнала, не дождавшись конца мелодии, что может привести к необходимости нового запуска мелодии, пока она еще не отзвучала. Здесь вам поможет событие Цифepблaт_бyдильникa_GotFocus.

Самое досадное то, что если вы во время установки времени будильника случайно хоть на мгновение сотрете двоеточие или напишете вместо цифры букву или как-нибудь по-другому нарушите правильный формат времени, то проект аварийно Завершит работу, потому что оператор (If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Включить_сигнал_будильника) не сможет понять, чему равно время Циферблат_будильника.Text. Здесь вам понадобятся средства, предотвращающие ввод в текстовое окно неправильных данных. Самое простое из них — функция IsDate, которая подобно функции IsNumeric определяет, можно ли считать ее аргумент правильным временем и правильной датой или это белиберда. Подумайте, вам вполне по силам справиться с этой проблемой.

В течение той секунды, когда время на часах и будильнике одинаково, процедура таймера выполняется с десяток раз, а значит и сигнал будильника запускается с десяток раз. Это нехорошо.

В циферблате даты месяц хорошо бы показывать не числом, а текстом.

Я не запускал секундомер в полночь.


Таймер и моделирование

Теперь о роли таймера в компьютерном конструировании поведения реальных механизмов. Заглянем-ка еще раз в процедуру таймера часов:

Private Sub Таймер_часов_Timer()

Время_на_часах = Time

Циферблат_часов.Text = Время_на_часах

If Время_на_часах = 0 Then Смена_даты_и_дня_недели

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Включить_сигнал_будильника

End Sub

Вы видите, что эта процедура является главным мотором, приводящим в движение весь механизм часов с будильником, главным штабом, планирующим всю их работу. Таймер, как сердце, несколько раз в секунду посылает импульсы, каждый из которых заставляет выполнится эту процедуру. А что за операторы составляют тело процедуры? Это как раз главные операторы проекта, которые, выполняясь, в свою очередь управляют выполнением вспомогательных процедур Смена_даты_и_дня_недели и Включить_сигнал_будильника. За один импульс таймера механизм совершает весь цикл своего функционирования с начала до конца и выполняет всю работу, которую положено выполнить: время на часах обновлено; если подошел момент, то именно на этом импульсе заменены дата и день недели; и если подошел момент, то именно на этом же импульсе отдан приказ на включение сигнала будильника. На следующем импульсе все повторяется. И так беспрерывно, бесконечно.

Этот принцип применения таймера подойдет для компьютерного конструирования работы бесчисленного множества других механизмов и аппаратов: холодильника, синтезатора, автоматической метеостанции, беспилотного космического аппарата и пр. и пр. Нужно только знать принцип их работы и вы сможете создать проект, "вживую" показывающий их деятельность на кухне или в космосе. Это называется моделированием. Вот, например, мы с вами создали модель будильника, которая настолько хороша, что работает не хуже оригинала. Однако, мы с вами не копировали работу реальных шестеренок бабушкиных ходиков, нам это было не нужно. Таким образом, нужно понимать, что мы создали модель только внешнего, а не внутреннего поведения механического будильника. Внутреннее поведение нашего будильника совсем другое.

Можно вполне моделировать и работу механизмов под управлением человека: автомобиля, корабля, самолета и др. В этом случае роль человека будете исполнять вы, щелкая мышкой по созданным вами кнопкам и рычагам управления автомобиля. Кстати, вы уже создали такой проект. Ведь будильник — это тоже механизм, работающий под управлением человека.

Задание 99-1: Это задание — на любителя. Его делать не нужно, если вы выполните проект "Шахматные часы" (см. ниже). Усовершенствуйте часы. Пусть они по вашему желанию показывают время в любом из нескольких десятков городов мира. Пользователю достаточно ввести название города в текстовое поле. Вам для программирования нужно самим знать поясное время в других городах. Для этого можете сделать двойной щелчок мышкой по индикатору времени на панели задач и в открывшемся окне загляните в список Time Zone. Основой для программирования можете сделать большой оператор Select Case. Будильник не должен обращать внимание на чужое время на циферблате, он все равно должен звонить по нашему местному времени.

Задание 99-2: "Шахматные часы". Это задание нужно сделать обязательно. По шахматным правилам шахматист не может думать над ходом бесконечно. На обдумывание первых, скажем, 40 ходов ему дается, скажем, 2 часа. Таким образом, партия, дошедшая до 41 хода, не может продолжаться дольше 4 часов. На следующие ходы тоже отводится какой-то лимит времени. Чтобы шахматисты могли следить за тем, сколько времени им осталось на обдумывание, существуют специальные шахматные часы. Они представляют собой единый корпус с двумя циферблатами — счетчиками времени, двумя кнопками и двумя флажками. Перед началом партии шахматистов А и В каждый счетчик показывает 2 часа. Пусть шахматисту А выпало начинать. Как только партия начинается, судья запускает счетчик А, который начинает обратный отсчет времени, уменьшая свои показания. Таким образом, в каждый момент партии счетчик показывает, сколько времени осталось шахматисту на обдумывание. Пока работает счетчик А, счетчик В, естественно, стоит. Как только шахматист А сделал ход, он тут же нажимает кнопку А, которая останавливает его счетчик и запускает счетчик В. За обдумывание принимается шахматист В. Сделав ход, он нажимает кнопку В, которая останавливает его счетчик и запускает счетчик А. И так далее. Если шахматист просрочит время, его флажок падает — он проиграл.

Для удобства шахматистов добавьте к часам счетчик ходов.


АНИМАЦИЯ

Анимация означает придание неподвижному предмету движения. Еще одно значение слова анимация — мультфильм.


Анимация при помощи графических методов

Я уже объяснил идею создания иллюзии движения картинок по экрану. Там же мы двигали по форме объекты. Попробуем заставить двигаться по экрану не объекты, а геометрические фигуры, полученные графическими методами. Пусть слева направо движется окружность. Для этого мы должны сначала нарисовать ее слева и быстро же стереть, для чего нарисовать ее на том же месте, но цветом фона. Несмотря на то, что мы окружность быстро стерли, она успеет мелькнуть на экране, и глаз это заметит. Затем нужно нарисовать и стереть такую же окружность чуть правее, затем еще правее и т. д.

Ввиду причин, упомянутых выше, откажемся от операторов цикла. Будем использовать таймеры. Создадим проект. Поместим в него таймер. Установим его интервал в любое число < 50, при этом он будет выдавать максимально возможное число импульсов в секунду — 18. Вот программа:

Dim х As Integer 'Координаты и радиус окружности

Dim у As Integer

Dim R As Integer

Dim Цвет_окружности As Long

Dim Цвет фона As Long


Private Sub Form Load()

х = 1000

у = 1500

R = 200

DrawWidth = 5 'Толщина линии

Цвет_окружности = vbBlack

Цвет_фона = BackColor

End Sub


Private Sub Timer1_Timer()

Circle (x, y), R, Цвет_окружности 'Рисуем окружность

For i = 1 To 500000: Next 'Пустой цикл для задания паузы

Circle (х, у), R, Цвет_фона 'Стираем окружность

х = х + 30 'Перемещаемся немного направо

End Sub

Пояснения: Когда вы попробуете выполнить эту программу на компьютере, изображение движущейся окружности может получиться некачественным — окружность в процессе движения будет мерцать и пульсировать. Это связано с разверткой электронно-лучевой трубки вашего монитора. Если создать маленькую паузу между рисованием и стиранием окружности, нежелательные эффекты сойдут на нет. Эту паузу я создаю пустым циклом. Поэкспериментируйте с радиусом, толщиной окружности, продолжительностью паузы или шагом движения по горизонтали. Последние две величины определяют скорость движения.

Задание 100: Пусть по экрану движется "вагон" — прямоугольник и два колеса.


Движем объекты

Мы больше не будем заниматься анимацией при помощи графических методов, потому что объекты двигать гораздо приятнее.

Поместим на форму объект Shape в виде той же окружности и таймер. Пусть окружность движется вверх. Программа:

Private Sub Timer1_Timer()

Shape1.Top = Shape1.Top — 20

End Sub

Как видите, она гораздо проще, чем программа анимации при помощи методов.

Задание 101: Пусть одновременно движутся две окружности. Таймер — один.

Задание 102: Одна вниз, другая направо.

Задание 103: Покажите своим друзьям фильм, снятый "секретной видеокамерой": В небе над вашим домом летит летающая тарелка. Для этого вам понадобится ввести в компьютер фотографию, на которой были бы видны ваш дом и небо. Роль летающей тарелки с успехом выполнит фигура эллипса с заливкой. Можете сделать ей окна (фигуры окружностей с желтой заливкой). Все эти фигуры должны лететь с одинаковой скоростью, не то окна "уплывут" с тарелки.

Заставим какую-нибудь фигуру двигаться направо, а затем самостоятельно отскочить от правого края формы:

Dim Шаг As Integer

Dim х As Integer


Private Sub Form_Load()

x = Shape1.Left

Шаг = 50

End Sub


Private Sub Timer1_Timer()

x = x + Шаг

Shapel.Left = x

If x > Width Then Шаг = -50 'Если фигура улетела за правый край формы, то лететь обратно

End Sub

Задание 104: Заставьте фигуру бесконечно двигаться, отскакивая от правого и левого краев формы.

Задание 105: "Биллиардный шар". Нарисуйте «биллиардный стол» — большой прямоугольник. Шар под углом летает по столу, отскакивая от его краев по закону отражения. Попав "в лузу" (любой из четырех углов стола), останавливается. Объектом здесь удобно взять Image с загруженной иконкой в виде шарика (подходящие иконки есть в Visual Basic).

Задание 105-1(сложное): "Часы со стрелками". Если вы в ладах с тригонометрией, сделайте часы со стрелками: часовой, минутной, секундной. Задача упростится, если вы выберете в качестве стрелок тоненькие сектора окружностей.

Задание 106: Изобразите полет камня, брошенного с башни, для задания 45 из 0. Напоминаю условие задания. Камень бросили горизонтально со 100-метровой башни со скоростью v=20m/c. Его расстояние от башни по горизонтали (s) выражается формулой s=v*t, где t — время полета камня в секундах. Высота над землей h выражается формулой h=100 — 9.81*t2/2. Нарисуйте башню, Землю. Камнем может служить Image с подходящей загруженной иконкой. Затем камень летит. Добейтесь, чтобы время полета камня на экране примерно соответствовало реальному времени, полученному при решении задания 45. Нарисуйте траекторию полета камня. Для этого достаточно, чтобы камень оставлял за собой следы в виде точек.

Указание: В задаче говорится о метрах, а на экране расстояние измеряется в твипах. Поэтому вам придется задать масштаб, то есть вообразить, что один твип равен, скажем, одному метру. Тогда высота башни будет равна 100 твипов, а скорость камня — 20 твипов в секунду Правда, картинка на экране в этом случае будет слишком маленькой. Тогда можете задать другой масштаб — 1 метр равен, скажем, 40 твипам. Тогда высота башни будет равна 4000 твипам, а формулы изменятся: s = 40*v*t и h=40*(100 — 9.81*t2/2).

Задание 107 (сложное): Сделайте игру: Пушка на экране стреляет в цель ядрами. С какого выстрела она поразит противника? Между пушкой и целью расположена небольшая гора. Перед началом игры случайно задается горизонтальная координата цели. Затем рисуется картинка.



Перед каждым выстрелом компьютер отображает в текстовом поле номер выстрела и запрашивает у человека стартовую скорость ядра v и угол а наклона ствола пушки к земле. Затем летит ядро. Полет ядра подчиняется двум уравнениям: s=v*t*cosa и h=v*t*sina — 9.81*t2/2 (см. предыдущее задание). Считается, что цель поражена, если ядро ее коснулось, не коснувшись горы. Указание: Вы можете запрограммировать автоматическое определение попадания в цель. Для этого нужно в момент, когда ядро при падении пересекло уровень земли, сравнить горизонтальные координаты ядра и цели. Если они достаточно близки, то фиксируйте попадание. Определение прикосновения к горе — более хлопотное занятие, но идея та же.


"Движем" свойства объектов

Сделаем рекламный ролик: Из черной глубины экрана на нас наплывают, увеличиваясь, красные слова "Съешьте Марс!"

Покрасим форму. Поместим на форму метку и сделаем ее большой и прозрачной. Придадим ее свойству Caption значение нужного текста. Сменим название шрифта на "Times" или какой-нибудь другой красивый, настроим стиль и цвет шрифта. Программа:

Private Sub Timer1_Timer()

Label1.FontSize = Label1.FontSize + 1

End Sub

Задание 108: Пусть текст также непрерывно меняет цвет.


Пусть теперь на нас надвигается, увеличиваясь в размерах, фото. Для этого придадим это фото объекту Image. Установив в True его свойство Strech, будем увеличивать размеры объекта, стараясь сохранять его пропорции:

Private Sub Timer1_Timer()

Image1.Width = Image1.Width + 10

Image1.Height = Image1.Height + 7

End Sub

Таким образом можно оживлять объект, меняя любое его свойство, имеющее численное значение.


Мультфильм

Когда мы снимаем видеокамерой идущего человека, то на разных кадрах у него разное положение ног. Когда мультипликаторы на студии создают мультик с идущим человечком, они карандашом и красками прорисовывают все кадры, а их много — по нескольку на каждую секунду фильма — адский труд.

Сейчас мы с вами создадим сверхпростой мультфильм, где вот такой вот человечек — >



идет по белой форме справа налево. Для создания приемлемой иллюзии ходьбы нам достаточно смены этих трех кадров. Я пронумеровал их справа налево.

Зайдите в графический редактор Paint и на белом фоне нарисуйте первый кадр. Вы можете сделать человечка гораздо красивее и подробнее, чем это сделал я. Если вы отлично работаете в солидном графическом редакторе, то можете даже взять фотографию вашего знакомого. Сохраните человечка под именем Кадр1. Теперь, не стирая человечка, измените ему положение ног и сохранитесь как Кадр2 (не Save, a Save as…). Аналогично создайте и сохраните Кадр3.

Теперь зайдите в Visual Basic. Сделайте форму белой. Поместите на форму куда-нибудь в сторонку три объекта Image. Каждому в качестве картинки придайте свой кадр. Теперь поместите на форму объект Image4. Наша идея — придавать объекту Image4 по очереди с достаточной скоростью картинки из трех других Image. Тогда мы увидим, что человечек в Image4 передвигает ногами. Менять кадры нужно в такой последовательности: 1-2-3-2-1-2-3-2-1-2-3-2-1-2-…. Если при этом объект Image4 будет еще и двигаться налево по белой форме, то результат будет приятным. Давайте-ка для дальнейшего понимания разобьем эту последовательность на одинаковые участки: 1-2-3-2-1-2-3-2-1-2-3-2-1-2-… Длина участка равна 4.

Поместите на форму таймер и придайте ему интервал 100 (потом, если движение будет слишком быстрым или медленным, вы его измените). Наша задача — сделать так, чтобы при каждом выполнении процедуры таймера мы видели один очередной кадр из приведенной мной последовательности. Для этого я организовал переменную N и заставил ее пробегать значения 0-1-2-3-0-1-2-3-0-1-2-… Как видите, длину участка на ней я подобрал тоже = 4. Сделайте три объекта Image невидимыми, чтобы не мешались. Вот программа:

Dim N As Integer


Private Sub Form_Load()

N = 0 'Начинаем с 0

End Sub


Private Sub Timer1_Timer()

Select Case N

Case 0 Image4.Picture = Image1.Picture

Case 1 Image4.Picture = Image2.Picture

Case 2 Image4.Picture = Image3.Picture

Case 3 Image4.Picture = Image2.Picture

End Select

N = N + 1 'Увеличиваем N на 1

If N = 4 Then N = 0 'После 3 должен идти 0, а не 4

Image4.Left = Image4.Left — 60 'Движем человечка налево

End Sub

Пару операторов N = N + 1

If N = 4 Then N = 0 можно заменить одним изящным оператором N = (N + 1) Mod 4

Вы можете как угодно улучшать мультик, например, пусть сзади человечка медленно едет автомобиль.

Задание 109: "Улыбка". Для тех, кто умеет рисовать. Попросите у своей знакомой ее фотографию, где она снята с серьезным выражением лица. Введите фото в компьютер. Сделайте в Paint, а лучше в FotoShop еще два-три кадра этого фото, аккуратно понемножку приподнимая уголки губ на изображении. Подумайте, в какой последовательности нужно показывать кадры, чтобы улыбка постепенно возникала и исчезала.


О прозрачном цвете

Конечно, вам бы хотелось, чтобы человечек шел не по белому экрану, а по улице (фотография улицы). Но здесь вы столкнетесь с проблемой: человечек будет обрамлен белым прямоугольником фона, в котором вы его рисовали. Хорошо бы можно было сделать белый (или любой другой) цвет прозрачным. Но это нетривиальная проблема и в курсе для начинающих ее не стоит решать.


РАБОТА С МЫШЬЮ И КЛАВИАТУРОЙ

До сих пор в режиме работы проекта мы пользовались мышкой только для того, чтобы примитивно нажимать на кнопки, а клавиатурой — только для ввода текста в текстовые поля. Однако, Visual Basic позволяет мышью и клавиатурой делать все те вещи, которые мы делаем ими в любых графических и текстовых редакторах, играх и других приложениях Windows. В том числе, мы можем с их помощью управлять поведением и движением объектов на форме.


Работа с мышью

Создадим программу на определение точности руки и глаза: При нажатии кнопки возникает в случайном месте экрана и тут же исчезает маленькая окружность. Вы должны поточнее щелкнуть мышкой там, где она была. После щелчка компьютер сообщает вам, на каком расстоянии от центра окружности было острие мышиного курсора во время щелчка.

Для создания программы нам необходимо поближе познакомиться с событиями, возникающими при работе с мышью. Заглянем в "универсальный справочник" Object Browser. Поскольку щелкать мышью мы будем над формой, то в левой части Object Browser выберем объект Form. В правой части отыщем события, связанные с мышью. Нас пока интересует пять событий: Click (щелчок), DblClick (двойной щелчок), MouseDown (нажали клавишу мыши), MouseUp (отпустили клавишу мыши), MouseMove (сдвинули мышь).

События Click и DblClick нам не подойдут, так как они ничего не говорят о координатах мыши во время щелчка. А вот MouseDown подойдет, так как координаты сообщает. А при щелчке события MouseDown и MouseUp обязательно наступают, так как любой щелчок это не что иное, как нажатие и отпускание.


События MouseDown и MouseUp

Зайдем в окно кода и выберем для объекта Form событие MouseDown. В окне кода появится следующая заготовка:

Private Sub Form_MouseDown (Button As Integer, Shift As Integer, X As Single, Y As Single)

End Sub

4 параметра в скобках — это 4 вещи, которые компьютер сообщает процедуре в момент события:

Button — какая из трех кнопок мыши была нажата

Shift — были ли при этом в нажатом состоянии служебные клавиши на клавиатуре и какие именно

X, Y — координаты острия курсора мыши во время нажатия

Для того, чтобы понять и проверить смысл этих параметров, прочтите (чтобы понять) и запустите (чтобы проверить) такую программу:

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)


'Определяем, какая клавиша мыши нажата:

Select Case Button

Case 1: Debug.Print "Нажата левая клавиша"

Case 2: Debug.Print "Нажата правая клавиша"

Case 4: Debug.Print "Нажата средняя клавиша"

End Select


'Определяем, какие из трех клавиш клавиатуры (Shift, Ctrl, Alt) были при этом в нажатом состоянии:

Select Case Shift

Case 0: Debug.Print "He нажата ни одна клавиша Shift, Ctrl, Alt"

Case 1: Debug.Print "Нажата клавиша Shift"

Case 2: Debug.Print "Нажата клавиша Ctrl"

Case 3: Debug.Print "Нажаты клавиши Shift, Ctrl"

Case 4: Debug.Print "Нажата клавиша Alt"

Case 5: Debug.Print "Нажаты клавиши Shift, Alt"

Case 6: Debug.Print "Нажаты клавиши Ctrl, Alt"

Case 7: Debug.Print "Нажаты клавиши Shift, Ctrl, Alt"

End Select


'Определяем координаты острия курсора мыши во время нажатия:

Debug.Print "Х="; X, "Y="; Y

End Sub

В численном значении Shift есть система. Посмотрите в процедуре, чему "равны" клавиши Shift, Ctrl, Alt по одиночке. 1, 2 и 4. Так вот, их совместное нажатие "равно" их сумме. Убедитесь.[27]

Поместите на форму несколько разных объектов. Обратите внимание, что при щелчке по ним процедура не срабатывает. Это естественно, у каждого объекта есть свое событие MouseDown.

Событие MouseUp работает аналогично.

Пример программы:

Вот программа для поставленной выше задачи на точность руки и глаза:

Dim Х_кружка As Integer

Dim Y_Kpy>KKa As Integer

Dim Расстояние_до_кружка As Double


Private Sub Form_Load()

Randomize

End Sub


'Процедура для создания мелькнувшего кружка:

Private Sub Command1_Click()

Х_кружка = 4000 * Rnd 'Определяем координаты кружка (центра кружка)

Y_кружка = 4000 * Rnd

ForeColor = vbBlack 'Чертим кружок черным цветом

Circle (Х_кружка, Y_кружка), 50

For i = 1 То 3000000: Next 'Пауза, чтобы мы успели заметить кружок

ForeColor = BackColor 'Стираем кружок цветом фона

Circle (Х_кружка, Y_Kpy>KKa), 50

End Sub


'Процедура для определения расстояния от щелчка до кружка:

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

Расстояние_до_кружка = Sqr ((X — Х_кружка) A 2 + (Y — Y_кружка)^2)

MsgBox ("Промах на " & Int(Расстояние_до_кружка) & " твип.")

End Sub

Пояснение того, как вычислялось расстояние (для тех, кто знает теорему Пифагора): Мысленно соедините отрезком прямой центр окружности и точку щелчка.

Это будет гипотенуза прямоугольного треугольника, катеты которого проведите вертикальной и горизонтальной линией. Нетрудно заметить, что горизонтальный катет равен X — Х_кружка, а вертикальный равен Y — У_кружка (знак я не учитываю). Гипотенуза же равна нужному нам расстоянию. Теорема Пифагора гласит, что квадрат гипотенузы равен сумме квадратов катетов. Отсюда, гипотенуза равна корню квадратному из суммы квадратов катетов (каковая формула и записана в программе).


Событие MouseMove

Это событие возникает, как только мы сдвигаем мышку с места, а во время движения мыши оно возникает постоянно и многократно. Оно похоже на событие MouseDown, но есть и отличия. Запустите и проверьте эту поясняющую программу:

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

'Определяем, какие клавиши мыши удерживаются нажатыми во время движения:

Select Case Button

Case 0: Debug.Print "He нажата ни одна клавиша мыши"

Case 1: Debug.Print "Нажата левая клавиша"

Case 2: Debug.Print "Нажата правая клавиша"

Case 3: Debug.Print "Нажаты левая, правая клавиши"

Case 4: Debug.Print "Нажата средняя клавиша"

Case 5: Debug.Print "Нажаты левая, средняя клавиши"

Case 6: Debug.Print "Нажаты правая, средняя клавиши"

Case 7: Debug.Print "Нажаты левая, правая, средняя клавиши"


'Определяем, какие из трех клавиш клавиатуры (Shift, Ctrl, Alt) удерживаются нажатыми во время движения:

Select Case Shift

Case 0: Debug.Print "He нажата ни одна клавиша Shift, Ctrl, Alt'

Case 1: Debug.Print "Нажата клавиша Shift"

Case 2: Debug.Print "Нажата клавиша Ctrl"

Case 3: Debug.Print "Нажаты клавиши Shift, Ctrl"

Case 4: Debug.Print "Нажата клавиша Alt"

Case 5: Debug.Print "Нажаты клавиши Shift, Alt"

Case 6: Debug.Print "Нажаты клавиши Ctrl, Alt"

Case 7: Debug.Print "Нажаты клавиши Shift, Ctrl, Alt"

End Select


'Определяем, координаты острия курсора мыши во время движения:

Debug.Print "Х="; X, "Y="; Y

End Sub

Если событие MouseDown сообщает о нажатии какой-то одной клавиши мыши, то MouseMove сообщает о любой комбинации мышиных клавиш. Если событие MouseDown сообщает о событии нажатия какой-то клавиши, то MouseMove сообщает о состоянии мышиных клавиш (удерживаются нажатыми или нет).


Мышь рисует

Вот программа, превращающая мышку в карандаш:

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

PSet (X, Y)

End Sub

Запустите ее и медленно ведите мышкой по форме. За мышкой остается нарисованный след.

Задание 110: Сделайте так, чтобы мышь рисовала только при нажатой левой клавише, что более привычно для всех, кто работал в графических редакторах.

Задание 111: Сделайте так, чтобы при щелчке по правой клавише толщина линии возрастала на 1.


Работа с клавиатурой

Поставим задачу сделать игру, где наш миниатюрный гоночный автомобиль будет под управлением клавиш клавиатуры нестись от старта до финиша. Для этого вам нужно познакомиться с событиями, связанными с клавиатурой. Их три: KeyDown (клавиша нажата), KeyUp (клавиша отпущена) и KeyPress.(по клавише щелкнули). Нас пока интересуют только первые два.


События KeyDown и KeyUp

Создайте проект из одной формы, без элементов управления. Зайдите в окно кода и выберите для объекта Form событие KeyDown. В появившуюся заготовку процедуры запишите следующий код:

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

'Определяем, какая клавиша клавиатуры была нажата:

Select Case KeyCode

Case vbKeyUp: Debug.Print "Нажата стрелка вверх"

Case vbKeyDown: Debug.Print "Нажата стрелка вниз"

Case vbKeyLeft: Debug.Print "Нажата стрелка налево"

Case vbKeyRight: Debug.Print "Нажата стрелка направо"

Case vbKeyW: Debug.Print "Нажата клавиша W"

Case vbKey7: Debug.Print "Нажата клавиша 7"

Case vbKeySpace: Debug.Print "Нажата клавиша пробела"

Case vbKeyDelete: Debug.Print "Нажата клавиша Delete"

Case vbKeyF4: Debug.Print "Нажата клавиша F4"

Case vbKeyAdd: Debug.Print "Нажата клавиша +"

Case vbKeyEscape: Debug.Print "Нажата клавиша Esc"

End Select


'Определяем, какие из трех клавиш клавиатуры (Shift, Ctrl, Alt) при этом были в нажатом состоянии:

Select Case Shift

Case 0: Debug.Print "He нажата ни одна клавиша Shift, Ctrl, Alt

Case 1: Debug.Print "Нажата клавиша Shift"

Case 2: Debug.Print "Нажата клавиша Ctrl"

Case 3: Debug.Print "Нажаты клавиши Shift, Ctrl"

Case 4: Debug.Print "Нажата клавиша Alt"

Case 5: Debug.Print "Нажаты клавиши Shift, Alt"

Case 6: Debug.Print "Нажаты клавиши Ctrl, Alt"

Case 76 Debug.Print "Нажаты клавиши Shift, Ctrl, Alt"

End Select

End Sub

Два параметра в скобках заголовка процедуры — это две вещи, которые компьютер сообщает процедуре в момент события:

KeyCode — код нажатой клавиши. На клавиатуре — сто с лишним клавиш. На каждой — по две буквы или один, два, три других символа. Компьютер различает клавиши независимо от того, какие значки на них нанесены. Так мать различает сыновей независимо от того, что написано у них на майках. У каждого сына есть имя, у каждой клавиши есть код (KeyCode). Итак, попросту говоря, компьютер сообщает процедуре, какая клавиша была нажата. Полный список кодов находится в Object Browser (класс KeyCodeConstants).

Shift — были ли при этом в нажатом состоянии клавиши клавиатуры (Shift, Ctrl, Alt) и какие именно. В численном значении Shift та же система, что и в событии MouseDown. Совместное нажатие клавиш Shift, Ctrl, Alt "равно" сумме их нажатий по-одиночке (1, 2 и 4).

Запустите проект и проверьте, как работает программа. Обратите внимание, что при удержании клавиш в нажатом состоянии событие генерируется (создается компьютером) несколько раз в секунду. Положение несколько меняется, когда при нажатой Shift, Ctrl или Alt щелкается обычная клавиша. Впрочем, пока это неважно.


События, связанные с клавиатурой, имеются у многих объектов. Поместим на форму, к примеру, пару кнопок и текстовое поле. Предположим, процедуру Private Sub Form_KeyDown мы стерли, а написали три процедуры:

Private Sub Command1_KeyDown…

Private Sub Command2_KeyDown…

Private Sub Text1_KeyDown…

Запустим программу и щелкнем по какой-нибудь клавише. Какая из трех процедур сработает? Та, чей объект находится в фокусе. Для нашей игры это неудобно: если мы для программирования реакции автомобиля на нажатия клавиш выберем, например, процедуру Private Sub Command2_KeyDown, то во время гонки мы не сможем щелкать по другим кнопкам, кроме Command2, так как иначе Command2 выйдет из фокуса и автомобиль перестанет реагировать на клавиши. Не надо было стирать процедуру Private Sub Form_KeyDown, восстановим ее. Но это не помогает. По простой причине — один какой-нибудь объект на форме всегда находится в фокусе, так что до процедуры Private Sub Form_KeyDown дело никак не доходит. Против этого в Visual Basic есть специальный прием — свойство формы KeyPreview устанавливается в True. Это означает приказ компьютеру почти каждое нажатие на клавиши считать событием формы, а не другого объекта. Вдобавок к этому советую поместить в самый конец процедуры Private Sub Form_KeyDown оператор KeyCode=0. Тоже хорошо помогает (без комментариев).

Что значит "почти каждое нажатие"? Есть исключения — клавиши Enter, Esc, Tab в некоторых случаях.

Событие KeyUp работает аналогично.

Задание 112. "Светофор": Нарисуйте светофор: прямоугольник и три круга. При нажатии на клавиатуре клавиши R светофор должен загораться красным светом, G — зеленым, Y — желтым. Здесь таймер не нужен.

Задание 113. "Зенитка": Вверху справа налево медленно движется вражеский самолет. В подходящий момент вы нажатием любой клавиши запускаете снизу вверх зенитный снаряд. Здесь нужны два таймера.


ПРОЕКТ — ГОНКИ (ИГРА)

Мы с вами разобрали уже два больших проекта: "Калькулятор" и "Будильник".

Но "Калькулятор" можно не считать, на нем мы просто знакомились с Visual Basic. Выходит, "Будильник" — единственный большой проект, который написан более-менее правильно. И этого, конечно, мало. Вам нужен опыт создания проектов, в частности проектов с движением объектов по форме, да к тому же под управлением мыши и клавиатуры. Поэтому я решил разобрать с вами еще один проект (строк на 180). На этот раз это будет игра.


Постановка задачи

Вот внешний вид игры (о красотах я не заботился, красоты вы всегда сможете добавить по вкусу):



Процесс игры таков. Вы нажимаете на кнопку Начинаем сначала. На форме рисуется квадратное поле для гонки со случайно расположенными газонами. Нажатием на клавишу пробела вы даете газ и машина со старта набирает скорость. Ваша цель — любым путем побыстрее добраться до финиша. На белом асфальте вы можете газовать до любой скорости. Если же ненароком попадете на газон, то на газоне ваша скорость будет очень мала (я выбрал 15). Поэтому имеет смысл по газонам ездить пореже. Направление движения может быть только горизонтальное и вертикальное, наискосок машина не движется. Выбор направления (руль) — это клавиши со стрелками. Тормоз — клавиша В (английская). Тормозить надо по той причине, что на слишком большой скорости руль отказывает (это не потому, что проект плохой, а потому что я так придумал). В ограждение врезаться нельзя — катастрофа. Когда приедете на финиш, посмотрите на счетчик времени — это ваш результат. Снова нажимаете на кнопку Начинаем сначала. Теперь расположение газонов будет другим. Сажайте за клавиатуру приятеля и смотрите, не покажет ли он время лучшее, чем ваше. Можете посмотреть, кто из вас покажет лучшее время из 10 заездов. И тому подобное.

Не удивляйтесь, что скорость на спидометре не равна пути, деленному на время. Ведь это мгновенная (то есть настоящая скорость в данное мгновение), а не средняя скорость автомобиля (см. Физика, 9 класс).

Все эти правила я старался сделать как можно проще, чтобы не усложнять проект. Разобравшись в проекте, вы всегда сможете дописать процедуры, делающие процесс гонки более для вас привлекательным.

Для проекта я выбрал вариант игры с одним автомобилем. Я вам намекну, как модифицировать проект, чтобы получилась игра с двумя автомобилями. Однако помните, что для грамотного создания игры с несколькими автомобилями вам нужно будет подняться на новый уровень программирования — научиться создавать собственные классы объектов.


Делим проект на части

Начнем создавать проект. Прежде всего, как положено, разделим его по возможности на части. Мы уже делили проект на части, когда создавали будильник. Сейчас вам очень полезно перечитать тот материал. И проглядеть ту программу.

Сразу же бросается в глаза, что наша задача распадается на две последовательные почти независимые части:

Сначала рисование поля и всех его элементов, выкатывание машины на старт, обнуление скорости, времени и пути — в общем, все то, что должно быть сделано после нажатия на кнопку Начинаем сначала, но до начала движения. Этим будет заниматься одна группа процедур.

Затем управление машиной и событиями во время гонки. Этим будет заниматься другая группа процедур. Мы полностью задействуем идею использования таймера, так, как я ее изложил в 0. На каждом импульсе таймера автомобиль должен будет проделывать весь цикл своего функционирования.


Первая часть

Поскольку в первой части нет движения, то, в общем, все равно, что именно рисовать сначала, что потом, но и здесь следование житейской логике дает некоторую экономию кода и смысла:

• Сначала нарисуем большой квадрат поля (ограждение), затем

• Рисуем старт

• Рисуем финиш

• Рисуем газоны

• Ставим машину на старт и обнуляем показания приборов

В общем, идеология первой части ясна. Пора разбираться в полном тексте программы, приведенном ниже. Здесь вам бы очень помогло, если бы программа уже находилась в вашем компьютере. Вам было бы легко и приятно в такт моим словам нажимать клавишу F8.

Начнем сверху. Разберитесь в объявленных переменных, не вникая пока в те, что относятся к движению.

Разобрались? Теперь идем дальше. Первая процедура, которая выполняется в проекте, это, конечно, Form Load. В каждом проекте в ней удобно программировать все действия и вычисления, которые нужно выполнить один раз за все время работы проекта, в самом начале. В нашем случае это в основном задание и вычисление значений переменных величин — размеров элементов поля игры. Кое-что здесь нуждается в пояснении:

Windowstate — это не переменная, а свойство формы. Вы помните, что свойства формы, в отличие от свойств других объектов, можно писать, не указывая хозяина (Form1.WindowState).

ScaleLeft и ScaleTop. Это тоже свойства формы. Мы их устанавливаем, если нам не нравится, что начало системы координат находится в левом верхнем углу формы. ScaleLeft занимается смещением начала координат по горизонтали, ScaleTop — по вертикали. Примеры:

Оператор ∙ Смысл

ScaleLeft = 1000 ∙ Начало системы координат смещается налево на 1000 твипов

ScaleLeft = -500 ∙ Начало системы координат смещается направо на 500 твипов

ScaleTop = 800 ∙ Начало системы координат смещается вверх на 800 твипов

ScaleTop = -500 ∙ Начало системы координат смещается вниз на 500 твипов

В нашем проекте мы, конечно, могли бы обойтись и без этого, но многие операторы рисования у нас запишутся гораздо проще, если начало координат находится в левом верхнем углу поля игры, а не формы.

Все числа, которые встречаются в программе, я подобрал на опыте, исходя из размеров экрана и быстродействия своего компьютера. Вы можете эти числа изменить и посмотреть, что получится.

После выполнения процедуры Form_Load вы видите распахнутую на весь экран пустую форму с четырьмя текстовыми полями, тремя метками и кнопкой, ждущей нажатия. После щелчка по этой кнопке должна в полном объеме выполнится первая часть нашего проекта, так, как она описана выше. Заглянем в процедуру Кнопка_начинай_сначала_Click.

Здесь процедуры рисования ограждения, старта и финиша ясны без пояснений. Поясню процедуру Рисуем_газоны. Вы видите, что некоторые переменные я объявил внутри процедуры. Так поступают, когда знают, что значения этих переменных нигде, кроме как в этой процедуре, не нужны. Значения чисел и вид формул для Х_газона и У_газона я выбрал так, чтобы газоны не накладывались ни на ограждения, ни на старт с финишем.

Процедуру Ставим_машину_на_старт я поясню во второй части, так как она больше относится к ней.

Оператор Спидометр. SetFocus, появился вот почему. При запуске проекта фокус автоматически устанавливается на кнопку "Начинаем сначала". Кнопка в фокусе перехватывает нажатия на стрелки, в результате чего первое нажатие во время гонки на клавишу со стрелкой приводило не к выбору направления машиной, а к перескакиванию фокуса с кнопки на другой объект формы. Оператор Спидометр. SetFocus просто увел фокус с кнопки.

Вот, в общем, и все, что касается первой части. После ее выполнения мы увидим все, что нужно для старта, процедура Ставим_машину_на_старт поставит машину на старт, мотор будет заведен, вам останется только коснуться руля или педалей, чтобы началась часть вторая. Перейдем к ней.


Вторая часть

Если с первой частью все просто, то про вторую стоит поговорить подробнее.

Фактически, нам нужно будет создавать автомобиль, как раньше мы создавали будильник. Не имея программистского опыта, мы попытаемся использовать житейский опыт касательно того, как автомобиль устроен. Причем применительно к задачам проекта. Так, цвет сиденья нам не очень важен в этом смысле. А важно нам управлять скоростью и направлением движения (этим в обычном автомобиле занимаются руль и педали газа и тормоза). А еще важно, чтобы автомобиль чувствовал, "куда он въехал" (газон, ограждение, финиш) и вел себя соответственно.

Итак, на каждом импульсе таймера автомобиль должен будет проделать весь цикл своего функционирования:

Определить, где он находится (асфальт, газон, ограждение, финиш) и действовать соответственно.

Изменить или не изменить скорость в соответствии с приказами клавиатуры.

Изменить или не изменить в соответствии с приказами клавиатуры направление движения и сделать очередной шаг в нужном направлении.

Изменить нужным образом показания приборов на пульте управления.

Но прежде, чем заниматься всем этим, давайте возьмем быка за рога и сразу посмотрим, как с клавиатуры примитивно управлять движением автомобиля.

Создайте отдельный пустой проект и поместите на форму объект Image. Дайте ему имя Image_авто. Чтобы он был виден в режиме работы, придайте значение его свойству BorderStyle. Он будет слушаться клавиш со стрелками при помощи такой программы:

Dim х As Integer 'Горизонтальная координата

Dim у As Integer 'Вертикальная координата


Private Sub Form_Load()

x = Image_авто. Left

у = Image_авто. Top

End Sub


Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

Select Case KeyCode

Case vbKeyRight: x = x + 100

Case vbKeyLeft: x = x — 100

Case vbKeyDown: у = у + 100

Case vbKeyUp: у = у — 100

End Select

Image_авто. Left = x

Image_авто. Top = у

End Sub

Эта программа только иллюстрирует идею, но для проекта она не годится. Во-первых, потому, что для непрерывного движения объекта необходимо клавишу держать все время нажатой, что создает трудности при обработке нажатия в это время других клавиш. Во-вторых, сложные проекты с таймерами всегда должны помнить, куда они едут, а для этого нужна переменная величина. Есть и другие причины.

Создадим переменную, назовем ее Руль и сделаем перечислимой (см. объявления в тексте программы). Она выполнит предназначенную ей роль — помнить, куда мы едем. Создадим также перечислимую переменную Педаль (см. там же). Она будет хранить информацию о том, нажали ли мы педаль газа, тормоза или вообще на педаль не нажимали. Теперь разберемся с процедурой Form_KeyDown. Вы видите, что переменная Руль будет чувствовать нажатие на стрелки только тогда, когда скорость движения автомобиля меньше пороговой. О том, что на педали пока не нажимали, сообщает компьютеру процедура Ставим_машину_на_старт. Именно поэтому после нажатия кнопки Начинаем сначала машина сама не срывается со старта, несмотря на работающий мотор. Оператор Клавиатура_сработала = True нужен для того, чтобы запустить счетчик времени

If Клавиатура_сработала Then Время = Время + 1

в процедуре Отображаем_информацию).


Итак, при нажатии нужных клавиш меняются значения нужных переменных. Но дела никакого не происходит. О деле чуть позже, а сейчас давайте подумаем, как сделать так, чтобы автомобиль глядел в ту же сторону, куда он едет. Есть всего 4 направления движения, значит и 4 ориентации автомобиля. Нужно всего лишь взять 4 картинки автомобиля с разной ориентацией и вовремя их менять. Откуда взять картинки? Нарисовать одну в графическом редакторе, а там ее легко поворачивать в нужном направлении и сохраняться. Сохранитесь в 4 файлах. Если вы не хотите рисовать, возьмите из папки с иконками Visual Basic, о которой я уже говорил, 4 иконки в виде стрелок, направленных в разные стороны. Вот вам и автомобиль.

Затем поместите на форму 4 объекта Image, дайте им имена Image_вверх, Image_вниз, Image_налево, Image_направо и придайте им соответствующие картинки. Чтобы эти объекты не мозолили глаза, сделайте их невидимыми. Вся механика будет заключаться в том, что когда вы нажимаете на клавиатуре стрелку вверх, должен выполняться оператор

Image_авто. Picture = Image_вверх. Picture

а когда вниз — то оператор

Image_авто. Picture = Image_вниз. Picture

И так далее.

Теперь можно разбираться в тексте процедур.


Мы с вами чуть выше определили четыре вещи, которые должен проделать автомобиль на каждом импульсе таймера. Посмотрите в процедуру Timer1_Timer и найдите там обращения к соответствующим процедурам. Из них нас сейчас интересует процедура Выбираем_куда_ехать_и_делаем_шаг. Именно она задает направление движения. Загляните в нее. Ее дело — чувствовать одно из 4 значений переменной Руль и запускать соответствующую из 4 процедур. Каждая из этих процедур делает две вещи: поворачивает машину в нужном направлении и меняет в этом направлении ее координату. Само же изображение автомобиля прыгнет на указанную координату чуть позже — во время выполнения процедуры Показываем_автомобиль.

Теперь посмотрим, как регулируется скорость. Прежде всего, при нажатии кнопки Начинаем сначала скорость устанавливается в ноль процедурой Ставим_машину_на_старт. В процессе гонки скорость регулируется процедурой Изменяем_скорость. Действие ее полностью определяется значением переменной Педаль. Если это газ, то на данном такте таймера скорость возрастет на 5. Если тормоз — упадет на 10 (потому что тормоз обычно действует сильнее газа). Как видите, значение переменной Педаль в конце процедуры принудительно приравнивается никакой педали. Это значит, что на следующем такте таймера скорость не изменится. Чтобы она изменилась, нам нужно еще раз нажать на клавишу газа или тормоза. Обычно поступают по-другому — просто удерживают клавишу нажатой, при этом событие KeyDown возникает несколько раз в секунду и скорость меняется достаточно быстро. Это соответствует механике реального автомобиля — чтобы набирать скорость, нужно непрерывно держать нажатой педаль газа, а чтобы тормозить — тормоза.

Процедура Отображаем_информацию заботится о том, чтобы на каждом такте в текстовых полях Спидометр, txtПуть и txtBpeмя были правильные цифры. В нашем проекте переменная Скорость только называется скоростью, а на самом деле это расстояние, на которое перемещается машина на одном такте таймера. Поэтому для вычисления суммарного пути, пройденного автомобилем, вполне уместен оператор Путь = Путь + Скорость. Переменная Время тоже является не временем в секундах, а количеством тактов таймера, прошедших со старта.

Теперь о процедуре Определяем_где_мы. Ее задача — задать реакцию автомобиля на три ситуации: попадание на газон, на финиш и на полосу ограждения. Метод, при помощи которого автомобиль определяет, где он, самый простой — Point. Его мы разобрали в 0. Поскольку газон я рисовал сиреневым (vbMagenta), финиш — синим, а ограждение — красным, то метод Point выдает на них разные результаты. Оператор Select эти результаты анализирует и задает реакцию автомобиля. Как видите, на сиреневое компьютер реагирует только установкой скорости = 15, на два других цвета он выдает сообщение в текстовое поле Сообщение, выключает мотор и устанавливает переменную Приехали, чтобы компьютер ее тут же проанализировал (см. процедуру таймера) и вышел из процедуры таймера, так как, когда приехали, делать, естественно, больше нечего.

В процедуре Ставим_машину_на_старт вы вполне сможете разобраться по комментариям самостоятельно.


Ну вот, кажется, и все пояснения.

Текст программы

Dim х As Integer 'Горизонтальная координата автомобиля

Dim у As Integer 'Вертикальная координата автомобиля

Dim Х_старта As Integer 'Координаты старта и финиша

Dim У_старта As Integer

Dim Х_финиша As Integer Dim У_финиша As Integer

Dim Размер_старта As Integer 'Старт — квадрат, это сторона квадрата

Dim Размер_финиша As Integer 'Финиш — квадрат, это сторона квадрата

Dim Число_газонов As Integer 'Каждый газон — это случайный прямоугольник в случайном месте

Dim Максимальный_размер_гаpона As Integer

Dim Размер_поля As Integer 'Поле — квадрат, это сторона квадрата

Dim Отступ_поля_от_края_формы As Integer 'Имеется в виду отступ слева и сверху

Dim Путь As Long 'Путь автомобиля с момента старта (в твипах)

Dim Время As Integer 'Время измеряется количеством импульсов таймера с момента щелчка по кнопке начала

Dim Скорость As Integer 'Скорость — это не скорость, а расстояние. Она численно равна шагу автомобиля на каждом такте таймера

Dim Пороговая_скорость As Integer 'Скорость, выше которой не работает руль

Dim Цвет_под_автомобилем As Long 'Нужен чтобы знать, где находится автомобиль — на газоне, на финише, врезался в ограждение


Private Enum типРуль

вверх

влево

вниз

вправо

End Enum


Dim Руль As типРуль

Private Enum типПедаль

тормоз

газ

ни_та_ни_эта

End Enum


Dim Педаль As типПедаль

Dim Приехали As Boolean 'Приехали = True, когда приехали на финиш или врезались в ограждение

Dim Клавиатура_сработала As Boolean 'Чтобы секундомер судьи запускался автоматически, когда мы стартуем, не раньше


Private Sub Form_Load()

Timer1.Enabled = False 'Нечего мотору зря работать до начала гонки

Randomize 'Нам придется рисовать случайные газоны

WindowState = 2 'Окно игры распахнуто на весь экран

BackColor = vbWhite 'Асфальт белый

'Задаем и вычисляем размеры элементов поля (все числа подбирайте на опыте):

Отступ_поля_от_края_формы = 500

ScaleLeft = — Отступ_поля_от_края_формы 'Смещаем для удобства начало

системы координат в левый верхний угол поля

ScaleTop = — Отступ_поля_от_края_формы

Размер_поля = Screen.Height — 2 * Отступ_поля_от_края_формы 'Отступ от края экрана должен быть и снизу Размер_старта = 600 Размер_финиша = 600

Х_старта = Размер_поля — Размер_старта 'Чтобы старт находился у правой кромки поля

Х_финиша = 0 'Чтобы финиш находился у левой кромки поля

У_старта = Размер_поля / 2 'Чтобы старт по высоте находился посредине поля

У_финиша = Размер_поля / 2 'Чтобы финиш по высоте находился посредине поля

Число_газонов = 30

Максимальный_размер_газона = Размер_поля / 6 Пороговая_скорость = 200

End Sub


Private Sub Кнопка_начинай_сначала_С1ick()

Клавиатура_сработала = False 'Мы еще не стартовали

Timer1.Enabled = False 'Нечего мотору зря работать до начала гонки

'Рисуем поле игры со всеми элементами:

Cls 'Перед тем, как заново рисовать, надо все стереть

Рисуем_границы_поля

Рисуем_старт

Рисуем_финиш

Рисуем_газоны

'Необходимые начальные установки:

Ставим_машину_на_старт

Приехали = False

Timer1.Enabled = True 'Заводим мотор, скоро начало гонки

Спидометр. SetFocus 'Это чтобы фокус ушел с кнопки, а то первое нажатие на стрелку действует не так, как нам надо

End Sub


Private Sub Рисуем_границы_поля()

DrawWidth = 10

Line (0, 0) — (Размер_поля, Размер_поля), vbRed, В

DrawWidth = 1 'Возвращаем нормальную толщину карандаша

End Sub


Private Sub Рисуем_старт()

Line (Х_старта, У_старта)-(Х_старта + Размер_старта, У_старта + Размер_старта), vbGreen, BF

End Sub


Private Sub Рисуем_финиш()

Line (Х_финиша, У_финиша) — (Х_финиша + Размер_финиша, У_финиша + Размер_финиша), vbBlue, BF

End Sub


Private Sub Рисуем_газоны() 'Каждый газон — это прямоугольник случайного размера в случайном месте Dim i As Integer

Dim Х_газона As Integer 'Горизонтальная координата верхнего левого угла газона

Dim У_газона As Integer 'Вертикальная координата верхнего левого угла газона

For i = 1 То Число_газонов ' Числа в формулах подобраны на опыте:

Х_газона = 2 * Размер_финиша + Размер_поля * Rnd *2/3

У_газона = Размер_финиша + (Размер_поля — Размер_финиша — Максимальный_размер_газона) * Rnd

Line (Х_газона, У_газона)-(Х_газона + Максимальный_размер_газона * Rnd, У_газона + Максимальный_размер_газона * Rnd), vbMagenta, BF Next

End Sub


Private Sub Ставим_машину_на_старт()

x = Х_старта:

у = У_старта 'Координаты машины приравниваются координатам точки старта

Скорость = 0: Путь = 0: Время = 0

Руль = влево 'Это чтобы машина знала, куда ехать, когда стартуем нажатием на газ

Едем_влево 'Отсюда нам нужна только ориентация машины налево, а шага не будет, так как скорость=0

Педаль = ни_та_ни_эта 'Газовать пока нельзя, а тормозить бессмысленно

Image_авто. Visible = True 'До первого старта я сделал машину невидимой, теперь пришла пора ей появиться

Показываем_автомобиль

End Sub


Private Sub Timer1_Timer()

Определяем_где_мы

If Приехали Then Exit Sub

Изменяем_скорость

Выбираем_куда_ехать_и_делаем_шаг

Показываем автомобиль

Отображаем_информацию

End Sub


Private Sub Определяем_где_мы()

Цвет_под_автомобилем = Point(x, y)

Select Case Цвет_под_автомобилем

Case vbMagenta: Скорость = 15 'На газоне скорость мала

Case vbBlue: Сообщение.Text = "Финиш!": Timer1.Enabled = False: Приехали = True

Case vbRed: Сообщение.Text = "Врезались в ограждение!":

Timer1.Enabled = False: Приехали = True

End Select

End Sub


Private Sub Изменяем_скорость()

Select Case Педаль

Case газ

Скорость = Скорость + 5

Case тормоз

If Скорость > 0 Then Скорость = Скорость — 10 'потому, что тормоз быстрее газа

If Скорость < 0 Then Скорость =0 'В результате быстрого торможения скорость может стать отрицательной, что и предотвращается

End Select

Педаль = ни_та_ни_эта 'Это чтобы во время набора скорости и торможения приходилось без перерыва жать на педаль

End Sub


Private Sub Выбираем_куда_ехать_и_делаем_шаг()

Select Case Руль

Case вверх: Едем_вверх

Case вниз: Едем_вниз

Case влево: Едем_влево

Case вправо: Едем_вправо

End Select

End Sub


Private Sub Едем_вверх()

Image_авто. Picture = Image_вверх. Picture

у = у — Скорость

End Sub


Private Sub Едем_вниз()

Image_авто. Picture = Image_вниз. Picture

у = у + Скорость

End Sub


Private Sub Едем_влево()

Image_авто. Picture = Image_налево. Picture

x = x — Скорость

End Sub


Private Sub Едем вправо()

Image_авто. Picture = Image_направо. Picture

х = х + Скорость

End Sub


Private Sub Показываем_автомобиль()

Image_авто. Left = x

Image_авто. Top = у

End Sub


Private Sub Отображаем_информацию()

Спидометр.Text = Скорость

Путь = Путь + Скорость 'Нужно помнить, что именем Скорость назван шаг автомобиля

txtПуть.Text = Путь

If Клавиатура_сработала Then Время = Время + 1 'Счетчик времени запускается только тогда, когда мы стартуем

txtBpeмя.Text = Время

End Sub


Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

Клавиатура_сработала = True

Select Case KeyCode

Case vbKeyUp: If Скорость < Пороговая_скорость Then Руль = вверх 'Поворот на большой скорости запрещен

Case vbKeyLeft: If Скорость < Пороговая_скорость Then Руль = влево

Case vbKeyDown: If Скорость < Пороговая_скорость Then Руль = вниз

Case vbKeyRight: If Скорость < Пороговая_скорость Then Руль = вправо

Case vbKeySpace: Педаль = газ

Case vbKeyB: Педаль = тормоз

End Select

KeyCode = 0 ' Это чтобы объекты на форме не реагировали на клавиатуру

End Sub


Недоработки проекта

Замеченные мной недоработки вызваны в основном нежеланием увеличивать размер кода и заключаются в следующем:

Координатами (х, у) машины считается ее левый верхний угол, а не центр. Причина этого — слишком простые операторы в процедуре Показываем_автомобиль. Это приводит к некоторой ассиметрии поведения машины при переезде с цвета на цвет. Немного повозившись, вы сможете исправить положение.

При большой скорости машина делает огромные шаги от одного такта таймера к другому. А ведь цвет под собой она ощущает не непрерывно, а только на тактах таймера. Значит она может перепрыгнуть через тоненький газон, не заметив его. То же относится к финишу и особенно к ограждению. Сделайте их потолще, чем у меня на картинке, или ограничьте скорость.

Сам бог велел вам добавить в проект управление машиной с помощью мыши. Например, щелчок мышью в стороне от машины вызывает поворот машины в эту сторону, удерживание нажатой левой клавиши мыши — газ, правой — тормоз. Для этого вам нужно будет написать процедуру MouseDown, придавая в ней нужные значения переменным Руль и Педаль аналогично тому, как это делает процедура KeyDown. Вам придется поразмыслить, как правильно сравнить координаты машины и мыши, чтобы добиться нужного результата.


Гонки двух автомобилей

Если вы хотите играть вместе с другом, вам нужны гонки двух машин. Несмотря на то, что ничего нового вам придумывать не придется, размер программы вырастет раза в полтора. Для второй машины нужен будет второй таймер. Вам придется иметь по два экземпляра переменных, описывающих поведение каждой машины. Например, вместо переменной Скорость вам придется иметь две переменные — Скорость1 и Скорость2. Вам придется иметь по два экземпляра процедур, задающих поведение каждой машины. Процедуру KeyDown вам придется дополнить новыми клавишами для управления второй машиной. При этом нужно будет внести серьезные изменения в педали, так как удерживать клавиши нажатыми теперь будет нельзя без усложнения программы. Вы могли бы сократить рост программы, используя процедуры с параметрами, но пока у вас для этого нет достаточных знаний. А если у вас гонки 10 автомобилей? Проблемы нарастают.

Visual Basic конечно же предлагает универсальное решение этой проблемы. Он, как и все серьезные и мощные языки программирования, является объектно-ориентированным языком. В частности, имеется в виду, что он позволяет программисту создавать собственные классы объектов. Вот у вас имеется класс объектов "кнопка" — CommandButton и вы пользуетесь в проекте отдельными экземплярами этого класса — объектами. Поведение кнопок запрограммировано глубоко внутри Visual Basic и вы видите только результаты этого программирования. Например, когда выполняется оператор

Command1.Visible = True

вы видите, что кнопка легко возникает на форме. Однако, чтобы она возникла, нужно чтобы компьютер ее нарисовал из прямоугольников и других элементов и написал что-то на ней, а для этого нужна программа.

Научившись создавать собственные классы, вы сможете создать класс "автомобиль" и пользоваться каким угодно числом экземпляров этого класса. Программу поведения автомобиля вы пишете сами, причем один раз и только для одного автомобиля. Остальные автомобили будут автоматически пользоваться ей же.


Задание на игру "Торпедная атака

Задание 114: "Торпедная атака". Начинается все красивой заставкой с названием игры. Компьютер спрашивает ваше имя, чтобы во время игры оно горело красивыми яркими буквами в углу экрана. В меню вы можете посмотреть правила игры, сведения об авторе, выбрать игру со звуком или без. Но вот игра началась. На экране морской пейзаж (нарисованный вами или взятый готовым). Вдали экрана по горизонтали плывет вражеский корабль. У нижнего края экрана притаился ваш торпедный аппарат. В подходящий момент времени вы нажимаете клавишу — и торпеда плывет вдаль, уменьшаясь по мере удаления. Если вы попали, то экран озаряется вспышкой от взрыва, на мгновение виден и сам взрыв, раздается коротенькая радостная мелодия, на экране — коротенький поздравительный текст, счетчик подбитых кораблей на экране увеличивается на 1. Если не попали, то зрительные и звуковые эффекты — совсем другие. В любом случае уменьшается на 1 счетчик оставшихся торпед. Затем плывет следующий корабль. И так далее. Когда торпеды у вас кончатся (скажем, их было 10), игра заканчивается. Программа анализирует ваши успехи и в зависимости от них выдает на экран текст, скажем "Мазила!", если вы не попали ни разу из 10, или "Профи!", если вы попали 8 раз. Затем спрашивает, будете ли вы играть еще.

Помощь: Как компьютер определит, попал или не попал? Нужно в тот момент, когда торпеда доплывет до линии движения корабля, сравнить горизонтальные координаты корабля и торпеды, и если они достаточно близки, считать, что попал.

Улучшение. Если у всех кораблей будет одинаковая скорость, то попадать будет слишком просто, а значит и играть неинтересно. Сделайте скорость кораблей случайной. Конечно, не совсем уж (скажем, в условных единицах скорости диапазон от 0 до 10 — это слишком), а в пределах разумного (скажем, от 4 до 8 — это нормально). Причем не нужно менять скорость одного и того же корабля в процессе движения. Пусть она остается постоянной, а то все будет зависеть не от вашего мастерства, а от везения. Различаются скорости только разных кораблей.

Пусть игрок сможет выбирать из нескольких уровней трудности. Трудность удобнее всего увеличивать, уменьшая размеры корабля, то есть требуемую величину близости координат корабля и торпеды при определении попадания.

Загрузка...