четверг, 12 мая 2011 г.

Урок 8 . Учим таймер “петь”


В предыдущем уроке основной алгоритм работы программы бытового таймера был реализован и отлажен: таймер может производить обратный отсчет, показывая значения убывающих секунд и останавливаться по окончании отсчета.
Но этого, очевидно, не достаточно. было бы не плохо, если бы по окончании отсчета, уснувшему на клавиатуре от непосильного труда пользователю подавался звуковой сигнал.
Чтобы поместить на форму компонент TMediaPlayer, нужно отыскать его на вкладке “System” панели инструментов и перетащить в подготовленное для него место.
Прежде, чем писать какой-то код для работы плеера, настройте его внешний вид, отключив “лишние” кнопки: вряд ли в процессе отладки понадобятся кнопки записи, извлечения диска, перемотки, да и паузы тоже. Оставьте видимыми только кнопки btPlay и btStop.
Сам плеер в момент сразу после старта программы нам тоже на форме ни к чему, поэтому после того, как все будет отлажено, установите его свойства Enabled и  Visible в False
Теперь “начнем с конца” и позаботимся об остановке плеера, добавив в процедуру
Do_StopExecute строчку:
// Остановка плеера
MediaPlayer1.Stop;
Какой же звук будет воспроизводить наш плеер? Добавьте в папку с проектом любой небольшой звуковой файл (wav), я его назвал MyTimer.wav.
Организуйте новую секцию “Sound” в файле настроек MyTimer.ini:
[Sound]
SoundFullPath=F:\! Мои программы\MyTimer\MyTimer.wav
Замечу, что путь к программе, а соответственно и к Вашему файлу wav будет отличаться от того пути, что указан выше: F:\! Мои программы\MyTimer\.
Добавьте в секцию “interface” в переменные:
MediaFileName: String;                        //  Полный путь к звуковому файлу
Затем, добавьте в процедуру FormCreate строку, считывающую информацию из файла настроек ini, из секции “Sound”:
MediaFileName:=Ini.ReadString('Sound','SoundFullPath','MyTimer.wav');
и далее в этой же процедуре выполните проверку:
//  Если в ini не указан медиа файл, то попытаться воспроизвести указанный по умолчанию MyTimer.wav
If FileExists(MediaFileName)
then
begin
MediaPlayer1.FileName:=MediaFileName;
MediaPlayer1.Open;
StatusBar1.Panels[0].Text:='Звук: '+MediaFileName;
end
else
StatusBar1.Panels[0].Text:='Звуковой файл отсутствует'; // На самом деле в этом месте
// алгоритма заложена бага: если
// звукового файла нет, то и таймер           //запускать незачем, но решение этой проблемы - домашнее задание :-)
;
Для запуска плеера по событию окончания работы первого таймера впишите в соответствующую процедуру следующую строчку:
// Воспроизвести звук
MediaPlayer1.Play;
и заремить или стереть строки, которые были написаны ранее:
// Вернуть элементы управления в стартовое состояние
//  SetRecBtnStatus(1);
//  SetBtnStatus;
чтобы оставалась доступной кнопка “Стоп”.
А теперь нужно разобраться с работой медиа плеера. Для этого скомпилируем проект и выполним программу. Нажмите кнопку старт, дайте возможность таймеру закончить отсчет и... Вы услышите звук. Но, к сожалению, звук будет воспроизведен один раз. Для бытового таймера это допустимо, но не очень здорово. Пользователь отошел на минуточку и прошляпил... “А у вас молоко убежало...” (Карлсон). Нужно заставить плеер играть, пока пользователь не остановит его сам, как это реализовано в поломавшейся дешевой иностранной подделке, все еще примагниченной к дверце холодильника
Здесь я позволю себе процитировать учебник:
“В компоненте MediaPlayer определено событие OnNotify.
Событие OnNotify происходит после возвращения очередного метода, если свойство медиа-плеера Notify было установлено в true. Способ возврата любого метода медиа-плеера определяется свойством Wait. Если установить Wait равным false, то возвращение управления в приложение происходит сразу после вызова метода, не дожидаясь завершения его выполнения. Таким образом, задав Notify равным true и Wait равным false, можно обеспечить немедленный возврат в приложение и отображение пользователю текущего состояния объекта мультимедиа.
Свойства Notify и Wait действуют только на один очередной метод. Поэтому их значения надо каждый раз восстанавливать в обработчиках событий OnClick или OnNotify”
И вряд ли Вы.найдете еще что-то большее. Собственно, ради того, чтобы показать как, я и затеял этот урок. Создайте процедуру, соответствующую событию onNotify:
procedure TForm1.MediaPlayer1Notify(Sender: TObject);
begin
With Sender as TMediaPlayer do
begin
wait:=False;
case Mode of                      // анализ состояния плеера
mpPlaying:
begin
play;                                // Продолжается проигрывание
Notify:=True;
end;
mpStopped:
begin
Notify:=True;                   // Проигрывание прекращается
end
end;
end;
end;
Теперь проигрывание выбранного звука продолжается, пока пользователь не проснется и не нажмет кнопку стоп.
И наконец, создайте процедуру FormClose и запишите в нее строку закрытия плеера:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MediaPlayer1.Close;
end;
По поводу использования компонента TMediaPlayer я предвижу массовые возражения со стороны других программистов, мол, компонент устарел, нынче модно использовать PlaySound...
Я не зря привел цитату из учебника, подозреваю, что подобное мнение сформировалось под воздействием тех, кто не смог или не захотел разобраться.
Хорошо, расскажу, как ту же задачу решить с playsound():
1. Добавьте в Uses mmsystem;
2. В процедуре procedure TForm1.Timer1Timer(Sender: TObject);
// Воспроизвести звук
//  MediaPlayer1.Play;
PlaySound(PAnsiChar(MediaFileName), 0, SND_ASYNC or SND_LOOP);
3. В процедуре
procedure TForm1.Do_StopExecute(Sender: TObject);
begin
...
// Остановка плеера
//    MediaPlayer1.Stop;
PlaySound(0, 0, SND_ASYNC or SND_LOOP);
4. Процедура MediaPlayer1Notify(Sender: TObject) должна быть исключена.
На вид - проще, но на одну библиотеку больше... Какой выбрать способ - решать Вам.
Наглядный видео урок Вы можете посмотреть или скачать.
Что же дальше?
А дальше я Вам скажу следующее: на странице сайта “Таймер для домашнего хозяйства” Вы можете скачать скомпилированную готовую программу и пользоваться ей, несмотнря на все ее недостатки. Почему я не выложил исходные тексты и весь проект, как Вы думаете? Из жадности? Нет. Потому что в проекте помимо компонентов сторонних производителей я использую собственные компоненты, которых в Вашей среде разработки заведомо нет. Попытка открытия проекта вызвала бы ошибку, а Вы посетовали бы в мой адрес нехорошими словами... Я и сам не один десяток раз натыкался на подобные ситуации: качнешь из сети исходники, чтобы побыстрее какой-то вопрос решить, а не компилируются. И укоренилось мнение в голове: чем разбираться в чужом творчестве, проще и по времени выгоднее написать свое. Поэтому я планирую на следующем уроке подробно остановиться на процессе создания своего собственного компонента. Пусть это будет самый простой компонент - метка (Label), но я постараюсь до самых мелких подробностей проследить все детали процесса.

Комментариев нет:

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.