Продолжение создания собственного графического редактора 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Продолжение создания собственного графического редактора



 

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

Тем не менее мы не будем подробно анализировать текст этого приложения. Рассмотрим только основные приемы, которые использованы при создании раз­личных инструментов. А общую логику работы вы можете придумать сами или по­заимствовать ее из примера.

Приложение выполняет следующие функции:

• Установка основного и дополнительного цветов. Щелчок на панели цветов ле­вой кнопкой мыши устанавливает основной цвет, а щелчок правой кнопкой — вспомогательный.

• Кисть — кнопка SBBrush. Закрашивает замкнутую область, ограниченную цветом того пикселя, который указан щелчком мыши. При щелчке левой кнопкой закрашивание производится основным цветом, при щелчке правой кнопкой — вспомогательным.

• Индикация цвета — кнопка SBColor. В этом режиме вы можете указать кур­сором мыши любой пиксель на изображении и, щелкнув левой кнопкой, уста­новить цвет этого пикселя как основной, а щелкнув правой кнопкой, устано­вить его как вспомогательный цвет.

• Карандаш — кнопка SBPen. В этом режиме вы можете рисовать произволь­ную кривую основным цветом.

• Выделение фрагмента — кнопка SBRect. Фрагмент выделяется точечной рам­кой. Выделенный фрагмент можно в дальнейшем перетащить мышью на дру­гое место. Если в процессе перетаскивания нажата клавиша Ctrl, то произво­дится копирование фрагмента, в противном случае — вырезание, при котором область начального размещения фрагмента закрашивается вспомогательным цветом. Выделенный фрагмент может быть также скопирован или вырезан в буфер обмена Clipboard соответствующими командами меню.

• Стирание изображения (ластик) —кнопка SBErase. Перемещение ластика за­крашивает область под ним во вспомогательный цвет.

• Рисование прямоугольника — кнопка SBRectang. Рисуется прямоугольная рамка основным цветом.

• Рисование заполненного прямоугольника — кнопка SBFillRec. Рисуется пря­моугольная рамка основным цветом и прямоугольник внутри закрашивается вспомогательным цветом.

• Рисование прямой линии — кнопка SBLine. Рисуется прямая линия основ­ным цветом.

• Открытие графического файла — команда Файл | Открыть.

• Сохранение изображения в графическом файле — команда Файл | Сохранить как....

• Отмена операций, выполненных последним использованным инструментом — команда Правка | Отменить.

• Копирование или вырезание выделенного фрагмента изображения в буфер об­мена Clipboard — команды Правка | Копировать или Правка | Вырезать.

• Вставка графического изображения типа битовой матрицы из буфера обмена Clipboard — команда Правка | Вставить.

Начнем с рассмотрения функции выделения фрагмента. Она осуществляется методом DrawFocusRect. В этом режиме при событии OnMouseDown холста компонента Image3, выполняются операторы:

// запоминание начального положения курсора мыши ХО:=Х;,YO:=Y;

// формирование начального положения области фрагмента R.TopLeft!= Point(X,Y); R.BottomRight:= Point(X,Y); // рисование рамки ImageS.Canvas.DrawFocusRect(R); RBegin:= true;

Эти операторы запоминают координаты мыши X и Y в переменных ХО и YO, задают начальные координаты прямоугольной области — переменной R типа TRect и рисуют рамку (пока нулевого размера) методом DrawFocusRect. Устанав­ливается также флаг начала выделения фрагмента — переменная RBegin.

При событии OnMouseMove компонента Image3, если установлен флаг RBe­gin, выполняются операторы:

// стирание прежней рамки Image3.Canvas.DrawFocusRect(R);

// формирование области R if ХО < X

then begin R.Left:= ХО;

R.Right:= X end else begin R.Left:= X; R.Right:= XO end; if YO < Y

then begin R.Top:= УО;

R.Bottom:= Y end

else begin R.Top:= Y;

R.Bottom:= YO end;

// рисование новой рамки Image3.Canvas.DrawFocusRect(R);

Первый из этих операторов стирает прежнее изображение рамки (напомним, что метод DrawrFocusRect рисует рамку с помощью операции XOR). Два следую­щих оператора формируют новую область R из начальных координат (ХО, YO) и те­кущих координат курсора (X, Y). Дело в том, что область, передаваемая в функ­цию DrawFocusRect, должна быть сформирована «правильно» — значение R.Left должно быть меньше R.Right, a R.Top — меньше R.Bottom. А поскольку пользо­ватель может перемещать курсор в любом направлении и соотношение координат (ХО, YO) и (X, Y) может быть любым, требуется упорядочивание координат.

Последний оператор рисует рамку в новом положении.

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

with Image3.Canvas do begin

// стирание,.прежней рамки DrawFocusReet(R);

// установка флага перетаскивания

RDrag:= true;

// запоминание начального положения курсора мыши

ХО:= X; У0:= Y;

//запоминание начального положения перетаскиваемого фрагмента

RO.TopLeft:= R.TopLeft; RO.BottomRight:= R.BottomRight;

// запоминание изображения

BitMap. Assign'(Image3.Picture);

// установка, цвета кисти-Brush. Color:= Image2.Canvas.Brush.Color;

end;

Первый оператор стирает рамку. Второй— устанавливает флаг перетаскива­ния — переменную RDrag. Два следующих оператора запоминают начальное поло­жение перетаскиваемого фрагмента в переменной RO типа TRect. Следующий опе­ратор запоминает методом Assign изображение в момент начала перетаскивания в переменной BitMap. Это необходимо, чтобы в процессе перетаскивания можно было восстанавливать испорченные места изображения и чтобы при желании по­льзователя можно было в дальнейшем отменить результат перетаскивания. По­следний оператор задает цвет кисти равным вспомогательному цвету, хранящему­ся в компоненте Image2.

При событии OnMouseMove компонента Image3, если установлен флаг RDrag, выполняются операторы:

// восстановление изображения под перетаскиваемым фрагментом.

CopyRect (R,BitMap.Canvas,R);

// если не нажата клавиша Ctrl - стирание изображения в .RO

if not (ssCtrl in Shift) then FillRect (RO);

// формирование нового положения фрагмента

R.Left:= R.Left + X - ХО;

R.Right:= R.Right + X - XO;

R.Top:= R.Top + Y - YO;

R.Bottom:= R.Bottom + Y - YO;

// запоминание положения курсора мыши

ХО:= X;

YO:= Y;

// рисование фрагмента в новом положении

CopyRect(R,BitMap.Canvas,R0);

// рисование рамки

DrawFocusRect (R);

Первый оператор восстанавливает изображение под перетаскиваемым фраг­ментом в его прежней позиции (т.е. стирает фрагмент), копируя соответствую­щую область методом CopyRect из компонента BitMap. Далее, если не нажата кла­виша Ctrl, то очищается область начального размещения фрагмента (осуществляет­ся вырезание) методом FillRect. Затем запоминаются новые координаты курсора и новое положение фрагмента, после чего фрагмент и его рамка рисуются в новом положении.

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

Режимы рисования заполненного и не заполненного прямоугольников проще. Начало этих режимов по событию OnMouseDown и их продолжение по событиям OnMouseMove не отличаются от рассмотренного ранее режима выделения фраг­мента. Отличие только в том, что при завершении формирования пользователем прямоугольной рамки, т.е. при событии OnMouseUp, надо в данном случае нарисо­вать прямоугольник. Рисование заполненного прямоугольника осуществляется операторами:

with Image3.Canvas do begin;

Brush.Color:= Image2.Canvas.Brush.Color;

Pen.Color:= Imagel.Canvas.Brush.Color;

Rectangle(R.Left,R.Top,R.Right,R.Bottom); end;

Они задают цвета кисти и пера и рисуют прямоугольник методом Rectangle. Рисование не закрашенного прямоугольника осуществляется операторами:

with Image3.Canvas do begin

Brush.Color:= Imagel.Canvas.Brush.Color;

FrameRect(R); end;

Обратите внимание, что равным основному цвету задается цвет кисти, а не пера, поскольку метод FrameRect рисует цветом кисти.

Рисование прямой линии осуществляется следующим образом. Начало рисо­вания по событию OnMouseDown сводится к операторам:

ХО:= X;

YO:= Y;

XI:= X;

Y1:= Y;

Image3.Canvas.Pen.Color:= Imagel.Canvas.Brush.Color;

Image3.Canvas.Pen.Mode:= pmNotXor;

Они запоминают положение курсора в двух наборах переменных: (ХО, YO) и (XI, Y1). Зачем нужны два набора — будет сказано позднее. Затем устанавливает­ся цвет пера и режим pmNotXor, который позволит при движении мыши стирать изображение линии.

При событиях OnMouseMove работают следующие операторы:

with Image3.Canvas do begin // стирание прежней линии

MoveTo(ХО,YO);

LineTo(XI,Yl); // рисование новой линии

MoveTo(ХО,YO);

LineTo(X,Y); // запоминание новых координат конца линии

XI:= X;

Yl:= Y; end;

В этих операциях сначала парой методов MoveTo и LineTo стирается линия в прежнем положении, а затем такой же парой методов рисуется новая линия. По­сле этого запоминаются новые координаты конца линии.

Попробуем разобраться, зачем все так сложно. Ведь казалось бы, что достаточ­но всего двух операторов:

LineTo (XO,YO); LineTo(X,Y);

Первый из них сотрет прежнюю линию, поскольку текущая позиция пера по­сле рисования этой прежней линии соответствовала концу линии (тем координа­там, которые мы храним в переменных XI, Y1). А второй оператор нарисует новую линию. И не надо хранить никаких координат.

Так просто нельзя сделать из-за одной тонкости: метод LineTo рисует линию, начинающуюся в текущей позиции пера и заканчивающуюся в указанной точке, исключая эту конечную точку. Поэтому, если выполнить в режиме pmNotXor приведенные выше операторы, то первый из них сотрет прежнюю линию, но оста­вит нестертой точку с координатами (X0, Y0) и, кроме того, нарисует точку в быв­шей позиции курсора, поскольку она, как конечная, была исключена при рисова­нии предыдущей линии. Таким образом, на концах линии останется «грязь» в виде концевых точек, которая и будет тянуться за перемещающимся курсором мыши.

Заключительные операции при событии OnMouseUp аналогичны рассмотрен­ным выше, но дополняются переводом пера в режим рmСору, при котором рисует­ся окончательная линия:

with Imaige3.Canvas do begin // стирание прежней линии

MoveTo(XO,YO);

LineTo(XI,Yl); // рисование новой линии

Pen.Mode:= pmCopy;

MoveTo(XO,YO);

LineTo(X,Y); end;

Теперь рассмотрим инструмент Перо, позволяющий рисовать произвольные линии. Казалось бы естественной реализацией этого инструмента был бы оператор

Image3.Canvas.Pixels[X,Y]:= Imagel.Canvas.Brush.Color;

который окрашивает пиксель под курсором в основной цвет. Однако попробуйте так реализовать Перо и ничего хорошего не увидите. Курсор мыши перемещается быстро и события OnMouseMove происходят вовсе не при перемещении на сосед­ний пиксель. Линию, оставляемую курсором, следует рисовать тоже методом LineTo, поместив в обработчик события OnMouseMove оператор

Image3.Canvas.LineTo(X, Y).

Коротко перечислим оставшееся. Ластик реализуется методом FillRect, очищаю­щим изображение под его рамкой. Кисть, отмена команд и загрузка внешнего фай­ла. Сохранение файла осуществляется с использо­ванием компонента типа SavePictureDialog.

Изображение с холста сохраняется в компоненте BitMap, из которого методом SaveToFile записывается в выбранный пользователем файл.

Команды меню Копировать и Вырезать осуществляются процедурой

procedure TForml.MGopyClick(Sender: TObject); var BMCopy: TBitMap;

begin

// стирание рамки

Image3.Canvas.DrawFocusRect(R); // создание временного объекта ВМСору

ВМСору:= BitMap.Create;

ВМСору.Width:= R.Right - R.Left;

ВМСору.Height:= R.Bottom - R.Top;

try

// копирование фрагмента в BM Сору

ВМСору.Canvas.Соругееt(Rect(0,0,ВМСору.Width,

ВМСору.Height)

Image3.Canvas,R); // восстановление рамки

Images.Canvas.DrawFocusRect (R); // копирование в Clipboard

ClipBoard.Assign(ВМСору); if

(Sender as TMenuItem).Name:= 'MCut'

then begin // вырезание

Image3.Canvas.Brush.Color:=clWhite;

Image3.Canvas.FillRect(R);

end; finally // освобождение памяти

ВМСору.Free; end; end;

Копированию или вырезанию подлежит ранее выделенный пользователем объект, местоположение и размеры которого определяются переменной R. Поэто­му сначала создается временный объект типа TBitMap, в который переносится ко­пируемый фрагмент. Затем этот объект копируется в Clipboard. Благодаря разделу finally память освобождается от временного объекта при любом исходе копирова­ния: удачном или аварийном.

Аналогично реализуется команда Вставить, копирующая изображение из буфе­ра обмена Clipboard:

procedure TForml.MPasteClick(Sender: TObject); var ВМСору:TBitMap; begin

ВМСору:=BitMap.Create;

try

try

ВМСору.LoadFromClipBoardFormat(cf_BitMap,

ClipBoard.GetAsHandle(cf_Bitmap),0);

Image3.Canvas.CopyRect(Rect(0,0,ВМСору.Width, ВМСору.Height),

ВМСору.Canvas,Rect(0,0,ВМСору.Width,ВМСору.Height)):

finally

ВМСору.Free; end; except

On EInvalidGraphic do ShowMessage(Ошибочный формат графики); end;

end;

Чтение из Clipboard осуществляется методом LoadFromClipBoardFormat. Предусмотрен перехват исключения EInvalidGraphic, если в Clipboard содержится не битовая матрица.

Попро­буйте также усовершенствовать редактор, добавив в него, например, выбор шири­ны линий, рисование эллипсов и т.д.

 

Мультимедиа и анимация

 

Звук

 

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

Наиболее простым звуковым файлом является волновой файл.wav. В нем за­писано цифровое представление информации о волновой форме электрического сигнала, соответствующего каждому звуку. Волновой файл «не знает» вообще ничего о том, что такое звук и что он означает; поэтому для хранения звукового кли­па приходится запоминать массу информации.

Другим часто применяемым типом файлов-носителей являются файлы цифро­вого интерфейса музыкальных инструментов (MIDI). Файлы.midi используются для хранения музыкальных фрагментов. В этих файлах звук хранится в виде дан­ных о том, на каких инструментах исполняются определенные ноты и как долго они звучат. Одним из главных преимуществ MIDI является то, что файлы получа­ются сравнительно небольшими.

Волновые и MIDI файлы могут хранить только звук или музыку. Для хране­ния видео информации разработан ряд форматов. Отметим среди них файлы AVI и MPEG. Большинство видеофайлов поддерживают также хранение звуковой дорож­ки, так что звук воспроизводится синхронно с картинкой.

Наиболее простой процедурой, управляющей звуком, является процедура Веер. Она не имеет параметров и воспроизводит стандартный звуковой сигнал, установленный в Windows, если компьютер имеет звуковую карту и стандартный сигнал задан (он устанавливается в программе Windows «Панель управления» по­сле щелчка на пиктограмме Звук). Если звуковой карты нет или стандартный сиг­нал не установлен, звук воспроизводится через динамик компьютера просто в виде короткого щелчка.

Откройте новое приложение, введите в него кнопку, в обработчике щелчка ко­торой напишите одно слово:

Веер;

Можете запустить приложение, щелкнуть на кнопке и прослушать стандартный звук Windows или просто щелчок, если стандартный звук не установлен. Более серьезной процедурой является MessageBeep. Она определена как

function MessageBeep (uType: word).: boolean;

Параметр uType указывает воспроизводимый звук как идентификатор разде­ла [sounds] -реестра, в котором записаны звуки, сопровождающие те или иные события в Windows. С помощью приложения Звук в «Контрольной панели» пользова­тель может удалить или установить соответствующие звуки.

После запроса звука функция MessageBeep возвращает управление вызвав­шей функции и воспроизводит звук асинхронно. Во время воспроизведения прило­жение может продолжать выполняться.

Если невозможно воспроизвести указанный в функции звук, делается попыт­ка воспроизвести стандартный системный звук, установленный по умолчанию. Если и это невозможно, то воспроизводится стандартный сигнал через динамик.

При успешном выполнении возвращается ненулевое значение. При аварийном завершении возвращается нуль.

Можете в своем тестовом приложении ввести еще одну кнопку и написать для нее обработчик:

MessageBeep(MB_OK);

Вы услышите тот же стандартный звук Windows, что и при выполнении про­цедуры Веер. Или услышите тот же тихий щелчок, если стандартный звук не уста­новлен. Попробуйте установить различные звуки с помощью «Панели управле­ния» и проверить MessageBeep при различных значениях ее параметра.

А теперь давайте займемся более серьезной функцией PlaySound, которая по­зволяет воспроизводить не только звуки событий Windows, но и любые волновые файлы. Это функция API Windows, параметры которой описаны в модуле mmsystem. Поэтому для использования этой функции в вашем приложении необходимо включить в его оператор uses ссылку на mmsystem, поскольку автоматически эту ссылку Delphi не включает.

Функция PlaySound определена следующим образом:

function PlaySound (pszSound:PChaf; hmod:HINST; fdwSound: Cardinal): boolean;

Параметр pszSound представляет собой строку с нулевым символом в конце и определяет воспроизводимый звук. Параметр hmod используется, если звук берет­ся из ресурса. А поскольку далее звуками из ресурса мы пользоваться не будем, то hmod всегда можно задавать равным nil или 0.

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

- SND_ASYNC - Звук воспроизводится асинхронно и функция PlaySound воз­вращается немедленно после начала воспроизведения. Чтобы прекратить асинхронное воспроизведение волнового файла, надо вызвать PlaySound с параметром pszSound, равным 0.

- SNDJLOOP - Воспроизведение звука постоянно повторяется, пока не вызо­вется PlaySound с параметром pszSound, равным 0. Одновре­менно надо установить флаг SND_ASYNC асинхронного вос­произведения звука.

- SND_NOSTOP - Если заданный звук не может быть воспроизведен, поскольку ресурсы, необходимые для воспроизведения, заняты воспроиз­ведением другого звука, функция PlaySound немедленно вер­нет false, не воспроизводя заданного звука. Если данный флаг не указан, функция PlaySound пытается остановить воспроиз­ведение другого звука, чтобы устройство могло быть использо­вано для воспроизведения нового звука.

- SND_NOWAIT - Если драйвер занят, функция сразу вернется без воспроизве­дения заданного звука

- SND_PURGE - Останавливается воспроизведение любых звуков, вызванных в данной задаче. Если pszSound не 0, останавливаются все эк­земпляры указанного звука. Если pszSound равен 0, то оста­навливаются все звуки, связанные с данной задачей.

- SND_SYNC - Синхронное воспроизведение звука события. Функция PlaySo­und возвращается только после окончания воспроизведения.

Флаги могут комбинироваться операцией оr.

Звук, указанный параметром pszSound, должен помещаться в доступную па­мять и должен подходить для установленного драйвера устройства воспроизведе­ния волновых файлов. Функция PlaySound ищет файл звука в следующих катало­гах: текущем, каталоге Windows, системном каталоге Windows, каталогах, пере­численных в переменной среды PATH, в списке каталогов, предоставляемых сетью. Если указанный звук не находится, функция PlaySound воспроизводит системный звук по умолчанию. Если функция не может найти и его, то воспроизведения не будет, а вернется значение false.

Приведем примеры использования функции PlaySound.

Оператор

PlaySound('c:\win98\media\3вукMicrosoft.wav',О,SND_ASYNC);

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

Чтобы опробовать функцию PlaySound, введите в свое приложение диалог OpenDialog и кнопку со следующим обработчиком щелчка:

if OpenDialogl.Execute then PlaySound (PChar (Open Dialogl.FileName),0,SND_ASYNC);

Запустите приложение, выберите файл какой-нибудь приятной музыки и ра­ботайте со своим приложением, наслаждаясь попутно выбранной мелодией.

В предыдущих примерах звук задавался именем его волнового файла. Функ­ция PlaySound позволяет воспроизводить и системные звуки, просто называя их псевдонимы. Например, оператор

PlaySound('SystemStart',0,SND_ASYNC);

воспроизведет тот же звук открытия Windows, что и приведенный ранее оператор, указывавший имя и путь к нему. Оператор

PlaySound('с:\win98\media\3вук Microsoft.wav', 0, SND_ASYNC or SND_LOOP);

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

PlaySound(0,0, SND_PURGE);

Оператор

PlaySound('с:\win98\media\3вук Microsoft.wav, 0, SND_SYNC);

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

Все рассмотренные ранее операторы прерывали при своем выполнении звук, который асинхронно воспроизводился в момент вызова PlaySound. Если же вы вы­полните оператор с флагом SND_NOSTOP, например:

PlaySound('с:\win98\media\3вук Microsoft.wav',0, SND_SYNC or. SND_NOSTOP)

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

 



Поделиться:


Последнее изменение этой страницы: 2016-12-28; просмотров: 239; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 13.58.39.23 (0.065 с.)