SNK Software
Web Studio Монополия Metaproducts Утилиты Игры
Монополию Web Studio Библиотека
Вебмастер Дельфи Работа на ПК Самоучитель
Для PHP Для Delphi
Веб-дизайн Программирование Компьютеры Девайсы Заметки
SNK Software Индустрия hardware Индустрия software
О студии Портфолио Сопровождение сайтов

Новые материалы

Девайсы:
Сравнительный обзор Nokia Lumia 920 и HTC 8X
Девайсы:
Обзор Nokia Lumia 820 – смартфона на WP8
Вебмастеру:
Настройка Apache, PHP и MySQL для Linux-VPS
Вебмастеру:
VPS на домашнем ПК: настройка сети в VM VirtualBox и Debian
Вебмастеру:
VPS на домашнем ПК: устанавливаем Linux Debian 6
Вебмастеру:
VPS на домашнем ПК: установка VM VirtualBox
Работа на компьютере:
Иные возможности текстового процессора Word
Работа на компьютере:
Вставка объектов
Работа на компьютере:
Таблицы в Word
Работа на компьютере:
Печать и сохранение документов
Работа на компьютере:
Сноски, колонтитулы, оглавление и указатели в Word

Работа с файлами и мультимедиа

Продолжая знакомство с библиотекой VCL, рассмотрим еще несколько групп компонентов, в частности, для работы с файлами, а так же компоненты для работы с графикой и видео. Здесь следует отметить, что данные компоненты, в отличие от уже рассмотренных диалогов или коллекции изображений, являются визуальными. Также примечателен тот факт, что некоторые компоненты для работы с файлами, которые мы рассмотрим в этой главе, относятся к группе 16-разрядных элементов интерфейса, т.е. достались в наследство со времен Windows 3.1 и Delphi 1. Тем не менее, во многих случаях их использование бывает вполне уместно.

Списки файлов и каталогов

Самый простой путь отображения содержимого дисков ПК в Delphi - это использование компонентов FileListBox (список файлов) и DirectoryListBox (список каталогов). Оба этих компонента появились еще в 1-й версии Delphi и относятся к группе компонент Win 3.1. Компонент списка файлов позволяет просматривать содержимое указанного каталога. Он является наследником обычного списка (ListBox) и имеет набор дополнительных свойств, определяемых собственной спецификой. С ними можно ознакомиться в таблице 15.1.

Таблица 15.1. Свойства FileListBox
СвойствоТипОписание
DirectoryStringОпределяет каталог, файлы которого должны отображаться в данном списке
DriveCharОпределяет букву диска, файлы которого должны отображаться в данном списке
FileEditTEditСвязывает данный список с полем редактирования, в котором будет отображаться выбранный файл
FileNameStringОпределяет имя текущего выбранного файла в списке (включая путь файла)
FileTypeTFileTypeОпределяет, файлы какого типа (по атрибутам) должны отображаться в списке
MaskStringОграничивает видимые в списке файлы по маске
ShowGlyphsBooleanУказывает, должны ли отображаться иконки файлов, коих предусмотрено всего 2 типа - доя выполняемых и для остальных

Следует учитывать, что ряд свойств, в частности, Directory, Drive и FileName являются взаимозависимыми. Т.е., скажем, установив определенное значение для FileName, вы можете параллельно изменить Drive и Directory (например, если файл находится на другом диске). Свойства FileType и Mask позволяют ограничить отображаемые файлы, отбирая их по принципу принадлежности к той или иной группе по атрибутам (FileType) или по шаблону имени (Mask). Шаблон задается в соответствии с обычными для Windows правилами подстановки масок, т.е. с использованием подстановочных знаков "*" и "?". Что касается атрибутов, то для свойства FileType предусмотрены следующие флаги:

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

В то же время, не будем забывать, что у нас имеется еще один компонент - DirectoryListBox, который как раз и предназначен для навигации по каталогам диска. Он имеет всего 4 собственных свойства - Directory, DirLabel, Drive и FileList. При этом свойства Drive и Directory полностью аналогичны таковым у FileListBox, а свойство DirLabel весьма похоже на FileEdit, с той лишь разницей, что если с FileListBox ассоциируется однострочный редактор, то с DirLabel - метка, свойство Caption которой и подлежит изменению в зависимости от выбранного каталога.

Последнее свойство DirectoryListBox - FileList. Оно служит для ассоциирования данного списка каталогов с компонентом - списком файлов. Имея связанные таким образом компоненты, мы получим автоматически работающую связку, в которой при изменении текущего каталога в списке каталогов, будет автоматически производиться смена каталога в ассоциированном списке файлов.

Рассмотрим эту пару компонент на простом примере. Для этого создадим приложение и поместим на его главную форму следующие компоненты, разместив их один под другим: Label, DirectoryListBox, Edit и FileListBox. Назовем их DirLbl, DirLst, FileEd и FileLst, после чего установим свойство DirLabel списка каталогов в DirLbl, его же свойство FileList - в FileLst, а свойство FileEdit списка файлов - в FileEd. Саму программу можно назвать FileView, или FV. Запустив приложение, можно будет убедиться, что в зависимости от того, какой каталог в списке каталогов выбран, меняется надпись метки и содержимое списка файлов, а при выборе файла его имя отображается в текстовом редакторе (рис. 15.1).

Работа программы на Delphi для просмотра содержимого каталогов
Рис. 15.1. Работа программы просмотра содержимого каталогов

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

Файловые компоненты - списки

В только что рассмотренном примере программы для просмотра файлов явно не хватает возможности выбора диска. Для этих целей предусмотрен отдельный компонент, DriveComboBox - список дисков, в котором в виде ниспадающего списка отображаются все дисковые устройства ПК. Нетрудно догадаться, что этот компонент основан на обычном комбинированном списке (ComboBox), а все его отличия заключаются в нескольких дополнительных свойствах, связанных со спецификой применения этого компонента. Всего таких свойств 3 - DirList, Drive и TextCase.

Свойство DirList предназначено для ассоциирования списка дисков со списком каталогов, а свойство Drive указывает или задает букву выбранного диска. Таким образом, если поместить на форму нашего приложения (FileView) этот компонент и установить его свойство DirList в значение DirLst, то мы получим уже полностью функциональную программу для просмотра содержимого всех дисков компьютера.

Что касается свойства TextCase, то оно определяет, в каком регистре должны выводиться метки дисков: если установлено принятое по умолчанию значение tcLowerCase, то метки дисков будут отображаться в нижнем регистре, а если tcUpperCase, то в верхнем.

Теперь нам остается рассмотреть последний компонент, относящийся к группе унаследованных элементов управления файлами. Это список фильтров - FilterComboBox, который обеспечивает возможность быстрой установки фильтра (маски) для списка файлов. Подобно списку дисков, список фильтров основан на комбинированном списке, и так же имеет 3 собственных свойства, а именно FileList, Filter и Mask. Очевидно, что свойство FileList служит для ассоциирования этого компонента со списком файлов, а свойство Filter определяет сами фильтры. При этом синтаксис для определения фильтров у FilterComboBox полностью соответствует таковому у файловых диалогов. Наконец, свойство Mask позволяет узнать, какой именно фильтр используется в данный момент.

Таким образом, чтобы посмотреть, как взаимодействует "полный комплект" компонент управления файлами, поместим в самый низ формы список фильтров, и для свойства FileList укажем FileLst. Теперь можно определить сами фильтры: по умолчанию предлагается "All Files" (все файлы), заданный шаблоном "*.*". К нему можно добавить, скажем, "программы", задав шаблон "*.exe". Теперь остается запустить приложение и убедиться, что изменение фильтра непосредственно влияет на содержимое списка (рис. 15.2).

Полноценный просмотр содержимого дисков ПК
Рис. 15.2. Полноценный просмотр содержимого дисков ПК

Вновь отметим тот факт, что ни одной строчки кода для этого приложения так и не было написано!

Отображение графических изображений

Для отображения графических изображений используют компонент Image - изображение, относящийся к группе дополнительных (Additional) компонент. Обычно его помещают на поверхность формы и используют для отображения рисунков, в том числе, хранящихся в виде файлов. Компонент Image является наследником класса TGraphicControl и имеет несколько собственных свойств, связанных с графикой. Прежде всего, это самое главное свойство Image - Picture, которое служит для непосредственной работы с изображениями и имеет тип TPicture. Позже мы рассмотрим этот класс подробнее, пока же примем к сведению, что все операции над самим изображением (включая загрузку файла) выполняется посредством этого свойства.

Остальные свойства Image относятся к способам размещения изображения в рамках данного компонента. Так, свойство Center определяет, должно ли изображение быть размещено по центру (истина), или нет (ложь), в последнем случае оно будет выровнено по левому верхнему углу. Еще 2 свойства - Stretch и Proportional отвечают за масштабирование изображения. Так, если свойство Stretch установлено в истину, то изображение будет занимать все пространство, отведенное для компонента Image. Если оно при этом меньше, то оно будет увеличено, если больше - то сжато. При этом пропорции (отношение ширины к высоте) самого изображения не учитываются, что обычно приводит к искажениям. Поэтому, начиная с Delphi 6, было введено еще одно свойство - Proportional. Если оно установлено в истину, то изображение в любом случае сохранит свои исходные пропорции. Кроме того, если оно меньше, чем область, отведенная для изображения, то оно останется в исходных размерах, если только свойство Stretch так же не установлено в истину. Если же рисунок больше, то, вне зависимости от значения, заданного для Stretch, он будет пропорционально уменьшен до такого размера, чтобы поместиться в области компонента Image.

Свойство Transparent отвечает за прозрачность фоновых участков изображения: когда оно установлено в истину, фоновый цвет на рисунке заменяется прозрачным фоном. Правда, данный эффект распространяется не на все типы изображений.

Наконец, еще одно свойство, IncrementalDisplay, позволяет выбирать режим показа изображений: если установить его в истину, то файлы будут отображаться постепенно, по мере считывания и раскодирования. Это может быть актуально для больших сжатых файлов, например, для 5-мегапиксельных JPEG-изображений, особенно сохраненных в высоком качестве. При этом можно получать информацию о ходе загрузки изображения при помощи обработки события OnProgress. Это единственное собственное событие рассматриваемого компонента. Оно имеет тип TProgressEvent, для которого определен следующий синтаксис:

procedure (Sender: TObject; Stage: TProgressStage; PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: string) of object;

Аргумент Sender, как обычно, ссылается на объект, получивший уведомление о событии. Приблизительный процент выполнения операции можно получить, обратившись к PersentDone, а общее состояние - начало загрузки (psStarting), выполнение загрузки (psRunning) и завершение загрузки (psEnding) - к Stage. Ну а RedrawNow показывает, может ли быть отображена уже загруженная часть изображения, определяемая координатами прямоугольника R. На практике обычно используют только PercentDone, да и то следует учитывать, что это актуально только для файлов JPEG:

ProgressBar1.Position:=PercentDone;

Создадим простейшее приложение, которое может отображать рисунки. Для этого на форме, помимо Image, нам понадобятся следующие компоненты:

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

Сам код программы сводится всего лишь к 2 процедурам: обработчику OnClock копки, и обработчику OnProgress изображения. В результате мы получим код, приведенный в листинге 15.1.

Листинг 15.1. Простейшее приложение для просмотра рисунков

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, StdCtrls, jpeg; type TForm1 = class(TForm) Img: TImage; OpenBtn: TButton; ProgressBar: TProgressBar; OpenDlg: TOpenDialog; Bevel1: TBevel; procedure OpenBtnClick(Sender: TObject); procedure ImgProgress(Sender: TObject; Stage: TProgressStage; PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: String); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.OpenBtnClick(Sender: TObject); begin if OpenDlg.Execute then Img.Picture.LoadFromFile(OpenDlg.FileName); end; procedure TForm1.ImgProgress(Sender: TObject; Stage: TProgressStage; PercentDone: Byte; RedrawNow: Boolean; const R: TRect; const Msg: String); begin ProgressBar.Position:=PercentDone; if RedrawNow then Img.Repaint; end; end.

Чтобы можно было просматривать достаточно большие рисунки, не помещающиеся целиком в отведенную область, следует установить свойство Proportional компонента Img в истину, а для лучшего эстетического восприятия не помешает его еще и разместить по центру, установив в истину так же и свойство Center. Этот пример можно найти в каталоге Demo\Part3\SimpleImg.

Классы TPicture и TGraphic

Как уже было отмечено, важнейшей частью компонента Image является свойство Picture (рисунок), имеющее тип TPicture. Именно оно используется для работы с самим изображением, включая такие операции, как чтение из файла и запись в файл. Оригинальный размер изображения так же доступен через свойства Height и Width рисунка. В свою очередь, класс TPicture включает в себя несколько свойств, основанных на классе TGraphic, которые собственно и могут содержать само изображение. Всего предусмотрено несколько таких свойств:

Кроме них, существует еще свойство Graphic, которое ссылается на картинку вне зависимости от конкретного формата и имеет такие общие для всех рисунков свойства, как Height, Width и Transparent. Поэтому в тех случаях, когда тип изображения заведомо неизвестен, следует использовать именно это свойство. Более того, если используются нестандартные для Windows и Delphi типы графических фалов (взять тот же JPEG, который является опциональным в VCL), то только через свойство Graphic к нему и можно будет обращаться для того, чтобы, скажем, узнать размеры. Собственно говоря, когда используются свойства Height или Width объекта Picture, то они берут значения как раз от этого объекта.

Вообще можно отметить, что компонент Image является всего лишь полем для отображения изображений, поддержка которых полностью возложена на класс TPicture и его дочерние свойства, основанные на TGraphic. Единственной его особенностью являются сервисные функции для масштабирования изображений. В то же время, если этого не требуется, то можно просто создать программными методами экземпляр класса TPicture и выводить изображение на поверхность любого компонента, имеющего свойство Canvas:

var Pic: TPicture; ... Pic:=TPicture.Create; Pic.LoadFromFile('c:\mypicture.bmp'); Form1.Canvas.Draw(1,1,Pic.Graphic);

Кроме того, "сам по себе" класс TPicture может быть полезным при работе с таким компонентом, как ImageList. Например, можно сделать так, чтобы рисунки для изображений меню или панелей инструментов загружались из отдельного файла. В таком случае даже помещать ImageList на форму во время проектирования приложения, в обще-то не обязательно - все можно делать во время работы приложения. Кроме того, поскольку формат файл заранее известен - это будет BMP, то использовать класс TPicture так же нет необходимости, проще будет сразу обратиться к классу TBitmap - все равно TPicture будет просто переадресовывать все обращения к своему свойству Bitmap:

var ImgLst: TImageList; Bmp: TBitmap; ... ImgLst:=TImageList.Create; Bmp:=TPicture.Create; Bmp.LoadFromFile('tools.bmp'); Bmp.Transparent:=true; ImgList.AddMasked(Bmp,Bmp.TransparentColor);

Но в ряде иных случаев использование самого класса TPicture может быть более предпочтительным по той причине, что таким образом можно обеспечить поддержку других форматов. Для примера рассмотрим приложение, которое сможет не только показывать, но и создавать графические файлы. Для этого нам понадобится создать новое приложение, на главной форме которого расположим какой-либо объект, на поверхности которого можно рисовать, скажем, тот же Image. По традиции, назовем форму MainFrm, а изображение - Img. Затем поместим на форме 2 кнопки и назовем одну InsertBtn (вставить), а другую - SaveBtn (сохранить). Так же нам потребуется 2 диалога - для того, чтобы открывать и сохранять картинки. Используем специализированные диалоги OpenPictureDialog (OpenPicDlg) и SavePictureDialog (SavePicDlg).

Для того чтобы область, выделенная для творчества, была изначально заполнена белым фоном, имитируя лист бумаги, для события OnCreate или OnShow формы можно предусмотреть следующий код:

Img.Canvas.Brush.Color:=clWhite; Img.Canvas.FillRect(Rect(0,0,Img.Width,Img.Height));

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

procedure TMainFrm.InsertBtnClick(Sender: TObject); var Pic: TPicture; begin if not OpenPicDlg.Execute then exit; Pic:=TPicture.Create; Pic.LoadFromFile(OpenPicDlg.FileName); Img.Canvas.Draw((Img.Width-Pic.Width) div 2,(Img.Height-Pic.Height) div 2,Pic.Graphic); Pic.Free; end;

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

Но это еще не все: все-таки составлять коллажи - не единственная возможность, предоставляемая холстом. Можно на нем просто рисовать, что уже было рассмотрено в предыдущей части книги. Между тем, мы можем не просто выводить какие-либо предопределенные фигуры, но и предоставить пользователю возможность нарисовать что-либо. Пусть это будут хотя бы простые линии, которые будут появляться после того, как пользователь нажмет на левую клавишу мышки, переместит указатель, и отпустит клавишу. Для этого мы задействуем обработчики событий OnMouseDown и OnMouseUp для объекта Img, и используем методы MoveTo и LineTo его холста:

procedure TMainFrm.ImgMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Img.Canvas.MoveTo(X,Y); end; procedure TMainFrm.ImgMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Img.Canvas.LineTo(X,Y); end;

Наконец, нам остается реализовать возможность сохранения того, что в данный момент отображается в Img. Для этого нам и пригодится 2-я кнопка, код для которой будет выглядеть следующим образом:

if SavePicDlg.Execute then Img.Picture.SaveToFile(SavePicDlg.FileName);

Таким образом, все, что нарисовано на холсте, может быть без каких-либо ухищрений сохранено в качестве обычного файла в формате Windows Bitmap. Исходный код этой программы можно найти в каталоге Demo\Part3\PicEdit.

Пример программы просмотра графики

Теперь, когда мы разобрались с графикой в Delphi, попробуем создать более удобную программу для просмотра графических изображений. За основу возьмем программу для просмотра файлов - FileView, поскольку она уже содержит все необходимое для того, чтобы пользователь мог осуществлять навигацию по файловой системе своего ПК. Но прежде нам понадобится сделать некоторые изменения, в частности, было бы полезно переместить все имеющиеся компоненты непосредственно с поверхности формы на панель. Для этого сначала выделим все компоненты формы и вырежем их в буфер обмена (Ctrl+X). Затем поместим на форму панель и для ее свойства Align установим значение alLeft, в результате чего она займет все пространство по левому краю формы. Убедившись, что панель в данный момент является выбранным компонентом, произведем вставку из буфера обмена (Ctrl+V). Все ранее удаленные с поверхности формы компоненты появятся в том же виде на поверхности панели.

Разобравшись с компонентами, обеспечивающими навигацию по файлам, на пустующую правую часть формы поместим компонент ScrollBox, который находится на закладке Additional палитры компонентов. Этот компонент позволяет размещать объекты, размеры которых могут превышать отведенное для них на форме пространство. Чтобы он занял все оставшееся место, установим для него значение свойства Align в alClient, после чего поместим на него компонент Image, выровняв его по левому верхнему углу (т.е. установив свойства Left и Top в 0). Чтобы компонент мог отобразить изображение любого размера, установим его свойство AutoSize в истину.

После этого нам остается внести некоторые изменения в свойство Filter компонента-списка фильтров (назовем его FilterCb). А именно, при помощи редактора фильтра, вместо первой строки "Все программы", напишем "Все изображения" и установим следующий список расширений: "*.jpg;*.jpeg;*.bmp;*.ico;*.emf;*.wmf", после чего не забудем дописать модуль jpeg в uses. Так же можно предусмотреть возможность отбора всех этих типы файлов по отдельности, например, "Изображения в формате JPEG" с фильтром "*.jpg;*.jpeg".

Убедимся, что все компоненты правильно именованы (скажем, Image - Img, а ScrollBox - ImgSb) и приступим к написанию кода - на сей раз нам без этого не обойтись, хотя кода и потребуется всего одна строчка:

Img.Picture.LoadFromFile(FileLst.FileName);

Вопрос может быть только в том, в ответ на какое событие должен исполняться данный код. Вариантов может быт несколько, но ограничимся двойным щелчком мышкой по списку файлов, т.е. помести его в процедуру TMainFrm.FileLstDblClick. Таким образом, запустив приложение, можно выбрать любой графический файл из поддерживаемых программой форматов. Впрочем, учитывая настройки фильтра, только такие и будут отображаться в списке. Наконец, остается дважды щелкнуть по выбранному файлу, чтобы открыть его для просмотра. Если при этом изображение не будет помещаться целиком в области ScrollBox, то автоматически появятся полосы прокрутки (рис. 15.3).

Программа просмотра изображений на Delphi
Рис. 15.3. Программа просмотра изображений

Вместе с тем, в такой программе не помешало бы иметь возможность увидеть все изображение сразу, пусть и в уменьшенном масштабе. Реализовать переключение между режимами просмотра можно так же по двойному щелчку мышкой, но только уже не по списку файлов, а по самому изображению. Так что для элемента Img создадим следующий обработчик события OnDblClick:

procedure TMainFrm.ImgDblClick(Sender: TObject); begin Img.Proportional:=not Img.Proportional; if Img.Proportional then Img.Align:=alClient else Img.Align:=alNone; end;

В приведенном коде сначала значение свойства Proportional меняется на противоположное, после чего, в зависимости от того, включено ли масштабирование, изменяется свойство Align изображения. Суть тут в том, что если свойство Align компонента, помещенного в область прокрутки, установлено в alClient, то размеры этого компонента не могут быть больше, чем видимая часть области прокрутки. Если же размещение не задано (alNone), то, учитывая заданное нами изначально значение истины для свойства AutoSize элемента Img, этот компонент займет столько места, сколько необходимо для того, чтобы полностью показать все изображение.

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

Компонент MediaPlayer

Если для просмотра графических изображений используется обычный компонент Delphi, реализованный в самой VCL, то для просмотра или прослушивания мультимедийных данных используется системный компонент - MediaPlayer, расположенный на закладке System палитры компонентов. Суть системных компонент состоит в том, что практически все задачи по их работоспособности возлагаются на операционную систему, а в VCL лишь реализован простой интерфейс для доступа к функциям, предоставляемым ОС. В то же время, сам компонент MediaPlayer является обычным визуальным компонентом, основанным на TWinControl, а его "системность" проявляется лишь в виде функций, которые через его посредство реализуются.

Всего у этого компонента довольно много собственных свойств, что объясняется тем, что он, с одной стороны, предоставляет пользовательский интерфейс, а с другой - должен обеспечивать управление различными мультимедийными устройствами. Фактически, мы имеем дело с визуальным компонентом, обеспечивающим интерфейс и, одновременно, - с неким системным плеером. Список ряда свойств компонента MediaPlayer приведен в таблице15.2.

Таблица 15.2. Свойства компонента MediaPlayer
СвойствоТипОписание
AutoEnableBooleanОпределяет, должен ли компонент автоматически делать доступными или недоступными свои кнопки
AutoOpenBooleanОпределяет, должен ли плеер открываться автоматически при запуске приложения
AutoRewindBooleanОпределяет, должен ли плеер переходить к началу записи перед следующим воспроизведением
ColoredButtonsTButtonSetОпределяет, какие из кнопок компонента должны быть цветными (по умолчанию все)
DeviceTypeTMPDeviceTypesОпределяет тип мультимедийного устройства
DisplayTWinControlОпределяет оконный элемент интерфейса для вывода изображения
DisplayRectTRectОпределяет прямоугольную область для вывода изображения
EnabledButtonsTButtonSetОпределяет, какие из кнопок компонента должны быть доступными
ErrorLongintУказывает на код ошибки интерфайса MCI
ErrorMessageStringОписывает тип ошибки MCI
FileNameStringОпределяет имя файла для воспроизведения
LengthLongintУказывает на продолжительность текущей записи
ModeTMPModesУказывает на текущий режим плеера
PositionLongintОпределяет текущую позицию воспроизведения в записи
ShareableBooleanОпределяет, может ли выбранное устройство одновременно использоваться другими приложениями
TrackLengthLongintУказывает на продолжительность дорожки
TrackPositionLongintУказывает на насчальную позицию дророжки
TracksLongintУказывает на число дорожек
VisibleButtonsTButtonSetОпределяет, какие из кнопок компонента должны отображаться

Начнем со свойств, относящихся к внешнему виду компонента. Прежде всего, это ColoredButtons, EnabledButtons и VisibleButtons. С помощью этих свойств можно управлять доступностью и видом отдельных кнопок компонента. Всего кнопок 9, по числу основных операций, необходимых для устройства воспроизведения типа проигрывателя CD. Если же проигрывать компакт-диски не планируется, то вполне можно обойтись без кнопки выброса (btEject), равно как может быть излишним и наличие кнопок перехода между дорожками (btNext и btPrev). Кнопка записи (btRecord) также является ненужной, если речь идет именно о плеере.

Некоторые свойства необходимы только для определенных устройств воспроизведения, например, свойство Display актуально только для данных, имеющих видеоряд. Тип устройства задается свойством DeviceType, которое может принимать одно из следующих значений:

В то же время, в типичном случае оставляют принятое по умолчанию значение dtAuto, поскольку, за исключением CD и MIDI, остальные типы из реально встречающихся сейчас файлов не используются (тип dtAVIvideo подразумевает именно формат AVI, а не MPEG). Поддержка конкретных типов воспроизводимых файлов полностью лежит на ОС и установленных программах-кодеках, так что компонент MediaPlayer может воспроизводить все те же данные, что и Windows Media Player.

В простейшем случае, когда требуется только возможность проигрывания Audio-CD, достаточно просто поместить компонент на форму и установить свойство DeviceType в dtCDAudio, а AutoOpen - в истину. После этого останется лишь запустить приложение и нажать на кнопку Play, и если в приводе окажется диск формата CD-DA, то начнется его воспроизведение.

Если же надо создать универсальный проигрыватель, то потребуется оставить эти свойства как принято по умолчанию - DeviceType в dtAutoSelect, а AutoOpen - в ложь. При этом надо будет предусмотреть код, который будет устанавливать значение свойства FileName, если только не стоит задача воспроизводить один и тот же файл. Более того, для обычного проигрывателя многие кнопки будут лишними. кроме того, у компонента MediaPlayer имеется ряд методов, дублирующих нажатие на кнопки. А именно, Play, Stop, Back, Next и т.д. Но наиболее важными являются методы Open и Close. Первый делает плеер доступным, открывая интерфейс MDI, а второй, наоборот, закрывает. При этом следует учитывать, что открывать интерфейс можно только после того, как определен файл. Соответственно, если допустить, что на форме имеется проигрыватель (MediaMP), диалог открытия файла (OpenDlg) и кнопка "Открыть файл", то для нее код получится следующим:

if not OpenDlg.Execute then exit; MediaMP.Close; MediaMP.FileName:=OpenDlg.FileName; MediaMP.Open;

Если добавить еще строку с обращением к методу Play, то воспроизведение начнется автоматически. В то же время, если уж и создавать проигрыватель, то понадобится дать возможность остановить и продолжить просмотр. Итого получим 3 кнопки. Что касается компонента MediaPlayer, то нам от него понадобится лишь взаимодействие с системой, таким образом можно будет сделать его невидимым, установив свойство Visible в ложь. Вместе с тем, для вывода видео нам понадобится какой-либо компонент, происходящий от TWinControl, и обычная панель для этих целей вполне пригодна. Единственный вопрос может заключаться в том, что размеры видео могут быть больше, чем отведено пространства на панели. В таком случае нам поможет свойство DisplayRect, при помощи которого можно не только узнать размеры кадра, но и установить нужное. Поскольку при этом важно не нарушить пропорции, то проверять придется отдельно высоту и ширину, и вычислять нужный коэффициент масштабирования. Таким образом, нам надо будет сначала вычислить оба коэффициента, а затем в качестве окончательного взять больший.

var kw, kh, k: real; ... kw:=MediaMP.DisplayRect.Right/VideoPan.Width; kh:=MediaMP.DisplayRect.Bottom/VideoPan.Height; if (kw>1) or (kh>1) then begin if kh>kw then k:=kh else k:=kw; end else k:=1;

После этого останется лишь вычислить окончательные размеры изображения и установить получившиеся значения свойству DisplayRect, чтобы любой клип "вписался" в область просмотра, а новые значения можно вывести в окне заголовка (рис. 15.4).

Воспроизведение видео MPEG4 с масштабированием в Delphi
Рис. 15.4. Воспроизведение видео MPEG4 с масштабированием

Полный код приложения находится в каталоге Demo\Part3\Mplay.

Компоненты Timer и PaintBox

По соседству с MediaPlayer на закладке System располагаются еще несколько компонентов, среди которых - Timer и PaintBox. Компонент PaintBox, или область рисования, являются упрощенным вариантом компонента Image: на нем можно рисовать, но он не содержит свойств, при помощи которых можно было бы ассоциировать с ним изображение. Фактически, основным предназначением этого компонента является вывод графики через его холст (свойство Canvas). Собственно говоря, никаких иных свойств, кроме унаследованных от класса TGraphicControl, этот компонент и не имеет, так что можно считать его практическим воплощением этого класса.

Другой компонент - Timer, или таймер - это невизуальный компонент, который инкапсулирует в себе функции Windows API по взаимодействию с системным таймером. Он имеет всего 2 свойства - Enabled и Interval. Свойство Enabled делает таймер активным или неактивным, а свойство Interval задает промежуток времени (в миллисекундах), через который будет возникать событие OnTimer. Событие OnTimer - это единственное событие этого компонента, оно происходит, через промежуток времени, заданный свойством Interval, если свойство Enabled установлено в истину.

Применение таймера может быть самым разнообразным, но первое, что приходит на ум - это реализация часов. Некоторые старожилы, возможно, помнят те времена, когда на компьютерах устанавливалась система Windows 3.1. Нас она в данном случае интересует с той точки зрения, что в ней была программа, представляющая собой часы, выглядящие как аналоговые. Попробуем реализовать такую программу для современных версий Windows, воспользовавшись компонентами Timer и PaintBox.

Для начала создадим новое приложение, назовем его Clock, а главную форму, по традиции - MainFrm. Затем поместим на форму метку, чтобы видеть время в цифровом формате (назовем ее DigitalLbl), и область рисования для отображения времени в аналоговом формате (AnalogPB). Зададим для метки крупный шрифт, а для области рисования установим размер 110 на 110 точек. Ну и, разумеется, нужен еще и сам таймер - назовем его ClockTmr.

Начнем с самого простого - вывода времени в цифровом формате. Для этого в обработчике события OnTimer достаточно написать всего одну строчку:

DigitalLbl.Caption:=TimeToStr(now);

Если учитывать, что по умолчанию принят интервал в 1 секунду, а сам таймер активен, то мы получим работающие часы. Кроме того, можно добавить вывод времени непосредственно в заголовок приложения, чтобы даже в свернутом виде можно было узнать время, взглянув на панель задач. Для этого достаточно изменять значение свойства Title глобального объекта Application:

Application.Title:=DigitalLbl.Caption;

Но, разумеется, гораздо больше кода потребуется написать для того, чтобы выводить время в аналоговом формате. Создадим для этих целей отдельную функцию-метод формы, которая будет принимать значение времени и выводить его на циферблате. Соответственно, она будет находиться в части public класса TMainFrm и будет определяться следующим образом:

procedure DrawClock(t: TTime);

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

AnalogPB.Canvas.Brush.Color:=clWhite; AnalogPB.Canvas.Ellipse(3,3,108,108);

Затем начертим метки, но для начала определим интервал шага по окружности. Раз мы делаем часы, то пусть этот шаг будет равен 60. Соответственно, по известной формуле, мы получим размер шага (назовем его step, это должна быть переменная типа Double), равный 2?/60:

step:=2*pi/60;

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

for i:=0 to 11 do begin AnalogPB.Canvas.MoveTo(55,55); x:=55+Round(52*sin(i*step*5)); //55 - центр окружности, 52 - длина линии y:=55-Round(52*cos(i*step*5)); AnalogPB.Canvas.LineTo(x,y); end;

В результате мы получим "пирог", поделенный на 12 частей (рис. 15.5, слева). Скроем часть линий, нарисовав поверх них еще одну окружность меньшего диаметра, чтобы получить более похожее на настоящее часы оформление (рис. 15.5, справа):

AnalogPB.Canvas.Ellipse(7,7,104,104);

Подготовка аналоговых часов в Delphi
Рис. 15.5. Подготовка циферблата аналоговых часов

Итак, циферблат готов, можно приступить к стрелкам. В качестве подготовительной работы разложим полученное процедурой время (t) на составляющие - часы, минуты и секунды, для чего нам понадобятся 4 целых переменных типа Word:

var h,m,s,ms: word; ... DecodeTime(t,h,m,s,ms);

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

AnalogPB.Canvas.MoveTo(55,55); x:=55+Round(49*sin(s*step)); y:=55-Round(49*cos(s*step)); AnalogPB.Canvas.Pen.Color:=clGray; AnalogPB.Canvas.LineTo(x,y);

Следующей будет минутная стрелка. Поскольку минут тоже 60, то, в простейшем случае, для вычисления координат окончания линии мы могли бы воспользоваться той же формулой, что и для секунд, заменив лишь переменную s на m. Но если для секундной стрелки дискретное движение нормально, то для минутной не совсем годится (а для часовой будет вообще не приемлемо). Поэтому нам придется вычислять промежуточное значение, чтобы учитывать секунды, прошедшие с начала минуты:

c:=(m*60+s)/60;

Соответственно, после этого останется вычислить координаты на основе получившегося значения, не забыв вернуть черный цвет и сделать стрелку короче:

x:=55+Round(43*sin(c*step)); y:=55-Round(43*cos(c*step)); AnalogPB.Canvas.Pen.Color:=clBlack; AnalogPB.Canvas.LineTo(x,y);

На последок определимся с часами. Здесь, помимо уже известного решения проблемы с плавным перемещением стрелки, имеется еще 2 вопроса, а именно - необходимость повышающего коэффициента перемещения (т.к. часов меньше 60), и перевод 24-часового формата в 12-часовой. Вопрос с форматом решается просто: достаточно проверять переменную h на то, не больше ли она 12, и если да - то уменьшать ее на 12. На этом основании можно будет вводить коэффициент, равный 5 (60/12):

if h>12 then h:=h-12; c:=(h*60+m)/60*5;

После этого остается вычислить значения и нарисовать короткую толстую стрелку, не забыв после этого вернуть толщину линии обратно:

x:=55+Round(33*sin(c*step)); y:=55-Round(33*cos(c*step)); AnalogPB.Canvas.Pen.Width:=2; AnalogPB.Canvas.LineTo(x,y); AnalogPB.Canvas.Pen.Width:=1;

Последним штрихом может быть изменение оформление окна - для такого приложения лучше всего будет установить свойство BorderStyle в bsToolWindow (рис. 15.6).

Работающие аналоговые часы, написанные на Delphi
Рис. 15.6. Работающие "аналоговые" часы, написанные на Delphi

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

Листинг 15.2. Часы

unit main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TMainFrm = class(TForm) ClockTmr: TTimer; DigitalLbl: TLabel; AnalogPB: TPaintBox; AlphaTmr: TTimer; procedure ClockTmrTimer(Sender: TObject); procedure FormCreate(Sender: TObject); public procedure DrawClock(t: TTime); end; var MainFrm: TMainFrm; implementation {$R *.dfm} procedure TMainFrm.ClockTmrTimer(Sender: TObject); begin DigitalLbl.Caption:=TimeToStr(now); Application.Title:=DigitalLbl.Caption; DrawClock(now); end; procedure TMainFrm.DrawClock(t: TTime); var x,y,i: integer; h,m,s,ms: word; step,c: double; begin AnalogPB.Canvas.Brush.Color:=clWhite; AnalogPB.Canvas.Ellipse(3,3,108,108); step:=2*pi/60; AnalogPB.Canvas.Pen.Color:=clBlack; for i:=0 to 11 do begin AnalogPB.Canvas.MoveTo(55,55); x:=55+Round(52*sin(i*step*5)); y:=55-Round(52*cos(i*step*5)); AnalogPB.Canvas.LineTo(x,y); end; AnalogPB.Canvas.Pen.Color:=clGray; AnalogPB.Canvas.Ellipse(7,7,104,104); DecodeTime(t,h,m,s,ms); AnalogPB.Canvas.MoveTo(55,55); x:=55+Round(49*sin(s*step)); y:=55-Round(49*cos(s*step)); AnalogPB.Canvas.Pen.Color:=clGray; AnalogPB.Canvas.LineTo(x,y); AnalogPB.Canvas.MoveTo(55,55); c:=(m*60+s)/60; x:=55+Round(43*sin(c*step)); y:=55-Round(43*cos(c*step)); AnalogPB.Canvas.Pen.Color:=clBlack; AnalogPB.Canvas.LineTo(x,y); AnalogPB.Canvas.MoveTo(55,55); if h>12 then h:=h-12; c:=(h*60+m)/60*5; x:=55+Round(33*sin(c*step)); y:=55-Round(33*cos(c*step)); AnalogPB.Canvas.Pen.Width:=2; AnalogPB.Canvas.LineTo(x,y); AnalogPB.Canvas.Pen.Width:=1; end; procedure TMainFrm.FormCreate(Sender: TObject); begin MainFrm.Top:=Screen.DesktopHeight-MainFrm.Height; MainFrm.Left:=Screen.DesktopWidth-MainFrm.Width; end;

Если же вам не понравится, что они таким образом закроют "стандартные" часы Windows, да еще и вместе с индикатором клавиатуры, то можно будет сделать их полупрозрачными, причем эффект появления прозрачности может быть постепенным, для чего достаточно будет разместить на форме еще один таймер и изменять по нему свойство AlphaBlendValue. Именно такой вариант программы вы найдете в Demo\Part3\Time.

Современные файловые компоненты

Начиная с Delphi 6, в состав VCL было включено несколько дополнительных компонент, обеспечивающих доступ к файловой системе. Это ShellTreeView, ShellListView и ShellComboBox, все они находятся на закладке примеров (Samples). По этой причине их принято считать нестандартными компонентами VCL, и, более того, они не упоминаются в справочной системе. Тем не менее, эти компоненты являются удобной альтернативой морально устаревшим и не отвечающим современным требованиям компонентам DirectoryListBox, FileListBox и DriveComboBox. В частности, с их помощью затруднительно добраться до таких мест системы, как рабочий стол или до папки "Мои документы". Кроме того, они не могут напрямую работать с сетью. В современных компонентах, интегрированных с ОС, эти проблемы решены. В частности, компонент ShellTreeView (системное дерево) отображает структуру папок и устройств компьютера, а так же сетевых ресурсов. Подобную задачу выполняет и ShellComboBox, с той лишь разницей, что он не отображает каталоги на дисках и не показывает иерархии объектов. А компонент ShellListView может отображать все объекты, но не их иерархию. Сами системные компоненты, реализованные в ОС, можно видеть в проводнике Windows. В нем область "папки" соответствует компоненту ShellTreeView, основная область - ShellListView, а адресная строка, с некоторыми оговорками - ShellComboBox.

Рассмотрим некоторые свойства этих компонент, и начнем с ShellTreeView, для чего обратимся к таблице 15.3.

Таблица 15.3. Свойства ShellTreeView
СвойствоТипОписание
AutoContextMenuBooleanОпределяет, должно ли использоваться контекстное меню, предоставляемое ОС
AutoRefreshBooleanОпределяет, должно ли содержимое обновляться автоматически
ObjectTypesTShellObjectTypesОпределяет, объекты каких типов должны отображаться
RootStringОпределяет корневой каталог или системную папку
ShellComboBoxTShellComboBoxУказывает на ассоциированный компонент
ShellListViewTShellListViewУказывает на ассоциированный компонент
ShowButtonsBooleanОпределяет, отображать или нет значки рядом с именем папки, чтобы раскрыть ее содержимое
ShowLinesBooleanОпределяет, должны или нет выводиться линии
ShowRootBooleanОпределяет, должна или нет отображаться корневая папка

Свойство ObjectTypes имеет 3 флага, указывающих на то, какие компоненты следует показывать. Это otFolders - папки, otNonFolders - все, кроме папок, и otHidden - скрытые объекты.

Свойство Root, помимо непосредственного пути, вроде "c:\Dirname", может содержать специальные значения, ссылающиеся на различные системные папки. В их числе можно отметить следующие:

Компонент ShellListView имеет все те же самые свойства (из приведенных в таблице 15.3), что и ShellTreeView, разумеется, за исключением свойства ShellListView: вместо него используется аналогичное по назначению свойство ShellTreeView. Кроме того, у него имеется еще одно свойство - AutoNavigate, которое, будучи установленным в истину, позволит пользователю открывать содержимое каталогов непосредственно из этого компонента.

Наконец, компонент ShellComboBox, основанный на раскрывающемся списке, содержит только 1 свойство из всех вышеперечисленных - Root.

Для того чтобы самостоятельно создать некоторое подобие Проводника, достаточно поместить на форму все эти компоненты и связать их между собой при помощи свойств ассоциирования. А чтобы такой проводник вел себя так же, как имеющийся в Windows, т.е. мог изменять размеры, нам понадобится еще панель, на которую мы поместим ShellComboBox, и разделитель - компонент Splitter. Он находится на закладке Additional и выполняет функцию ползунка, при помощи которого можно изменять размеры соседних компонентов. При этом для всех участвующих в этом компонентов должно быть настроено выравнивание (свойство Align). Таким образом, вначале для панели, на которой находится раскрывающийся список, следует установить свойство Align в alTop, в результате чего панель займет все пространство вверху окна. Затем для дерева (ShellTreeView) установим значение Align в alLeft, чтобы оно расположилось по левому краю окна. После этого поместим на форму разделитель. Поскольку он должен граничить как раз с деревом, и изменять, в том числе, и его размеры, для него свойство Align тоже должно быть установлено в alLeft. Впрочем, по умолчанию оно как раз такое значение и имеет. Наконец, чтобы занять все оставшееся место, установим для ShellComboBox выравнивание в alClient. Запустив программу, можно убедиться, что она действительно функционирует подобно Проводнику Windows (рис. 15.7).

Упрощенный аналог проводника Windows, написанный на Delphi
Рис. 15.7. Упрощенный аналог проводника Windows

Подобно "настоящей" области просмотра файлов, ShellListView можно переключать между режимами отображения, для чего следует воспользоваться свойством ViewStyle, которое может принимать одно из следующих значений: vsIcon, vsSmallIcon, vsList и vsReport. В примере, находящемся в Demo\Part3\Explore, продемонстрированы все эти режимы применительно к нашему проводнику.

ПРИМЕЧАНИЕ
Следует отметить, что свойство ViewStyle происходит от предка ShellListView - универсального, с точки зрения применения, компонента ListView. Так же существует и прообраз ShellTreeView - компонент TreeView. Оба они относятся к группе Win32 и могут быть использованы для предоставления в иерархическом виде самой разнообразной информации.

Избранное

SNK GSCP
SNK GSCP - новая библиотека для PHP 5!
Web Studio
Web Studio и Visual Workshop
Библиотека:
Стандарты на web-технологии
Монополия
Монополия Android
Загрузки:
скачать программы
Продукция:
программы и книги
Техподдержка / Связаться с нами
Copyright © 1999-2020 SNK. Все права защищены.
При использовании материалов с сайта ссылка на источник обязательна.
Рейтинг@Mail.ru