Занимаемся днем недели

Нам не хочется трудиться, размещая в рамке метку, а потом еще и настраивая ее для дня недели. Замечаем, что она такая же, как для даты. Скопируем ее, как это принято в Windows, щелкнув по ней правой клавишей мыши и выбрав в контекстном меню Copy, а затем щелкнув правой клавишей мыши в рамке Часы и выбрав в контекстном меню Paste.

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

Циферблат_дня_недели.Text = Format(Now, "dddd")

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

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

Циферблат_даты.Text = Format(Now, "Long Date")

Циферблат_дня_недели.Text = Format(Now, "dddd")

End Sub

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

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

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

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

· Текстовое поле с именем Циферблат_будильника

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

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

В циферблат занесем в режиме проектирования текст 12:00:00. Просто для того, «чтобы было». В качестве циферблата мы выбрали текстовое поле, а не метку. А это для того, чтобы иметь возможность в режиме работы вручную устанавливать время будильника.

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

Вспомните, как мы занимались музыкой в «Плеере». Поместите на форму Windows Media Player и дайте ему имя Звонок. Сделайте его невидимым. Для настройки звонка достаточно трех операторов в процедуре Form1_Load:

Звонок.AutoStart = False 'Чтобы не запускался слишком рано

Звонок.PlayCount = 0 'Чтобы закончив играть, начинал снова

Звонок.FileName = "Mozart's Symphony No. 40.RMI"

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

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

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

Запустит воспроизведение мелодии оператор Звонок.Play(), но он должен выполниться только тогда, когда время на циферблате часов совпадет со временем на циферблате будильника.

Вот как дополнится теперь наш проект (я показываю только те процедуры, которых коснулись дополнения):

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Настройка_звонка()

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

End Sub

Private Sub Таймер_часов_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Таймер_часов.Tick

Время_на_часах = Format(Now, "HH:mm:ss")

Циферблат_часов.Text = Время_на_часах

If Время_на_часах = "00:00:00" Then Смена_даты_и_дня_недели()

If Время_на_часах = Циферблат_будильника.Text Then Звонок.Play()

End Sub

Sub Настройка_звонка()

Звонок.AutoStart = False 'Чтобы не запускался слишком рано

Звонок.PlayCount = 0 'Чтобы закончив играть, начинал снова

Звонок.FileName = "Mozart's Symphony No. 40.RMI"

End Sub

Запустите проект и установите время на циферблате будильника. Дождитесь, когда будильник зазвонит. Завершите работу проекта, не дожидаясь конца мелодии.

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

Придумаем переменную и дадим ей имя Будильник_установлен. Каким типом ее объявить? Для этого надо понять, а какие значения будет принимать эта переменная? По смыслу задачи значений два – «да» и «нет». Можно придать ей тип String, но хорошая практика программирования диктует тип Boolean. Вы скоро привыкнете к нему и поймете, что он удобнее.

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

· Нужно сообщить компьютеру, что будильник установлен

· Нужно, чтобы текст над циферблатом был такой: «Будильник установлен на»

· Нужно, чтобы текст на кнопке был такой: «Выключить будильник»

В соответствии с этим пишем процедуру:

Sub Включить_будильник()

Будильник_установлен = True

Метка_будильника.Text = "Будильник установлен на"

Кнопка_включения_выключения_будильника.Text = "Выключить будильник"

End Sub

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

· Нужно сообщить компьютеру, что будильник не установлен

· Нужно, чтобы текст над циферблатом был такой: «Будильник отключен»

· Нужно, чтобы текст на кнопке был такой: «Включить будильник»

В соответствии с этим пишем процедуру:

Sub Выключить_будильник()

Будильник_установлен = False

Метка_будильника.Text = "Будильник отключен"

Кнопка_включения_выключения_будильника.Text = "Включить будильник"

End Sub

Теперь нам удивительно легко написать процедуру щелчка по кнопке включения-выключения будильника:

Private Sub Кнопка_включения_выключения_будильника_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Кнопка_включения_выключения_будильника.Click

If Будильник_установлен Then Выключить_будильник() Else Включить_будильник()

End Sub

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

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

If Будильник_установлен = True Then ….

Процедуру щелчка по кнопке выключения звонка приведу без пояснений:

Private Sub Кнопка_выключения_звонка_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Кнопка_выключения_звонка.Click

Звонок.Stop()

End Sub

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

If Время_на_часах = Циферблат_будильника.Text Then Звонок.Play()

мы пишем оператор

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Звонок.Play()

Теперь нужно решить, должен ли будильник после запуска проекта быть включен или выключен. Можно решить и так и эдак, на работоспособность проекта это никак не повлияет. Я предпочитаю, чтобы он был выключен, поэтому пишу в процедуру Form1_Load оператор Выключить_будильник().

Программа часов с будильником целиком. Часы с будильником готовы. Приведу полностью их программу:

Public Class Form1

Inherits System.Windows.Forms.Form

Windows Form Designer generated code

Dim Время_на_часах As String

Dim Будильник_установлен As Boolean

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)Handles MyBase.Load

Настройка_звонка()

Выключить_будильник()

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

End Sub

Private Sub Таймер_часов_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Таймер_часов.Tick

Время_на_часах = Format(Now, "HH:mm:ss")

Циферблат_часов.Text = Время_на_часах

If Время_на_часах = "00:00:00" Then Смена_даты_и_дня_недели()

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Звонок.Play()

End Sub

Sub Настройка_звонка()

Звонок.AutoStart = False

Звонок.PlayCount = 0

Звонок.FileName = "Mozart's Symphony No. 40.RMI"

End Sub

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

Циферблат_даты.Text = Format(Now, "Long Date")

Циферблат_дня_недели.Text = Format(Now, "dddd")

End Sub

Sub Включить_будильник()

Будильник_установлен = True

Метка_будильника.Text = "Будильник установлен на:"

Кнопка_включения_выключения_будильника.Text = "Выключить будильник"

End Sub

Sub Выключить_будильник()

Будильник_установлен = False

Метка_будильника.Text = "Будильник отключен"

Кнопка_включения_выключения_будильника.Text = "Включить будильник"

End Sub

Private Sub Кнопка_включения_выключения_будильника_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Кнопка_включения_выключения_будильника.Click

If Будильник_установлен Then Выключить_будильник() Else Включить_будильник()

End Sub

Private Sub Кнопка_выключения_звонка_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Кнопка_выключения_звонка.Click

Звонок.Stop()

End Sub

End Class

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

Звонок.Play()

а парой операторов:

Звонок. CurrentPosition = 0

Звонок.Play()

Но в этом случае вместо

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Звонок.Play()

вам придется писать

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then

Звонок.CurrentPosition = 0

Звонок.Play()

End If

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

If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Включить_звонок()

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

Делаем секундомер

Размести в проекте второй таймер, дав ему имя Таймер_секундомера. Поместим в рамку с именем Секундомер элементы управления для секундомера и дадим им имена:

· Циферблат_секундомера (это метка)

· Кнопка_пуска_паузы_секундомера

· Кнопка_обнуления_секундомера

а также не забудем метку с текстом «Секундомер».

Таймер нужен секундомеру для того же, для чего и часам, а именно – чтобы вовремя менялись цифры на циферблате, а собственный таймер предпочтительно (но в нашем случае не обязательно) иметь для того, чтобы не зависеть от часов. Поскольку нам нужно отслеживать сотые доли секунды, установим ему интервал меньше 10. Когда секундомер считает, таймер секундомера должен работать:

Таймер_секундомера.Enabled = True

а когда он в паузе или в нуле, таймер может и отдохнуть:

Таймер_секундомера.Enabled = False

Режимы работы секундомера. Если будильник в каждый момент времени может находиться в одном из двух состояний (режимов) – установлен или не установлен, то секундомер – в трех: считает, стоит в паузе, стоит в нуле. Придумаем переменную и дадим ей имя Режим _секундомера. Объявить ее типом Boolean явно недостаточно, ведь в типе Boolean всего два возможных значения, а нам нужно три. Здесь напрашивается перечисление:

Enum Режим

считает

пауза

в_нуле

End Enum

Dim Режим_секундомера As Режим

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

Dim Секунды_на_секундомере As Double

Dim Секунды_при_запуске_секундомера As Double

Dim Секунды_на_паузе_секундомера As Double

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

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

Засечем в момент пуска секундомера значение функции Timer оператором

Секунды_при_запуске_секундомера = DateAndTime.Timer

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

DateAndTime.Timer - Секунды_при_запуске_секундомера

как раз и будет равняться числу секунд, прошедших с момента запуска секундомера. А если нам удастся правильно засечь Секунды_на_паузе_секундомера (имеющие смысл секунд, прошедших с момента пуска до паузы), то дело решит оператор

Секунды_на_секундомере = DateAndTime.Timer - Секунды_при_запуске_секундомера _

+ Секунды_на_паузе_секундомера

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

Внешний вид показаний секундомера. Переменная Секунды_на_секундомере – это дробное число типа Double. Например, такое – 65.28194. Но на секундомере эти самые цифры, сами понимаете, должны выглядеть по-другому – 00:01:05.28. Для этого нам нужно как-то преобразовать число секунд в стандартный формат времени. Организуем переменную и константу:

Dim Время_на_секундомере As Date

Const Полночь As Date = #12:00:00 AM#

Здесь время #12:00:00 AM# обозначает, как ни странно, полночь по-американски.

Дело решает пара операторов:

Время_на_секундомере = Полночь.AddSeconds(Секунды_на_секундомере)

Циферблат_секундомера.Text = Format(Время_на_секундомере, "mm:ss.ff")

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

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

Sub Секундомер_остановить()

Sub Секундомер_запустить()

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

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

Наши рекомендации