ТОП 10:

Глава 11. Работа с таймером, временем, датами



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

Тип данных 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 секунд после полудня (PM)

Debug.Print #2/28/1998 10:45:00 PM# '10 часов 45 минут вечера 28 февраля 1998 года

D = #12/25/2044#

T = #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 PM # (это суббота), тогда:

Debug.Print DatePart("m", D) 2 (функция выделяет из даты номер месяца в году)
Debug.Print DatePart("q", D) 1 (функция выделяет из даты номер квартала в году)
Debug.Print DatePart("s", D) 7 (функция выделяет из даты номер секунды в минуте)
Debug.Print DatePart("w", D) 7 (функция выделяет из даты номер дня в неделе, но делает это по-американски, а в США первый день недели - воскресенье, значит 7-й - суббота)
Debug.Print DatePart("w", D, vbMonday)) 6 (а здесь мы попросили функцию считать первым днем недели понедельник (vbMonday) и поэтому результат она выдала привычный для нас - 6-й день - суббота)

Значением функции DatePart является число типа Integer, а не дата.

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

 

Debug.Print DateAdd("s", 10, D) 14.02.09 16:45:17 (функция добавляет к дате 10 секунд)
Debug.Print DateAdd("m", -1, D) 14.01.09 16:45:07 (функция вычитает из даты 1 месяц)

Пусть D1 = #2/14/2009 4:45:07 PM# , D2 = #2/16/2009 11:32:43 AM# , тогда:

Debug.Print DateDiff("h", D1, D2) 43 (количество часов, прошедших с момента даты D1 до момента даты D2)

 

Debug.Print Timer 53861,97 (количество секунд, прошедших с полуночи. Не путайте функциюTimer с элементом управления Timer. Результат выдается, как видите, с двумя знаками после запятой, но не верьте сотым долям, десятые же более менее точны)
Debug.Print MonthName(5) Май
Debug.Print WeekdayName(4) Четверг (как видите, работает по-нашему, а не по американски)

Опасные операторы:

Date= #05/22/2004# Это не безобидная функция Date, которая только сообщает, какое сегодня число, это оператор Date, который устанавливает системные часы Windows на ту дату, какую вы указали. Ничего особо страшного, конечно, от установки неправильной даты не будет, компьютер не сломается, но вот, например, сохраняемые вами файлы будут иметь неправильную дату сохранения, а это приведет к путанице в вашем файловом хозяйстве. Да и некоторые программы могут начать жаловаться. Отличить функцию от оператора с тем же именем просто - они встречаются по разные стороны знака равенства в операторе присваивания, причем функция всегда справа.
Time= #10:44:00 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 To 20000000 : Next

Debug.Print "Процедура таймера закончила работу"

End Sub

Здесь долго работает пустой цикл For i = 1 To 20000000 : Next. Несмотря на то, что делать ему нечего (тело у цикла отсутствует), у него много времени уходит на то, чтобы просто досчитать до 20 миллионов. На моем компьютере это занимает секунды две, на вашем, наверно, по-другому. Это неважно, а важно то, что за эти две секунды в процедуру врежется порядка 20 импульсов от таймера. И все как об стену горох - процедура на них не реагирует. Пока не завершит свою работу, как положено, оператором End Sub. После этого первый же следующий импульс, которому повезло, снова ее запускает. Вы увидите, что на экране не спеша, где-то раз в две секунды появляется очередная пара строчек.

 

Точность таймера невелика, а на интервалах меньше 1 секунды вообще никуда не годится. Не ждите, что если вы установили интервал равный 10, то в секунду будет послано 100 импульсов. Причина в том, что таймер вообще не способен выдавать больше 18 импульсов в секунду.

Задание 99: Запрограммируйте с помощью таймера печать чисел от 100 до 110 через 1 секунду.

 

11.3. Проект "Будильник-секундомер"

Вы узнали о Visual Basic вполне достаточно, чтобы рваться в бой. Наверняка у вас в голове зреет идея создать некий элегантный и одновременно вполне "убойный" проект строчек на 200, способный поразить в самое сердце ваших друзей и, что не менее важно, подруг. Однако, спешу вам сказать, что вы спешите. Ибо! Друзья и подруги может быть и понесут вас на руках до ближайшего кафе-мороженого, но человек, мало-мальски разбирающийся в программировании, бросив скучающий взгляд на ваше жалкое детище, спросит: "Юноша, в каком году вы кончали церковно-приходскую школу?" И не потому, что проект работает плохо, он вполне может проделывать на экране что-нибудь любопытное. Но программа! Программа! В ней невозможно разобраться! 200 строк вы осилили, а сколько вы возились? Неделю? А веди могли все сделать за пару дней! Сколько у вас процедур? 8? А нужно было 40! И так далее. Когда придет пора делать проект из 1000 строк, вы не сможете его одолеть никогда!

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

Пришла пора создать проект, "правильно" составленный из процедур. Проект "Калькулятор", написанный нами ранее, не подходит в качестве учебного пособия, потому что логика его работы слишком проста: нажал кнопку - выполнилась соответствующая процедура и все. Нужна более сложная задача. Для ее решения мы создадим совсем небольшую программу из 80 строк, включающую 15 процедур. Поскольку создаваемая программа представляет для многих из вас неведомую страну, я буду применять метод изложения "за ручку", который я уже применял в 1.3. Повторяйте за мной все, что я буду делать.

Начнем с постановки задачи.

Постановка задачи

Создать часы-будильник следующего вида:

 

 

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

· На верхнем циферблате - текущее время суток (системное время Windows) в часах, минутах и секундах

· Под ним - дата и день недели (02.08.00 означает 2 августа 2000 года)

· Пользователь имеет возможность редактировать содержимое циферблата установки времени будильника

· При нажатии на кнопку "Выключить будильник" надпись на кнопке меняется на "Включить будильник", а надпись над циферблатом меняется на "Будильник отключен"

· При срабатывании будильника раздается какая-нибудь продолжительная мелодия, которая замолкает при нажатии на кнопку "Выключить сигнал"

· Секундомер измеряет время с точностью до 0.1 сек. На картинке вы видите секундомер в момент паузы. Если нажать на ПУСК, то отсчет времени продолжится с 1 минуты 15.4 сек, которые вы видите на картинке, а надпись на кнопке сменится на ПАУЗА. Если снова нажать на кнопку, цифры на секундомере снова замрут.

· При нажатии на кнопку "Обнулить" секундомер сбрасывается в ноль и останавливается. На циферблате - 0:00:00.0.

Делим проект на части

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

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

· Часы (с датой и днем недели)

· Будильник

· Секундомер

Отлично! За какую из этих частей браться вначале? Для этого нужно сначала решить, зависят ли друг от друга отдельные части. Здесь очень пригодился бы некоторый опыт программирования. А если его нет, подойдет житейский опыт. Действительно, если бы вы мастерили будильник-секундомер из шестеренок, что бы в нем от чего зависело? Ну, ясно, что будильник не сработал бы без часов, ведь он должен чувствовать, когда время на циферблатах часов и будильника совпадает. А вот часы ходят и без будильника, они от него не зависят. Секундомер же, видимо, представляет собой полностью независимую часть со своим механизмом.

Итак, проект распался на две независимые части:

· Часы и будильник

· Секундомер

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

Итак, мы разделили проект на части и определили порядок выполнения частей:

1.Часы

2.Будильник

3.Секундомер

Беремся за часы. И тут опять пошла дележка. Чем раньше заниматься - временем суток (будем называть это просто часами), датой или днем недели? Шестеренки смутно подсказывают нам, что дата переключается в полночь, а значит момент переключения зависит от часов. Значит дату будем делать позже часов. А день недели, ясно, определяется датой.

Итак, окончательная последовательность такая:

1.Часы (время суток)

2.Дата

3.День недели

4.Будильник

5.Секундомер

 

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

 

Ну что ж, "Задачи ясны, цели определены, за работу, товарищи!", как говорили при социализме.

Делаем часы

Создаем новый проект. Первым делом берем элемент управления Shape и рисуем вокруг будущего циферблата часов красивую рамочку. Если вы хотите сделать что-нибудь более выдающееся, чем скромная рамочка на картинке, и украсить часы необыкновенными шедеврами графики, то на здоровье, пожалуйста!. Но не сейчас. Потом. Когда все заработает. Иначе потонете в подробностях и не откопаете в золотых лепесточках нужную вам стальную шестеренку.

Я не дал объекту Shape1 никакого другого имени, потому что не собираюсь упоминать его в программе. Все свойства я ему установил в режиме проектирования и не хочу, чтобы рамочка как-то себя "вела" в режиме работы.

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

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

 

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

Циферблат_часов.Text = Time

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

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

 

Поместим на форму таймер и дадим ему имя Таймер_часов. Зададим ему интервал = 2500. Напишем такую программу:

Private Sub Таймер_часов_Timer()

Циферблат_часов.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 из 11.1. А теперь нужно разобраться со скобками. Вы поняли, какая пара скобок к какой функции относится? Если нет, то я перепишу один оператор в два:

А = DatePart("w", Date, vbMonday)

Циферблат_дня_недели.Text = WeekdayName(А)

Здесь А будет равняться номеру дня недели (число от 1 до 7). Функция WeekdayName по номеру дня недели получает строковое название этого дня.

 

Раз мы организовали процедуру Смена_даты_и_дня_недели, то нам нет нужды вспоминать, в какие моменты времени проект должен менять день недели. Вставляем наш оператор в эту процедуру:

Private Sub Смена_даты_и_дня_недели()

Циферблат_даты.Text = Date

Циферблат_дня_недели.Text = WeekdayName(DatePart("w", Date, vbMonday))

End Sub

 

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

 

Итак, часы с датой и днем недели готовы.

Знакомимся с типом Boolean

Чтобы грамотно запрограммировать будильник, нам нужно познакомиться с новым типом переменных величин - Boolean. Это так называемый логический тип. В 5.7 вы уже позакомились с логическими выражениями. Их главная черта в том, что они могут принимать всего два значения - Trueи False(истина и ложь). Логическая переменная величина отличается той же чертой. Объявляется она так:

Dim С As Boolean

А зачем она нужна, выяснится из следующего параграфа.

Делаем будильник

Поместим на форму все объекты, необходимые для будильника. Дадим им имена:

· Метка_будильника

· Циферблат_будильника

· Кнопка_включения_выключения_будильника

· Кнопка_выключения_сигнала

В циферблат занесем в режиме проектирования текст 12:00:00. Просто для того, "чтобы было".

 

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

Вспомните, как вы занимались музыкой в "Калькуляторе". Поместите на форму Microsoft Multimedia Control 6.0 и дайте ему имя "Плеер". Для работы с мелодией нам нужно 5 операторов:

Плеер.DeviceType = "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 из 5.9 в качестве условия оператора 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 Кнопка_выключения_сигнала_Click()

Плеер.Command = "Close"

End Sub

 

Private Sub Form_Terminate()

Кнопка_выключения_сигнала_Click

End Sub

 

 

'ПРОЦЕДУРЫ РАБОТЫ СЕКУНДОМЕРА

 

Private Sub Таймер_секундомера_Timer()

Время_на_секундомере = Timer - Время_запуска_секундомера + Время_на_паузе_секундомера

Цифра_десятых = Int(10 * (Время_на_секундомере - Int(Время_на_секундомере)))

Циферблат_секундомера.Text = DateAdd("s", Время_на_секундомере, #12:00:00 AM#) & "." & Цифра_десятых

End Sub

Private Sub Кнопка_пуска_паузы_секундомера_Click()

If Режим_работы_секундомера <> считает Then Секундомер_запустить Else Секундомер_остановить

End Sub

Private Sub Кнопка_обнуления_секундомера_Click()

Секундомер_обнулить

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, как и многие языки, позволяет программисту создавать собственные типы. Наша задача - создать тип, в котором переменная принимает ровно три значения: считает, пауза, в нуле - а затем объявить этим типом переменную Режим_работы_секундомера.







Последнее изменение этой страницы: 2016-08-12; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.226.241.176 (0.075 с.)