Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






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

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

Private Enum типРежим_работы_секундомера

считает

пауза

в_нуле

End Enum

Это не процедура, хоть и похожа. Слово Enum означает, что тип - перечислимый. Это означает, что мы обязаны были придумать и в этой конструкции перечислить имена всех возможных значений переменной этого типа, что мы и сделали. Поскольку каждый тип должен иметь свое имя (Integer, String, …), нам тоже пришлось придумать имя новому типу (типРежим_работы_секундомера) и указать его в заголовке.

Теперь, когда новый тип определен, можно любую переменную объявить этим типом, что мы и делаем:

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

 

Замечание для новичков: Новички с трудом воспринимают смысл строк со стоящими рядом похожими именами, таких, например, как только что написанная. Новичку кажется, что эти имена означают одно и то же. Должен сказать, что профессиональные программисты специально обозначают близкие вещи похожими именами, им так больше нравится (можете себе вообразить?!). Например, у них может встретиться кнопка с именем cmdПодать_сюда_Ляпкина_Тяпкина и в этом же проекте переменная с именем 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, которое возникает при завершении воспроизведения мелодии. А можно, наверное, выкрутиться еще проще, как мы сделали в Калькуляторе.

· В будильнике пользователь может изменять время сигнала, не дождавшись конца мелодии, что может привести к необходимости нового запуска мелодии, пока она еще не отзвучала. Здесь вам поможет событие Циферблат_будильника_GotFocus.

· Самое досадное то, что если вы во время установки времени будильника случайно хоть на мгновение сотрете двоеточие или напишете вместо цифры букву или как-нибудь по-другому нарушите правильный формат времени, то проект аварийно завершит работу, потому что оператор (If Будильник_установлен And Время_на_часах = Циферблат_будильника.Text Then Включить_сигнал_будильника) не сможет понять, чему равно время Циферблат_будильника.Text. Здесь вам понадобятся средства, предотвращающие ввод в текстовое окно неправильных данных. Самое простое из них - функция IsDate, которая подобно функции IsNumeric из 5.9 определяет, можно ли считать ее аргумент правильным временем и правильной датой или это белиберда. Подумайте, вам вполне по силам справиться с этой проблемой.

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

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

· Я не запускал секундомер в полночь.

Таймер и моделирование

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

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 часа. Пусть шахматисту А выпало начинать. Как только партия начинается, судья запускает счетчик А, который начинает обратный отсчет времени, уменьшая свои показания. Таким образом, в каждый момент партии счетчик показывает, сколько времени осталось шахматисту на обдумывание. Пока работает счетчик А, счетчик В, естественно, стоит. Как только шахматист А сделал ход, он тут же нажимает кнопку А, которая останавливает его счетчик и запускает счетчик В. За обдумывание принимается шахматист В. Сделав ход, он нажимает кнопку В, которая останавливает его счетчик и запускает счетчик А. И так далее. Если шахматист просрочит время, его флажок падает - он проиграл.

Для удобства шахматистов добавьте к часам счетчик ходов.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.