Рисование с помощью пера Pen 


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



ЗНАЕТЕ ЛИ ВЫ?

Рисование с помощью пера Pen



 

У канвы имеется свойство Реn — перо. Это объект, в свою очередь, имеющий ряд свойств.

Свойство Style определяет вид линии.

Все стили со штрихами и пунктирами доступны только при Width = 1. В про­тивном случае линии этих стилей рисуются как сплошные.

Стиль psInsideFrame — единственный, который допускает произвольные цве­та. Цвет линии при остальных стилях округляется до ближайшего из палитры Windows.

У канвы имеется свойство PenPos типа TPoint. Это свойство определяет в ко­ординатах канвы текущую позицию пера. Перемещение пера без прорисовки ли­нии, т.е. изменение PenPos, производится методом канвы MoveTo(X,Y). Здесь X и Y — координаты точки, в которую перемещается перо. Эта текущая точка стано­вится исходной, от которой методом LineTo(X,Y) можно провести линию в точку с координатами (X,Y). При этом текущая точка перемещается в конечную точку ли­нии и новый вызов LineTo будет проводить линию из этой новой текущей точки.

Давайте попробуем нарисовать пером график синуса из предыдущего примера. Откройте прежний проект, добавьте на него еще один компонент. Размеры обоих компонентов Image должны быть абсолютно одинаковы, так как на этом для экономии размера кода и вашего труда основана программа, которую мы напишем. Затем в уже написанный вами обработчик щелчка на кнопке добавьте перед началом цикла оператор

Image2.Canvas.MoveTo(0,Image2.Height div 2);

который переводит перо в начало координат второго графика — на левый край канвы в середину ее высоты. А перед заключительным end цикла добавьте оператор

Image2.Canvas.LineTo(PX, PY);

который рисует на втором графике линию, соединяющую соседние точки.

Для экономии кода мы воспользовались тем, что оба графика у нас абсолютно одинакового размера и, следовательно, пересчет координат достаточно провести для одного из них, а потом воспользоваться этими координатами для рисования обоих графиков. Cравните полученные графики.

Отметим еще одно ценное свойство компонента Image и его канвы. Вы можете задавать координаты пикселей, выходящие за пределы размеров канвы, и ничего страшного при этом не случится. Это позволяет не заботиться о том, какая часть рисунка попадает в рамку Image, а какая нет. Вы можете легко проверить это, уве­личив, например, вдвое размах вашей синусоиды. Попробуйте сделать это самостоятельно.

Это позволяет легко осуществлять приложения, в которых пользователю предоставляется возможность увеличивать и просматривать в деталях какие-то фрагменты графиков.

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

Arc - Рисует дугу окружности или эллипса

Chord - Рисует замкнутую фигуру, ограниченную дугой окружности или эллипса и хордой

Pie - Рисует сектор окружности или эллипса

PolyBezier - Рисует кусочную кривую третьего порядка

Polygon - Рисует замкнутую фигуру с кусочно-линейной границей

Polyline - Рисует кусочно-линейную кривую

Rectangle - Рисует прямоугольник

RoundRect - Рисует прямоугольник со скругленными углами

Ниже приведен текст процедуры, которая рисовала некоторые фигуры, приведенные в вышележащей таблице.

with Imagel.Canvas do begin

Font.Style:= [fsBold];

Arc(10,10,90,90,90,50,10,50);

TextOut(40,60,'Arc');

Chord(110,10,190,90,190,50,110,50);

TextOut (135,60, 'Chord');

Ellipse (210,10,290,50);

TextOut(230,60,'Ellipse');

end.

 

Brush — кисть

 

У канвы имеется свойство Brush — кисть. Это свойство определяет фон и за­полнение замкнутых фигур на канве. Brush — это объект, имеющий, в свою оче­редь ряд свойств. Свойство Color определяет цвет заполнения. Свойство Style определяет шаблон заполнения (штриховку).

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

Bitmap: TBitmap;

begin

Bitmap:= TBitmap.Create;

try

Bitmap.LoadFromFile('MyBitmap.bmp');

Forml.Canvas.Brush.Bitmap:= Bitmap;

finally

Imagel.Canvas.Brush.Bitmap:= nil;

Bitmap.Free; end; end;

В этом примере создается объект Bitmap типа TBitmap, и в него загружается битовая матрица из файла с именем MyBitmap.bmp. Затем свойству Imagel.Can­vas.Brush.Bitmap присваивается указатель на этот объект. После этого загружен­ный шаблон можно использовать для заполнения фигур на канве Imagel. В конце кода свойству BitMap присваивается значение nil, после чего заполнение опять на­чинает определяться свойством Style. Затем объект Bitmap уничтожается, чтобы освободить занимаемую им память.

Имеются функции канвы, рисующие заполненные фигуры. Это, например, метод FillRect, объявленный как

procedure FillRect(const Rect: TRect);

Он заполняет заданным стилем или шаблоном прямоугольную область, задан­ную параметром Rect. Этот параметр имеет тип TRect. Для его задания проще всего использовать функцию Rect(Xl,Yl,X2,Y2), возвращающую структуру Rect с координатами углов, заданных параметрами (XI, Y1) и (Х2, Y2). Функцию FillRect удобно, в частности, использовать для стирания изображе­ния. Например, оператор

with Imagel do Canvas.FillRect(Rect(0,0,Width,Height));

очищает всю площадь канвы компонента Imagel.

Кисть участвует в заполнении фигур не только с помощью этой функции. Все перечисленные ранее методы рисования замкнутых фигур тоже заполняют их с по мощью кисти. Это относится к методам Chord, Ellipse, Pie, Polygon и др.

Имеется еще один интересный метод, работающий с кистью. Это метод Flood Fill, который заполняет замкнутую область на канве. Для определения области закрашивания можно использовать координаты и цвет одного из пикселей, расположенных внутри области (если FillStyle = fsSurfaсе) или снаружи ее (если FillStyle = fsBorder).

 

Пример построения собственного простого графического редактора

 

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

1. Начните новое приложение.

2. Перенесите на форму два компонента типа Tlmage и расположите их в нижней левой части формы, придав квадратную форму, например, размером 20 на 20. Это будут окна основного и вспомогательного цветов. Имена этих компонентов будут Imagel и Image2. (рис. 11)

 

 

Рисунок 11. Графический редактор, работа с изображением, загруженным из файла #' Г

Рафический редактор

3. Перенесите на форму еще один компонент типа Tlmage и расположите его в верхней части формы, несколько отступив от левого края, где у нас будет инструментальная панель, и растянув так, чтобы он занимал основную часть формы. Это будет холст для картинок. Имя этого компонента будет ImageS.

4. Перенесите на форму еще один компонент типа TImage и расположите его внизу правее первых двух на одном с ними уровне. Это будет палитра цветов. Ее высоту задайте той же, что у первых двух компонентов, а длину — в 10 раз большую. Имя этого компонента будет Image4.

5. Перенесите на форму кнопку типа TSpeedButton и расположите ее в верхнем левом углу формы. Эта кнопка будет соответствовать кисти — типичному ин­струменту графических редакторов. Назовите ее SBBrush. Установите у кноп­ки свойство Grouplndex равным 1 и свойство AllowAHUp в true. Эти свойства обеспечат кнопке возможность фиксироваться в нажатом и не нажатом состоя­нии. Желательно загрузить в свойство Glyph пиктограмму кисти (файл..\lma-ges\Buttons\brush.bmp).

6. Перенесите на форму еще одну кнопку типа TSpeedButton и расположите ее ниже SBBrush. Эта кнопка будет соответствовать указателю цвета пикселя ри­сунка. Назовите ее SBColor. Установите у этой кнопки, как и у предыдущей, свойство Grouplndex равным 1 (это обеспечит, что только одна из кнопок SBBrush или SBColor может быть нажата) и свойство AllowAllUp в true. Же­лательно загрузить в свойство Glyph пиктограмму (например файл..\lmages\ Buttons\one2one.bmp).

7. Перенесите на форму диалог OpenPictureDialog.

8. Перенесите на форму главное меню MainMenu. В меню задайте раздел Файл с подразделом Открыть. Назовите этот подраздел МОреп. Задайте еще один раз­дел — Правка с подразделом Отменить. Назовите этот подраздел Undo.

Теперь размещение компонентов закончено и можно писать обработчики со­бытий. Начнем со второстепенных обработчиков.

9. В раздел implementation включите объявление переменной

var BitMap:TBitMap;

Эта переменная будет тем объектом, в котором будет сохраняться изображе­ние, чтобы его можно было восстановить командой Отменить.

10. Для события OnCreate формы напишите обработчик вида:

procedure TForml.FormCreate(Sender: TObject); var HW, i: integer; begin BitMap:=TBitMap.Create;

//задание свойств кисти основного и вспомогательного цветов

Imagel.Canvas.Brush.Color:= clBlack;

Image2.Canvas.Brush.Color:= clwhite; // заполнение окон основного и вспомогательного цветов

with Imagel.Canvas do FillRect(Rect(0,0,Width,Height));

with Image2.Canvas do FillRect(Rect(0,0,Width, Height)); // задание ширины элемента палитры цветов

HW:=Image4.Width div 10; // закраска элементов палитры цветов

with Image4.Canvas do for i:=l to 10 do begin case i of

1: Brush.Color:= clBlack;

2: Brush.Color:= с1Aqua;

3: Brush.Color:= clBlue;

4: Brush.Color:= clFuchsia;

5: Brush.Color:= clGreen;

6: Brush.Color:= clLime;

7: Brush.Color:= clMaroon;

8: Brush.Color:= clRed;

9: Brush.Color:= clYellow;

10: Brush.Color:= clWhite;

end;

Rectangle((i-1)*HW, 0, i*HW, Height); end; -

// рисование креста на холсте - только для тестирования with Image3 do begin Canvas.MoveTo(0,0); Canvas.LineTo(Width,Height);, Canvas.MoveTo(0,Height); Canvas.LineTo(Width,0); end;

BitMap.Assign(Image3.Picture); end;

Обработчик длинный, но смысл его достаточно прост.

   

 

Сначала создается объект BitMap, в котором будет храниться первоначальное изображение. Затем задаются свойства кисти окон основного (Imagel) и вспомогательного (Image2) цветов: черный и белый. Окна заливаются соответствующим цветом с помощью функции FillRect. После этого формируется палитра цветов!! для каждого элемента палитры задается свой цвет и элемент заполняется этим! цветом с помощью функции Rectangle.

11. В обработчик события формы OnDestroy запишите оператор

BitMap.Free;

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

12. Для подраздела меню Открыть в обработчик включите операторы:

if OpenPictureDialogl.Execute then begin

ImageS.Picture.LoadFromFile(OpenPictureDialogl.File Name); BitMap.Assign(ImageS.Picture);

end;

Эти операторы загружают в компонент ImageS файл изображения, который пользователь выбирает в диалоге, и запоминают изображение в BitMap.

13. Для подраздела меню Отменить в обработчик включите оператор:

Image3.Picture.Assign(BitMap);

Этот оператор восстанавливает на холсте изображение, сохраненное в BitMap.

14. В обработчик события OnClick кнопок SBBrush и SBColor запишите оператор

if (Sender as TSpeedButton).Down

then BitMap.Assign(Image3.Picture);

Этот оператор запоминает текущий вид изображения перед началом работы с очередным инструментом.

15. В обработчик события OnMouseDown компонентов Image3 и Image4 вставьте код:

if (Sender = Image4) or SBColor.Down then // режим установки основного и вспомогательного цветов begin if(Button=mbLeft)

then with Imagel.Canvas do begin // установка основного цвета

Brush.Color:=(Sender as TImage).Canvas.Pixels[X,Y]; FillRect(Rect(0,0,Width,Height)); end

else with Image2.Canvas do begin //установка вспомогательного цвета

Brush.Color:= (Sender as TImage).Canvas.Pixels[X,Y]; FillRect(Rect(0,0,Width,Height)); end; end

else if SBBrush.Down then with Image3.Canvas do begin // режим закраски указанной области холста if Button = mbLeft

then Brush.Color:= Imagel.Canvas.Brush.Color else Brush.Color:= Image2.Canvas.-Brush.Color; FloodFill(X, Y, Pixels[X,Y], fsSurface); end;

Это основной код, осуществляющий как установку основного и вспомогатель­ного цветов, так и функцию инструмента графического редактора — кисти. Если кнопка мыши нажата на палитре цветов Image4 или если кнопка SBColor — кноп­ка указателя цвета утоплена, то приложение находится в режиме установки цве­тов. При нажатой левой кнопки мыши цвет пикселя под курсором мыши передает­ся в окно основного цвета, а при нажатии правой кнопки— в окно вспомогатель­ного цвета.

Если кнопка мыши нажата на холсте Image3 и при этом кнопка SBBrush утоплена, то приложение находится в режиме закраски указанной области рисун­ка. В этом случае в зависимости от нажатой кнопки мыши выбирается основной или вспомогательный цвет и функцией FloodFill производится закраска области, координаты внутренней точки которой указаны курсором мыши, а цвет — цветом пикселя, на который указывает мышь.

   

 

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

Если вы выполните команду Правка | Отменить, то изображение вернется к тому виду, какой был при начале работы с последним использованным инструментом.

Теперь вы можете загрузить командой Файл | Открыть вашего приложения какое-то изображение. Вы можете попробовать перекрашивать те или иные области изображения. Например, можете изменить цвет фона, выделить какую-то сплошную область рисунка одного цвета и т.п.

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

Режимы рисования

 

У пера Реn имеется еще одно свойство, которое мы пока не рассматривали. Это | свойство — Mode (режим). По умолчанию значение Mode = pmCopy. Это означает, что линии проводятся цветом, заданным в свойстве Color. Но возможны и другие ре­жимы, в которых учитывается не только цвет Color, но и цвет соответствующих пикселей фона. Наиболее интересным из этих режимов является режим pmNotХоr — сложение с фоном по инверсному исключающему ИЛИ. Операция инверс­ного исключающего ИЛИ анализирует по битам два своих операнда. Результирую­щий бит равен «0», если соответствующие биты двух операндов не равны друг дру­гу, а при равенстве битов операндов результирующий бит равен «1».

Вспомните, что каждый пиксель хранит цвет как набор битов. Пусть, напри­мер, фоновый пиксель имеет значение 0110011, а цвет пера установлен в 1111000, Применение операции pmNotXor к этим двум числам даст цвет со значением 0110100. Этот цвет перо задаст данному пикселю. А теперь посмотрим, что полу­чится, если перо повторно пройдет по тому же пикселю. В этом случае опять будет выполнена операция pmNotXor по отношению к цвету пера 1111000 и текущему цвету пикселя, который стал равен 0110100. Применение pmNotXor к этим чис­лам даст в результате 0110011, т.е. первоначальный цвет пикселя.

Это значит, что если нарисовать на фоне какую-то фигуру один раз, а затем на­рисовать ту же фигуру повторно, то нарисованная фигура исчезнет и каждый пик­сель вернется к своему первоначальному цвету. Эту особенность режима pmNot­Xor, свойственную также режиму pmХоr — сложение с фоном по исключающему ИЛИ, можно использовать для создания простенькой анимации. Достаточно нари­совать нечто, затем стереть нарисованное, перерисовать немного измененным - и рисунок будет представляться ожившим.

Ранее мы рассматривали и использовали копирование одного графического объекта в другой методом Assign. Однако у канвы имеются и другие методы копи­рования. Это, прежде всего, метод CopyRect, позволяющий копировать прямоуголь­ную область источника изображения в прямоугольную область данной канвы. Ме­тод определен следующим образом:

procedure CopyRect(Dest: TRect; Canvas: TCanvas; Source: TRect);

Параметр Dest определяет прямоугольную область канвы, в которую произво­дится копирование. Параметр Canvas указывает источник, из которого копирует­ся изображение. Это может быть канва любого компонента: типа TImage, типа TBitMap и др. В частном случае источником может быть и канва того же компо­нента, в который производится копирование. Параметр Source определяет прямо­угольную область в источнике изображения, которая копируется в область Dest.

Копирование — это не просто перенос изображения. В общем случае копирова­ние означает сложное взаимодействие копируемого изображения и того, которое было до этого в области, куда производится копирование. Характер этого взаимо­действия определяется параметром CopyMode (режим копирования) той канвы, в которую производится копирование. По умолчанию значение CopyMode равно cmSrcCopy. Это единственный режим, при котором производится действительное копирование: изображение в Dest стирается и заменяется скопиро­ванным. Есть два значения — cm Whiteness и cmBlackness, при которых собствен­но никакое копирование не производится: просто область закрашивается соответ­ственно белым или черным цветом. А все остальные режимы определяют сложное взаимодействие копируемого изображения с тем, которое было в Dest. Особый ин­терес представляет режим cmSrdnvert, при котором изображения канвы и источ­ника комбинируются, используя булеву операцию XOR. Так же, как мы видели это для пера, повторное копирование в подобном режиме восстанавливает прежнее изображение на канве.

Приведем примеры копирования в различных режимах. Операторы

ImageI.Canvas.CopyMode:= cmSrcCopy;

Imagel.Canvas.CopyRect(Rect(0,0,200,200),Image2.Canvas;

Rect(0,0,200,:200));

обеспечивают копирование изображения фрагмента канвы компонента Image2 в указанную область канвы компонента Imagel. Изображение, которое ранее было на канве компонента Imagel в пределах области с координатами углов (0, 0) и (200, 200), просто заменяется новым. Операторы

Imagel.Canvas.CopyMode:= cmSrdnvert;

Imagel.Canvas.CopyRect(Rect(0,0,200,200),Image2.Canvas,

Rect(0,0,200,200));

Imagel.Canvas.CopyRect(Rect(0,0,200,200),Image2.Canvas,

Rect(0,0,200,200));

обеспечивают копирование изображения фрагмента канвы компонента Image2 в указанную область канвы компонента Imagel в режиме cmSrdnvert. После вы­полнения функции CopyRect в первый раз изображения в компонентах Imagel и Image2 налагаются друг на друга, а в результате выполнения функции CopyRect во второй раз исходное изображение на канве компонента Imagel восстанавлива­ется.

Операторы

Imagel.Canvas.CopyMode:= cmWhiteness;

Imagel.Canvas.CopyRect(Rect(0,0,200,200),Image2.Canvas,

Rect (0,0,200,200));

просто очищают указанную область канвы компонента Imagel, закрашивая ее бе­лым цветом. При этом изображение в компоненте Image2 никак не участвует в операциях копирования.

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

Помимо копирования свойство CopyMode используется также методом рисо­вания на канве Draw. Его описание:

procedure Draw(X, Y: Integer; Graphic: TGraphic);

Метод Draw рисует изображение, содержащееся в объекте, указанном параметром Graphic, сохраняя исходный размер изображения в его источнике и перенося изображение в область канвы объекта, верхний левый угол которой определяется параметрами X и Y. Источник изображения может быть битовой матрицей, пиктограммой или метафайлом. Если источник — объект типа TBitmap, то перенос изображения производится в режиме, установленном свойством канвы СоруMode.

Например, оператор

ImageI.Canvas.Draw(10,10,Bitmapl);

рисует на канве компонента Imagel изображение из компонента Bitmap1 в область с координатами левого верхнего угла (10, 10).

Еще один метод рисования — DrawFocusRect. Этот метод рисует изображение прямоугольника в виде, используемом для отображения рамки фокуса, операцией XOR. Функция DrawFocusRect объявлена следующим образом:

procedure DrawFocusRect(const Rect: TRect);

где Rect — прямоугольная область. Поскольку при рисовании используется операция XOR, то повторный вызов этого метода с тем же значением Rect удаляет изображение прямоугольника.

 



Поделиться:


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

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