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

Предоплата всего

Подписываем
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Предоплата всего
Подписываем
Практическая работа№ 36
«Проигрыватель»
Цельработы-создатьпрограмму-проигрывательфайловмультимедиа,снабженный системой визуализации. Для начала многооконность будет реализована посредством стандартных диалогов. Проигрыватель файлов мультимедиа, проигрывающий различные форматы, а такжесопровождающиймузыкальныефайлы визуализацией.
1. Создатьна дискепапку (например C:\MyDelphi\MyMPlayer), в которой будет создан проект, скопировать в эту папку несколько музыкальных файлов и клипов. Для демонстрации полноценной работы проигрывателя понадобятся мультимедийные файлы wav, mid, wma, mp3, avi, которые можно найти в соответствующих папках.
Видеофайлы:
C:\Program Files\Borland\Delphi5\Demos\Coolstuf\
Аудиофайлы: C:\Windows\Media\
C:\Program Files\Microsoft Office\Office10\Media\ C:\Мои документы\Мои музыкальныезаписи\
2. Создать простейшую программу проигрывания аудиофайлов (см. практическая работа№ 10). Для этого поместить на форму кнопку, медиапроигрыватель, диалог загрузки.
Рис. 72.
3. Настроить фильтр диалога на файлы мультимедиа, соответственно заполнив таблицу.Убратьненужныенамкнопкипроигрывателя,отключивихвИнспектореОбъектов
(VisibleButtons). В обработчикенажатия на кнопкуописать загрузкуфайла.
OpenDialog – диалог загрузки
Рис. 73.
Основное свойство – FileName: string, основной метод – Execute. При вызове из программы методаExecute происходит вывод на экран диалога. Параметры вывода
110
определяютсясвойствамикомпонента:Title,Options,Filterидр.Еслипользовательвыберет файлдляоткрытияинажмет"Открыть",товсвойствоFileNameкомпонентабудетзаписано имяэтогофайлавформатеstring,арезультатомметодаExecuteбудетзначениеtrue.Иначе, если пользователь нажмет в диалоге кнопку"Отмена", результатExecute будетfalse, т.е. Execute является булевойфункцией.
MediaPlayer – медиапроигрыватель.
Основное свойство–FileName:string, основные методы– Play,Pause,Stop. После тогокаквсвойствоFileNameпомещеноимяфайламультимедиа,этотфайлнужнооткрытьс помощью методаOpen (если установлено свойствоAutoOpen, то открытие происходит автоматически, но это не всегда хорошо, поскольку, еслиFileName не задано или задано неверно, то при автооткрытии произойдет ошибка).
Когда файл открыт, он может быть воспроизведен. Это можно сделать с помощью кнопок самого компонента, либо вызвав методPlay. То же касается остановки и паузы– методовStop иPause. Для настройки внешнего вида компонента используется множество свойств, к примеру, можно скрытьчасть кнопок, настраивая свойство VisibleButtons.
4. В обработчике нажатия наButton1 вызывается метод диалогаExecute, и если он выдает результат true (пользователь выбрал файл и нажал "Открыть"), то медиапроигрывателюпередаетсяимяэтогофайлаифайлоткрывается.Теперьпользователь может воспроизвести его, нажав кнопки проигрывателя.
procedure TForm1.Button1Click(Sender: TObject);
begin
ifOpenDialog1.Execute then begin
MediaPlayer1.FileName := OpenDialog1.FileName;
MediaPlayer1.Open;
end;
end;
5. При запуске программы пользователь видит кнопку и проигрыватель. Проигрывательнеявляетсяактивным,посколькуфайл,которыйондолженвоспроизводить, не открыт.
Рис. 74.
При нажатии на кнопку активизируется диалог. Параметры диалога соответствуют значениям свойств, заданных предварительно в Инспекторе Объектов. К примеру, выбранныйфильтр звуковых файлов скрывает все файлы с отличающимся расширением.
После выбора в музыкальной папке файла при нажатии кнопки "Открыть"
проигрыватель стал доступным. Файл открыт,и можно воспроизвести его.
111
Если необходимо воспроизвести видеофайл, то при запуске автоматически будет создано отдельное окно, в котором отобразится изображение.
6. Проигрыватель готов. Необходимо оформить пользовательский интерфейс. Поместите на форму панель, а на ней расположите компонентImage, растянутый на всю панель. Добавьте таймер. Сохраните модуль как MainUnit и проект какMyMPlayer в приготовленную папку.
Рис. 75.
Дайте каждому компоненту подходящее название. Обработчик кнопки поменяйте согласно последним изменениям и добавьте растяжение видеоэкрана. Для того чтобы видеофайлы воспроизводились не в отдельномокне, а в заданном месте, например, на Panel1, необходимо соответствующим образом установить свойство медиапроигрывателя Display. Для того чтобы установить и растянуть нужным образом изображение, нужно установить свойство DisplayRect:
MPlayer.DisplayRect:=Rect(0,0,ScreenPanel.Width, ScreenPanel.Height);
где Rect(x1, y1, x2, y2: integer):TRect – функция, преобразующая четыре числа к формату TRect – прямоугольник,а свойствоDisplayRectимеет именно этот формат.
Для того чтобы переименовать компоненты измените свойствоName. Настройте параметры компонентов:
1) MainForm: TmainForm
Caption = ‘Мультимедиа-проигрыватель’ ClientWidth = 402
ClientHeigth = 290
2) LifeTimer: Ttimer Enabled = false Interval = 100
3) MediaOpenDlg: TOpenDialog
Options:ofFileExist=true
Title=‘Загрузить файл мультимедиа’
4) LifeImage: TImage
Align = alClient
5) ScreenPanel: TPanel Align = alTop Caption=‘’
Width = 402
Heigth = 252
6) MediaOpenBtn: TButton
Captoin = ‘Открыть’
7) MPlayer: TMediePlayer
Display = ScreenPanel
VisibleButtons = [btPlay,btPause,btStop]
112
7.Необходимосоздатьединуюформудлявоспроизведениязвуковыхивидеофайлов. Причем воспроизведение звуковых файлов тоже будет сопровождаться анимацией. В качествеэтого сопровожденияиспользуетсяигра "Жизнь".
Для этого добавимсоответствующий "рассчитывающий" и "рисующий" код.
Опишемконстанты,определяющиеразмерполя,введемновыйтип–массивклетоки объявимглобальную переменную этого типа.
const
XSize = 40;
YSize = 25;
type
TLifeCells= array[0..XSize-1,0..YSize-1]ofboolean;
var
MainForm: TMainForm;
A: TLifeCells;
Создадимпроцедуру,случайнымобразомзаполняющую массив.
procedure RandomCells;
var
i,j:integer;
begin
fori:=0 to XSize - 1do forj:=0to YSize - 1do
A[i, j] := random< 0.5;
end;
Это процедура случайного заполнения поля. Булева переменная присваивается логически,ане спомощьюусловногооператораifrandom<0.5thenA[I,j]:=trueelseA[i.j]:= false.
Создадимфункцию, определяющую число живых клеток-соседей уданной клетки.
functionNumOfCells(x,y:integer):integer;
var
i,j,xx,yy:integer;
begin
Result := 0;
fori:=-1to1do
forj:=-1to1do
begin
xx:=x+i;yy:=y+j;
if xx = -1thenxx:=XSize-1; if yy = -1thenyy:=YSize-1; if xx = XSize then xx := 0;
if yy = YSize then yy := 0;
ifA[xx,yy] then inc(Result);
end;
ifA[x,y]then dec(Result);
end;
Это функция подсчета живых соседей. Обратите внимание на переменныеxx иyy. Подобным образом реализуется"сшивка" верхнего и нижнего, левого и правого краев. В конце исключаетсясама клеткаиз числа соседей:ifA[x,y]thendec(Result);
Создадимпроцедуру, рисующую поле клеток.
procedureDrawCells;
var
i,j:integer;
113
begin
with MainForm.LifeImage.Canvasdo
begin
Brush.Color := сlBlue;
Pen.Color := Brush.Color;
Rectangle(0,0,XSize*10,YSize*10);
Brush.Color := clRed;
fori:=0to XSize - 1do
forj:=0to YSize - 1do
if A[i, j] thenRectangle(i*10,j*10,i*10+10,j*10+10);
end;
end;
Опишем обработчик таймера; каждый такт у нас будет происходить перерасчет живых клеток по правилам игры.
procedure TMainForm.LifeTimerTimer(Sender: TObject);
var
i,j:integer;
B: TLifeCells;
begin
fori:=0 to XSize - 1do for j:=0 to YSIze - 1do
caseNumOfCells(i,j)of
2: B[i, j] := A[i, j];
3: B[i, j] := true;
else B[i, j] := false;
end;
A:=B;
DrawCells;
end;
Каждыйтакттаймерапересчитываютсяживыеклетки.Алгоритмигры,какизвестно, состоитвследующем.Еслиуживойклеткидваилитрисоседа,тоонаостаетсяживой,если меньшедвух,–погибаетотодиночества,еслибольшетрех,–гибнетоттесноты.Рождается клетка, если у нее ровно три соседа. С помощью оператораcase реализуются правила. Использование локального массиваB необходимо. Если записывать сразу вA, то клетки нового поколения будут также считаться при учете соседей, что недопустимо: каждому – свое.Вконце,однако,нужноскопироватьновоепоколение,содержащеесявB,вмассивA. Простые массивыможно копировать присвоением:A:=B.
Модифицируется обработчик нажатия кнопки под новые задачи. Проанализируйте расширениезагружаемогофайла,и,еслизагруженвидеофайл,Imageстановитсяневидимым, освобождая экран для ролика, в противном случае, наоборот, выводится картинку, на которой идет игра, заполняетсяполе клеток и запускается таймер.
procedure TMainForm.MediaOpenBtnClick(Sender: TObject);
begin
if MediaOpenDlg.Execute then
begin
MPlayer.FileName := MediaOpenDlg.FileName;
MPlayer.Open;
MPlayer.DisplayRect:=Rect(0,0, ScreenPanel.Width, ScreenPanel.Height);
MPlayer.Play;
if ExtractFileExt(MPlayer.FileName) = '.avi'then LifeImage.Visible := false
elsebegin
LifeImage.Visible:=true;
114
RandomCells;
LifeTimer.Enabled:=true;
end;
end;
end;
Экран вывода "растягивается" на всю панель. Добавлен автоматический запуск воспроизведения. В зависимости от расширения воспроизводимого файла, LifeImage, на котором происходит"Жизнь", либо прячется (в случае'.avi'), либо выводится (в других случаях).
Рис. 76.
8.Необходимопредоставитьпользователювозможностьнастройкицветов.Наформу добавляемтрикомпонента–двадиалогавыборацветаFieldColorDlg:TColorDialog(Color= clNavy),CellColorDlg:TColorDialog(Color=clYellow) и одну кнопкуSetColorBtn:TButton
(Caption= ‘Цвета’).
В обработчикенажатияна этукнопкунужно описать вызов диалогов.
Рис. 77.
ColorDialog(основноесвойствоColor:TColor,основнойметод–Execute)- диалог выборацвета.Еслипользовательвыбралцветинажал"ОК",результатэтогометода–true, если пользователь нажал "Отмена",то результат false.
procedure TMainForm.SetColorBtnClick(Sender: TObject);
begin
if MessageDlg('Изменить цвета?', mtConfirmation, [mbYes, mbNo], 0) = mrNothen exit;
if MainForm.FieldColorDlg.Execute then ScreenPanel.Color := MainForm.FieldColorDlg.Color;
MessageDlg('Теперь изменитецвет клеток',mtInformation, [mbOk], 0);
CellColorDlg.Execute;
115
DrawCells;
end;
MessageDlg(const Msg: string; DlgType:TMsgDlgType;Buttons:TMsgDlgButtons; HelpCtx: Longint): Word; - вызовокна сообщения. Это служебноеокно.
Msg – текст сообщения.
DlgType – тип диалога. Возможные значения:mtWarning,mtError,mtInformation, mtConfirmation, mtCustom.
Buttons–используемыекнопки.Переменнаятипа"множество",возможныеэлементы: mbYes, mbNo,mbOK,mbCancel,mbAbort, mbRetry,mbIgnore,mbAll,mnNoToAll, mbYesToAll,mbHelp.
HelpCtx– индекс контекстной справки. В данном примере индекс равен нулю. При написании проектов сразвернутой справочной системой указываетсяреальныйиндекс.
MessageDlg возвращает число, равное одной из следующих констант:mrNone, mrAbort, mrYes,mrOk,mrRetry,mrNo,mrCancel,mrIgnore,mrAll. Эти константы – так называемый модальный результат (modal result) нажатия на соответствующую кнопку диалога.
Вданнойпрограммепроверяется,равенлимодальныйрезультатmrNo,т.е.нажатали кнопка"Нет";еслинажата,товызываетсяexit,ипрограмманемедленновыходитизтекущей процедуры-обработчика.
Функции MessageDlg и Execute Delphi позволяет вызывать как процедуры: MediaOpenDlg.Execute вместо if MediaOpenDlg.Execute then …
При этом невозможно проконтролировать, какие кнопки были нажаты: "OK" или
"Отмена".
Далее необходимо откорректировать процедуру рисования, затем запустить программу, загрузить музыкальный файл и настройте цвета. Наконец, необходимо использовать цвета диалогов при рисовании.
Внеситеизмененияв DrawCells:
…
with MainForm.LifeImage.Canvasdo
begin
Brush.Color := MainForm.FieldColorDlg.Color;
Pen.Color := Brush.Color;
Rectangle(0, 0, XSize * 10, YSize * 10); Brush.Color := CellColorDlg.Color;
Brush.Color := MainForm.CellColorDlg.Color;
……….
Рис. 78.
116
Рис. 79.
9. На данный момент форма может быть масштабирована во время работы приложения. Для того чтобы зафиксировать размер формы, необходимо установить соответствующеесвойствоBorderStyle.Крометого,нужнозапретитьразворачиваниеформы на весь экран (это такженежелательно).
Перечислимосновныесвойстваисобытия формы.
Свойства
BorderIcons: TBorderIcons – иконки заглавной панели формы, тип свойства– множество, возможные элементы:biSystemMenu,biMinimize,biMaximize,biHelp(в данном случаенужно отключить biMaximize, чтобы формунельзя было развернуть).
BorderStyle: ТBorderStyle – стиль бордюра bsDialog, bsSingle, bsNone, bsSizeable, bsToolWindow, bsSizeToolWin. Если установить bsNone, то форма будет без заглавной панели,азначитибезкнопкизакрытияпрограммы.Следовательнр,выходитьизпрограммы возможнолибоспомощьюAlt-F4,либопредусмотретьдополнительнуюкнопку сметодом Close.
ClientWidth, ClientHeigth: integer – ширина и высотаклиентской области формы.
FormStyle:TFormStyle – стиль формы. Наиболее важным значением является fsStayOnTop. Если установлено это значение, то форма будет находиться над остальными формами, дажеесли она не активна, и пересекаетсяс активной на данный момент формой.
Position:TPosition – расположение формы. Здесь задаются различные начальные положения формы, например, задать положение по центру экрана(poScreenCenter). При запускепрограммы онаокажетсяв центре.
WindowState: TWindowState – состояние окна. Возможные значения: wsNormal, wsMinimized,wsMaximized.Спомощьюэтогосвойстваможноразворачиватьисворачивать форму.
События
OnActivate, OnDesactivate(Sender:TObject)– события, возникающие, когда форма активируется и дезактивируется (при этом в формупереходит или ее покидает фокус ввода). OnCloseQuery(Sender:TObject;var CanClose:Boolean)– событие, возникающее при попыткезакрытьформу.Например,некотораяпрограммаспрашивает:"Выхотитезавершить программу?". Это – результат действия подобного события. Делается это в обработчике подобнымобразом:CanClose:=MessageDlg('Exitnow?',mtConfirmation,[mbYes,mbNo],0)=
mrYes.
OnCreate, OnDestroy(Sender: TObject) – событие, необходимое для описания действий,требуемыхв началеили в концеработыприложения(открытиеизакрытиефайлов, чтениеи сохранениенастроек, инициализацияпеременныхи т.п.).
OnHide, OnShow(Sender:TObject)– вызываются, когда форма становится видимой или невидимой (при присвоении соответствующегозначениясвойства Visible).
OnResize(Sender:TObject)– происходит, когда форма растягивается или сжимается.
Здесь описывают изменениеразмеров и расположениекомпонентов на форме.
117
10. Продолжить оформлениемедиапроигрывателя.
1) Для того чтобы случайное заполнение было более случайным, в событии формы
OnCreate добавить Randomize.
procedure TMainForm.FormCreate(Sender: TObject);
begin
Randomize;
RandomCells;
end;
2) Также желательно зациклить воспроизведение медиафайла, описать обработчик событиямедиапроигрывателяOnNotify.УMediaPlayerестьдвасвойства–Position:LongIntи Length:LongInt. Это, соответственно, текущая позиция в записи и длина записи. Событие проигрывателяOnNotify возникает при завершении различных управляющих методов MediaPlayer. Состояниепроигрывателяможноузнать из свойства Mode.
Когда запись будет доигрываться до конца, будет вызываться метод Play,
запускающий ее с начала. При остановкепроигрывателя «перематываем» запись на начало. if Position = Length then Play
procedure TMainForm.MPlayerNotify(Sender:TObject);
begin
with MPlayer do caseMode ofmpPlaying:ifPosition=Length then Play;
mpStopped: Rewind;
end;
end;
3) Установить название приложения и выбрать ему иконку. В главном меню открыть Project=>Options. На вкладкеApplication, задать название приложения(это название, в частности, будет отображаться снизу на панели задачWindows), а также загрузить подходящую иконку. Стандартную иконку можно найти в папкеC:\ProgramFiles\Common Files\BorlandShared\Images\Icons,создатьсвоюиконку–вредактореDelphi(меню Tools=> Image Editor) или в любом другом редакторересурсов.
Рис. 80.
118
Рис. 81.
11. Проанализируем недостатки: не выводится название проигрываемого файла, компоненты на форме не очень-то гармонируют друг с другом, неизвестно, сколько процентов записи проиграно на данный момент, нельзя устанавливать скорость визуализации, нет возможности редактированияи сохраненияпозиций игры "Жизнь".
Создайте копию проекта. Добавить в проект новую форму для управления воспроизведениеммедиафайла.Длясозданияновойформыщелкнитенакнопкуменю.Есть возможность сделать это и в пункте менюFile=>New… Там же можно создать форму с помощью мастера.
Добавьте на формупять кнопокSpeedButton,TrackBar итаймер.
Рис. 82.
Кнопка SpeedButton отличается от обычной кнопки, во-первых, тем, что может содержатькартинку,а во-вторых,тем, что может оставаться нажатой.
Рис. 83.
Основные свойства – Glyph:TPicture (картинка), Down:boolean(нажата), основное событие– OnClick. У этой кнопки есть еще несколько важных свойств. Для того чтобы кнопка могла быть нажата, ее свойство Group: integer должно быть больше нуля. В этом случае все кнопки с одинаковым значением группы становятся переключателями– если нажать одну, остальные отщелкиваются. Это может быть нежелательно в случае одной кнопкисненулевойгруппой–одинразнажав,еенельзяотключить.Вэтомслучаепоможет свойство AllowAllUp: boolean. Современныйвид кнопкам придает свойство Flat: boolean.
В программе откажемся от стандартного интерфейса MediaPlayer, и, сделав его невидимым, будем обращаться к нему через созданные кнопки. Коллекция иконок для кнопок находится в папке C:\Program Files\Common Files\Borland Shared\Images\Buttons\.
119
Настройка TrackBar проводится с помощью свойств ThumbLength:integer(длина бегунка), TickMarks:TTickMark(положение рисок линейки), TickStyle:TTickStyle(стиль рисок).
Настройтеформуи компоненты. Изменитеимена компонент.
1) ControlForm: TControlForm Caption = ‘медиафайл не загружен’ BorderStyle=bsToolWindow ClientHeight = 24
ClientWidth = 402
2) NewSpBtn: TSpeedButton
AllowAllUp = true
Flat=true Glyph: rety.bmp GroupIndex=1
3) PosTrk: TTrackBar
ThumbLength = 15
TickMarks=tmBoth
TickStyle=lsNone
4) PosTimer = TTimer Enabled = false Interval = 500
5) MediaOpenSpBtn: TSpeedButton
Flat=true
Glyph: MdOpen.bmp
6) PlaySpBtn: TSpeedButton
AllowAllUp = true
Flat=true
Glyph:vcrplay.bmp
GroupIndex=1
7) PlaySpBtn: TSpeedButton
AllowAllUp = true
Flat=true
Glyph: vcrpause.bmp
GroupIndex=1
8) StopSpBtn: TSpeedButton
AllowAllUp = true
Flat=true
Glyph: vcrstop.bmp
GroupIndex=1
12.Когдатребуетсяобратитьсяккаким-топеременным,функциям,типам,объектам, описанным в другом модуле, необходимо описать ссылку на этот модуль в разделеuses. Однако тонкость состоит в том, чтоuses может располагаться и в разделеinterface, и в разделе implementation. При запуске приложенияновое окно должно находиться под главным окном. Но если описать ссылки двух модулей друг на друга в разделахinterface, возникнет так называемая ошибка круговой ссылки. В рамкахPascal два модуля не могут использовать интерфейс друг друга. Ссылка в интерфейсе нужна для того, чтобы при описании типов, классов, переменных интерфейса использовать типы и константы, описанныевдругихмодулях.Вданноминтерфейсеиспользуется,кпримеру,классTForm, TSpeedButton, TTrackBar, TTimer, описанные, соответственно, в модулях Forms, Buttons, ComCtrls,ExtCtrls.Тоестьиспользованиедругихмодулейвинтерфейседаетвозможность, прежде всего, описать новые типы с помощью уже описанных типов. Именно поэтому
120
запрещена круговая ссылка. Тогда потенциально возможно было бы описать: TypeA = array[0..4]ofTypeB–водноммодулеиTypeB=array[0..99]ofTypeA–вдругом.Тоесть ignotumperignotius –неизвестноечерез еще более неизвестное (лат.).
Что же касается использования не типов, но конкретных переменных и объектов, фигурирующихвдругихформах,тоэтоиспользованиепроисходиткакразвimplementation, итуткруговыессылкивполнедопустимы.Приработеснесколькимиформамиважнотакже учитывать порядок их создания. Это касается обработки событийOnCreate– обращаться можно только к созданнымформам.
VarControlFom:TControlFom;
implementation
{$R*.DFM}
procedure TControlFom.FormCreate(Sender:Tobject);
begin
Top := MainForm.Top + MainForm.Height + 4;
Left := MainForm.Left;
end;
end.
Свои свойстваLeft иTop вторая форма подстраивает под те же свойства первой формы.Припопыткезапускапрограммы,однако,выводитсясообщениеотом,чтонеуказан модуль, в котором описанаперваяформа.
Рис. 84.
Еслинажатькнопку Yes,тов разделuses автоматическидобавится ссылкана нужный модуль. Однако, система не всегда автоматически работает. Лучше добавлять ссылки самостоятельно. В данномслучае– в раздел implementation.
implementation uses MainUnit;
ЗдесьидетобращениекMainForm,и даннаяформадолжнабытькэтомумоменту(то есть моментусоздания ControlForm) уже созданной.
Поумолчаниюприсозданииприложенияполагается,чтобыпризапускевыводилась толькоглавнаяформа.Однаковданномслучаевпрограммедолжныбытьвидныобеформы. Обязательно,уControlFormустановитьсвойствоVisible:=true.Иначеформабудетневидна при запуске программы.
121
Рис. 85.
Можно описать тот же код, с точностью до перемены ссылок, в обработчике MainForm.OnCreate главной формы. Для того чтобы выбрать нужный модуль, нажмите на кнопкупанели инструментов (выбрать модуль для редактирования). Соседняякнопкаслужит длявыбораформ(выбратьформудляредактирования).Следующаякнопка–переключатель модуль/форма.
Рис. 86.
Первая форма создается раньше второй. Следовательно, и событиеOnCreate у нее возникаетещедотого,каксозданавтораяформа,изначитпопыткадоступакней(попытка установить ее положение) вызовет ошибку.
13. Оставимглавной форме только предназначениеэкрана.Удалите код внутри обработчиков кнопок,а такжесами кнопки.
procedure TMainForm.MediaOpenBtnClick (Sender : TObject);
begin
end;
procedure TMainForm.SetColorBtnClick (Sender : TObject);
begin
end;
122
Установите медиапроигрывателю Visible := false, переместите его поверх панели. Если панель в форму добавлена позже проигрывателя, то проигрыватель окажется под панелью.Поэтомупредварительнопоменяйтепорядок –щелкнитеправойкнопкоймышина проигрыватель и выберите"BringToFront".
Рис. 87.
Теперь изменитеклиентскую высотуформы.Экран готов.
Рис. 88.
Теперь предстоит описать обработчики компонентов второй формы. Таймер будет передвигатьбегунок, отображая процент проигранной записи.
procedure TControlForm.PosTimerTimer(Sender: TObject);
begin
PosTrkBar.Position:=MainForm.MPlayer.Position;
end;
procedure TControlForm.PosTrkBarChange(Sender: TObject);
begin
if not PosTimer.Enabled then
MainForm.MPlayer.Position:=PosTrkBar.Position;
end;
В обработчикекнопки загрузки помещаетсякод, похожий на тот, чтоуже писали.
Код относится к компонентам главной формы. Из-за этого необходимо указывать вторую форму,когдаобращаютсякеекомпонентам,хотяитакнаходятсяся вобработчике второй формы.
Обратитевниманиенадватаймера –одинзапускаетвизуализацию,адругойдвигает бегунок. Передвижения бегунка действенны, только когда воспроизведение остановлено– PosTimer.Enabled:=false.Иначе происходитконфликт–таймерменяетпозициюбегунка,а
123
бегуноквответменяетпозициюпроигрывателя.Еслинеобходимоменятьпозициювовремя воспроизведения, придется вводить дополнительныепроверки.
Когда запись остановлена, можно поменять ее позицию тем же бегунком. Кнопки управленияпрограммнозапускаютиостанавливаютпроигрыватель.Покафайлнезагружен, их следует отключить, иначе при нажатии на них произойдет ошибка. Последняя кнопка определит, проигрывать ли запись в цикле.
procedureTControlForm.PlaySpBtnClick(Sender: TObject);
begin
MainForm.MPlayer.Play;
PosTimer.Enabled:=true;
end;
procedure TControlForm.PauseSpBtnClick(Sender: TObject);
begin
MainForm.MPlayer.Pause;
PosTimer.Enabled := false;
end;
procedure TControlForm.StopSpBtnClick(Sender: TObject);
begin
MainForm.MPlayer.Stop;
PosTimer.Enabled := false;
end;
Запуская и останавливая проигрыватель, мы запускаем и останавливаем таймер.
Необходимо внести измененияв код в модуле MainUnit,событие OnNotify проигрывателя:
procedure TMainForm.MPlayerNotify(Sender:TObject);
begin
if ControlForm.RewSpBtn.Down then
with MPlayer do
if NotifyValue = nvSuccessful then
begin
Notify:=true;
Play;
end;
end;
Здесь происходит проверка, зажата ли кнопка "цикличного воспроизведения" во второйформе.Приоткрытиифайланеобходимо включитьвсекнопкиибегунок(изначально Enabled :=false), запустить таймеры, настроить PosTrkBar на длину записи и вывести названиевоспроизводимого файла в Caption формы:
procedure TControlForm.MediaOpenSpBtnClick(Sender: TObject);
begin
with MainFormdo
if MediaOpenDlg.Execute then
begin
MPlayer.FileName := MediaOpenDlg.FileName;
MPlayer.Open;
MPlayer.Display := ScreenPanel;
124
MPlayer.DisplayRect:=Rect(0,0, ScreenPanel.Width, ScreenPanel.Height);
MPlayer.Play;
LifeImage.Visible :=not (ExtractFileExt(MPlayer.FileName) = '.avi');
LifeTimer.Enabled:=true;
ControlForm.PosTimer.Enabled:=true;
ControlForm.PosTrkBar.Max := MPlayer.Length;
ControlForm.PosTrkBar.Enabled:=true;
ControlForm.PlaySpBtn.Enabled:=true;
ControlForm.PauseSpBtn.Enabled := true;
ControlForm.StopSpBtn.Enabled:=true;
ControlForm.Caption := MediaOpenDlg.Filename;
end;
end;
14. Добавить к медиапроигрывателю игру«жизнь». Для управления визуализацией потребуется отдельная форма. С помощью этой формы можно очищать, заполнять и редактировать конфигурации клеток игры«Жизнь». Более того, появляется возможность сохранять интересные комбинации в специальные файлы с введенным нами расширением
.lif. Кроме того, можно будет управлять скоростью«жизни» и, что уже реализовывалось,
задавать цвет поля и клеток.
Создайте новую форму, сохраните ее модуль, поместите на нее пять кнопок Button, одну SpeedButton, один TrackBar, две надписи Label и диалоги загрузкии сохранения. Изменитепараметры компонент:
LifeSaveDlg: TSaveDialog
DefaultExt=‘lif’
Filter = ‘файлы игры «Жизнь» (*.lif)|*.lif’ Title=‘Загрузить позицию игры’ LifeOpenDlg: TOpenDialog
DefaultExt=‘lif’
Filter = ‘файлы игры «Жизнь» (*.lif)|*.lif’ Options.ofFileMustExist=true
Title=‘Сохранить текущую позицию игры’
Рис. 89.
В модуле второй формы добавьте строки, при открытии файла выводящие или скрывающие третью формуи отпускающиекнопку.
procedure TControlForm.MediaOpenSpBtnClick(Sender: TObject);
begin
with MainFormdo
if MediaOpenDlg.Execute then
125
begin
MPlayer.FileName := MediaOpenDlg.FileName;
MPlayer.Open;
MPlayer.Display := ScreenPanel;
MPlayer.DisplayRect:=Rect(0,0, ScreenPanel.Width, ScreenPanel.Height);
MPlayer.Play;
LifeImage.Visible :=not (ExtractFileExt(MPlayer.FileName) = '.avi');
LifeForm.Visible:=LifeImg.Visible;
LifeForm.EditSpBtn.Down := false;
LifeTimer.Enabled:=true;
ControlForm.PosTimer.Enabled:=true;
ControlForm.PosTrkBar.Max := MPlayer.Length;
ControlForm.PosTrkBar.Enabled:=true;
ControlForm.PlaySpBtn.Enabled:=true;
ControlForm.PauseSpBtn.Enabled := true;
ControlForm.StopSpBtn.Enabled:=true;
ControlForm.Caption := MediaOpenDlg.Filename;
end;
end;
На новой формеLifeForm располагаются кнопкиLifeOpenBtn,LifeSaveBtn,FillBtn, ClearBtn, SetColorBtn, EditSpBtn, SpeedTrkBar.Настройтекомпоненты новой формы:
LifeForm: TLifeForm BorderStyle=bsToolWindow Caption = ‘Визуализация’ ClientWidth = 402
ClientHeight = 56
EditSpBtn:TSpeedButton
AllowAllUp = true
Caption = ‘редактировать’ GroupIndex=1
SpeedTrkBar:TTrackBar
Frequency=50
Max=1000
Min = 1
Position = 100
ThumbLength = 15
TickMarks=tmTopLeft
Рис. 90.
В обработчикезагрузки медиафайланеобходимо добавитьследующиестроки.
LifeForm.Visible:=LifeImg.Visible;
ЕслиLifeImg видимый, т.е. нужна визуализация для звукового файла, то форма управления визуализацией тоже выводится, если же LifeImg спрятан (воспроизводится видеофайл), то и присутствиеформыуправления визуализациейизлишне. LifeForm.EditSpBtn.Down := false;
КнопкаEditSpBtnбудетотвечатьзаредактированиеклеток(еслионанажата,включен режимредактирования).ВовремяредактированиятаймерLifeTimerдолженбытьотключен.
126
Посколькуздесь,приоткрытии,мывключаемэтоттаймер,торежимредактированиядолжен быть отключен и кнопкаотпущена.
… MPlayer.Play;
LifeImg.Visible:= not(ExtractFileExt(MPlayer.FileName) = '.avi'); LifeForm.Visible:=LifeImage.Visible;
LifeForm.EditSpBtn.Down := false;LifeTimer.Enabled := true; ControlForm.PosTimer.Enabled:=true;
….
15. Необходимо описать обработчики событий для новых компонентов. Определим при создании формы ее местоположение.
В модуле LifeUnit:
var LifeForm: TLifeForm;
implementation
uses MainUnit, ControlUnit;
procedure TLifeForm.FormCreate(Sender: TObject);
begin
Top := ControlForm.Top + ControlForm.Height + 4;
Left := ControlForm.Left;
end;
Принажатиинакнопкиочисткиизаполнениямыиспользуемпроцедуры,описанные в модуле главной формы.
В модуле LifeUnit:
procedure TLifeForm.ClearBtnClick(Sender:TObject);
var
i,j:integer;
begin
fori:=0 to XSize - 1do
forj:=0 to YSize - 1do
A[i, j] := false;
DrawCells;
end;
procedure TLifeForm.FillBtnClick(Sender: TObject);
begin
RandomCells;
DrawCells;
end;
Однакодлятого,чтобыподобныйвызовбылвозможен,необходимов главноммодуле объявить эти процедуры в интерфейсе. Извне доступно только то, что объявлено в интерфейсе. В MainUnit необходимо "вывести" в интерфейсобъявлениепроцедур:
var
MainForm: TMainForm;
A: TLifeCells; procedure RandomCells; procedure DrawCells;
127
implementation uses ControlUnit;
{&r *.DFM}
ТrackBar устанавливает интервал для таймера, задавая тем самым скорость визуализации. А кнопка редактированияпереключает режимредактирования, останавливаяи включая таймер.
procedure TLifeForm.FillBtnClick(Sender: TObject);
begin
RandomCells;
DrawCells;
end;
procedure TLifeForm.SpeedTrkBarChange(Sender: TObject); {Меняет скорость«жизни»}
begin
MainForm.LifeTimer.Interval := SpeedTrkBar.Position;
end;
procedureTLifeForm.EditSpBtnClick(Sender:TObject);{включает/выключает режимредактирования}
begin
MainForm.LifeTimer.Enabled:=notEditSpBtn.Down;
end;
Само редактирование клеток происходит в главном модуле, в обработчике
OnMouseDown компонента LifeImg.
procedure TMainForm.LifeImgMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
ifLifeForm.EditSpBtn.Down then
A[X div10, Y div10]:=notA[X div10, Y div 10];
DrawCells;
end;
В uses нужно описать ссылкунаLifeUnit.
При запускепрограммы получается примернотакая картинка.
Рис. 91.
Теперь можно редактировать позиции.
128
16. Вначале при загрузке и сохранении картинок и прочих файлов использовались специальные методы объектов, в которые происходила загрузка. Теперь произведем эти операции вручную, пользуясьпроцедурами работы с типизированными файлами.
Типизированные файлы содержат записи определенного типа. К примеру,fileof integer может хранить произвольное количество переменных integer;fileof TLifeCells – произвольноеколичествопеременныхтипаTLifeCells.Однакодлянашихцелейдостаточно только одной записи. При работе с типизированными файлами используются следующие процедуры.
AssignFile(varF;FileName:string)–связываетфайловуюпеременнуюFстекстовымименем файла. Этодействиенеобходимо сделать перед всеми последующимиоперациями.
Reset(F) – открывает существующий файл, связанный с переменнойF, и устанавливает позицию чтения-записи в начало.
Rewrite(F)– создает файл, соответствующий файловой переменнойF.
Read(F,V)– читает из файла, связанного сF, данные в типизированную переменнуюV. Позиция файла увеличивается на один файловый компонент, байтовый размер которогоравен размерутипа переменной (для integer это 4 байта).
Write(F,V)–записываетвфайл,связанныйсF,типизированнуюпеременнуюV.Позиция файла увеличиваетсяна один файловыйкомпонент.
Seek(F,N:LongInt)– перемещает позицию файла к номеру N, начальнаяпозиция при N=0.
CloseFile(var F) – закрывает файл F.
В главноммодуле описан тип TFileCells:
{Privatedeclaration}
public
{Publicdeclaration}
end;
const
type
XSize = 40; YSize = 25;
TFileCells =array [0 .. XSize – 1, 0 .. YSize – 1]of boolean;
var
MainForm: TMainForm;
A: TFileCells;
ВобработчикеOnClickкнопкиLifeOpenопределяемфайлтакогожетипа.Еслифайл выбранвдиалоге,ассоциируемимяфайласпеременной,устанавливаемпозициюдлячтения вначалоисчитываемизфайладанныевпеременнуюA,описаннуювMainUnitихранящую положения клеток.
procedure TLifeForm.LifeOpenBtnClick(Sender: TObject);
var
F: file ofTLifeCells;
begin
ifLifeOpenDlg.Executethen
if FileExists(LifeOpenDlg.FileName) then
begin
AssignFile(F, LifeOpenDlg.FileName);
Reset(F);
Read(F, A);
129
CloseFile(F);
DrawCells;
end;
end;
Подобное чтение корректно, посколькутипы файла и переменной Aсовпадают.
Призаписивфайлситуацияпохожая,тольковдобавокпроводитсяпроверка,существуетли файл. Если нет, то он создается; если да, то должны спросить, действительно ли пользовательхочетегоперезаписать.Еслионпростоошибся,тозакрываемфайливыходим изобработчика;еслинужнопереписать,открываемегоиустанавливаемпозициюзаписив начало. Затемпроизводится запись переменной и закрытиефайла.
procedure TLifeForm.LifeSaveBtnClick(Sender: TObject);
var
F: file ofTLifeCells;
begin
ifLifeSaveDlg.Execute then
begin
AssignFile(F, LifeSaveDlg.FileName);
if not FileExists(LifeSaveDlg.FileName)then
Rewrite(F)
elseif MessageDlg('Перезаписать?', mtWarning, [mbYes, mbNo], 0) = mrYes then
Reset(F)
elsebegin
CloseFile(F);
exit;
end;
Write(F, A);
CloseFile(F);
end;
end;
Работа с нетипизированными файлами похожа на работу с типизированными. Отличиявтом,чтообъявляютсятакиефайлыпростоvarF:file;(безof…),приоткрытии– Reset(F,1)–нужноуказатьразмерблоказаписи(которыйпоумолчаниюравен128),чтение изаписьпроисходятспомощьюпроцедурBlockRead,BlockWirite(varF:File;varBuf;Count: Integer),гдеBuf–переменная,вкоторую(илиизкоторой)идетзапись,Count–числоблоков записи(размер блока был определен вReset). Если надо писать произвольные данные(к примеру,a:integer;b:boolean;c:TLifeCells; d: string[20]),сделайтеследующее.
При записи: Rewrite(F, 1);
BlockWrite(F, a, SizeOf(a)); BlockWrite(F, b, SizeOf(b)); BlockWrite(F, c, SizeOf(c)); BlockWrite(F, d, SizeOf(d)); CloseFile(F);
При чтении, соответственно: Reset(F,1);
BlockRead(F, a, SizeOf(a)); BlockRead(F, b, SizeOf(b)); BlockRead(F, c, SizeOf(c));
130
BlockRead(F, d, SizeOf(d)); CloseFile(F);
17. Чтобы решить проблему цвета, необходимо сделать специальное собственное диалоговое окно, позволяющее выбрать цвет.Раньше мы вызывали стандартныедиалоги.
Диалог– это обычная форма, которая, однако, вызывается специальным методом ShowModalивозвращаетмодальныйрезультат.Модальныйвызовприводитктому,чтопри выведенном диалогенельзяпереключиться никоднойдругойформеприложения,покане будетнажатаоднаизмодальныхкнопокдиалога,послечегодиалогзакроетсяиуправление вернетсявприложение.Модальнымкнопкамдажененадоописыватьобработчики.Просто надоустановить свойство ModalResult не равным mrNone.
Создайтеновую форму, сохранитемодуль как ColorUnit.Добавьте на нее две фигуры Shape (CellShape: TShape, FieldShape: TShape), кнопку «Утвердить» (ModalResult = mrOk), кнопку «Отмена»(ModalResult=mrCancel).
Рис. 92.
Настройте форму. В частности, задайте ее позицию и определите модальный результат для кнопок.
ColorForm: TColorForm BorderStyle=bsToolWindoiw Caption = выберитецвета Position = poScreenCenter
ВобработчикенажатиянафигурыShapeопишитевызовдиалгов.Обработчикидля кнопок можетене описывать.
В модуле ColorUnit – обработчики нажатияна FieldShapeи CellShape: procedure TColorForm.FieldShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
MainForm.FieldColorDlg.Execute;
FieldShape.Brush.Color := MainForm.FieldColorDlg.Color;
end;
procedure TColorForm.CellShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
MainForm.CellColorDlg.Execute;
131
CellShape.Brush.Color := MainForm.CellColorDlg.Color;
end;
В обработчике кнопки"задать цвета" на форме визуализации опишите модальный вызов этогонового диалога.
В модуле LifeUnit описываемобработчик SetColorBtn:
procedure TLifeForm.ColorBtnClick(Sender:TObject);
var
C1, C2: TColor;
begin
C1 := MainForm.FieldColorDlg.Color;
C2 := MainForm.CellColorDlg.Color;
ColorForm.FieldShape.Brush.Color := C1;
ColorForm.CellShape.Brush.Color := C2;
if ColorForm.ShowModal = mrCancel then
begin
MainForm.FieldColorDlg.Color := C1;
MainForm.CellColorDlg.Color := C2;
end;
end;
ВданномслучаевызываетсяформаColorForm–диалогустановкицвета.Есливнем нажатакнопка"Отмена",тозначенияцветоввосстанавливаются.Ониспециальнодляэтого перед вызовом сохраняются вC1 и C2.
18. Пользователь проигрывателя может случайно закрыть окно формы управления.
Следователь, придется перезапускать программу.
Можно решить эту проблему следующим образом. При попытке закрытия спросить пользователя, хочет ли он совсем выйти из программы. И если хочет – закрыть главную форму.
procedure TControlForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if MessageDlg('Выйтииз программы?', mtWarning,
[mbYes, mbNo], 0) = mrYes then MainForm.Close
elseCanClose:=false;
end;
Этойконструкциейзакрываетсяглавнаяформаизформыуправления.Тожесобытие можно обработать и в главной форме, каждыйраз спрашивая о желании выйти.
Запуститепрограмму.
Рис. 93.
132
19. Подведемитоги. Для создания многооконности необходимо:
1. Создать очередную форму.
2. Модули, предназначенные пользователю, поместить в interface, а модули,
предназначенныепрограммистуто, поместить в uses.
3. Необходимо помнить о круговых ссылкахи и избегать ignotum per ignotius. В
интерфейс поместить только необходимое.
4. В OnCreate делать описание, не забываяо порядкесоздания формв файле проекта.
5. Программа заканчивается, когда закрывается главная форма. Остальные формы приложения могут закрыватьсясколькоугодно.
6. Диалоги: вызов ShowModal, результат – ModalResult нажатой кнопки.
7. Выбрать нужнуюформу или модуль для редактирования можно с помощью кнопок панели инструментов или клавишами Ctrl-F12 и Shift-F12. Переключение модуль- форма – просто клавишей F12.