Объект TCanvas
 
В этом обзоре � дам описание объекта TCanvas, изложу его смысл и внутренний мир, а также методы его использовани�.
 
Что такое TCanvas
TCanvas это объект, который предназначен дл� рисовани� различными графическими примитивами в окнах. Этот объект содержит набор методов дл� рисовани�, а также набор свойств, используемых дл� них. Фактически, объект TCanvas �вл�етс� дополненным вариантом графического контекста Windows. Каждому окну выдел�етс� область дл� рисовани� (поверхность), котора� соответствует размеру окна, на которой можно рисовать с помощью методов объекта TCanvas. Чтобы глубже пон�ть смысл этого объекта нужно окунутьс� в мир графики Windows на уровне Windows API.

Дело в том, что дл� того чтобы не путатьс�, Windows выдел�ет дл� каждого окна специальную логическую область и присваивает ей название. После этого разработчик использу� это название рисует именно в этой области. Если он направл�ет графический вывод в область с другим названием, то рисование происходит уже в другом окне. Эта область получила название графического контекста устройства. Контексты служат дл� логического разделени� всех графических операций Windows, и если сказать точнее, чтобы окна не мешали друг другу. Windows управл�ет всеми контекстами и берет на себ� все операции по отсечению вывода, который выходит за пределы окна и вывода, который закрыт другим окном. Программиру� на Win32 API нужно вручную определ�ть контексты дл� каждого окна. В данном случае под окном подразумеваетс� любой элемент управлени� Windows - кнопка, поле ввода и т.д. Определив контекст, автоматически организуетс� область котора� накладываетс� на окно (его рабоча� область) и она соответствует размерам окна. Сначала эта область пуста, а затем, с помошью функций GDI вы в любой момент можете направл�ть вывод в это окно указыва� в каждой из них название контекста, который предназначен дл� этого окна. Каждый контекст содержит также р�д параметров, которые используютс� дл� рисовани�. Допустим линии рисуютс� с помощью пера, которое в Win32 API имеет тип HPEN, соответственно нужно устанавливать его аттрибуты такие как цвет, толщина и т.д. Дл� заполнени� фигур используетс� кисть, котора� имеет тип HBRUSH. Чтобы заполнить фигуру нужно определить и этот объект, т.е. указать тип кисти, ее цвет и т.д. �о же самое касаетс� и шрифта дл� текста (HFONT). Все эти объекты создаютс� отдельно и затем в нужный момент помещаютс� в соответствующие свойства контекста. Дл� разработки окна с собственным контекстом на Win32 API уходит много времени и соответственно строк кода. Поэтому Delphi, как среда, котора� облегчает разработчику жизнь представл�ет немного иной подход к рисованию, хот� он и базируетс� на Win32 API.

Объект TCanvas был создан дл� того чтобы объеденить в единое целое контекст, его свойства и функции GDI дл� рисовани� в контексте. �еперь если вы рисуете в этом объекте с помощью функций рисовани�, вы можете не заботитс� о том, что рисование будет выведено не в тот контекст или не в то окно.

 
Как TCanvas используетс� в Delphi
Как известно все в Delphi состоит из компонентов. Хот� и эти компоненты имеют таких хитрых предков как TPersistent, TComponent и TControl, все они �вл�ютс� окнами. Соответственно у каждого из них может быть контекст, на котором можно рисовать. Однако дл� логических и стратегических целей разработчики Delphi НЕ позвол�ют рисовать в абсолютно каждом компоненте. Допустим нельз� вз�ть и нарисовать что-нибудь на кнопке типа TButton или в поле редактировани�, типа TEdit. Однако это не проблема, так как существует целый класс потомков и предков, позвол�ющих организовывать эти эффекты. Я сейчас не буду заостр�ть внимание на каждом из них. По�сню только общие принципы.

У каждого компонента, в котором можно что-либо рисовать есть свойство Canvas. Именно оно и �вл�етс� собственным TCanvas-ом данного компонента. Он и используетс� дл� вывода в данный компонент. �акже у каждого компонента есть обработчик OnPaint, который вызываетс� каждый раз когда на внешний вид формы что-то повли�ло, т.е. ее перекрыло что-то, или ее свернули. Поэтому все рисование стоит выполн�ть в этом методе.

Вот простейший пример того, как можно нарисовать что-то в форме.


procedure Form1.FormPaint(Sender: TObject);
begin
  Canvas.MoveTo(10,10);
  Canvas.LineTo(10,20);
  Canvas.LineTo(20,20);
  Canvas.LineTo(20,10);
  Canvas.LineTo(10,10);
end;

Данный пример рисует в форме пр�моугольник (квадрат 10x10) использу� методы рисовани� объекта Canvas. Вы заметили что процедура называетс� FormPaint, хот� � ранее говорил, что она называетс� OnPaint. Дело в том что между событием и процедурой реакции на событие есть определенна� разница. Дело в том, что каждому событию присваиваетс� определенна� процедура. Событи� нужно искать на вкладке Events ObjectInspector-а, найдите там событие OnPaint, дважды щелкните на него и вы окажетесь в процедуре FormPaint, если это будет форма.

Итак, вы увидели, как быстро теперь можно рисовать в форме. Это значительно быстрее чем делать вызовы Win32 API. (хот� дл� полного эффекта их все-таки делать надо,однако об этом далее позже....). Выполнив этот пример мы видим пр�моугольник нарисованный тонкой линией черного цвета. Неужели этого нельз� изменить, подумаете вы? Конечно же можно и об этом далее.

 
Аттрибуты TCanvas
Объект TCanvas содержит набор свойств, определ�ющих как будут рисоватьс� линии, как будут заполн�тьс� фигуры и как будет изображатьс� текст. Соответсвенно они называютс� Pen, Brush и Font.

Линии рисуют пером, которое определ�етс� свойством Pen. Свойство Pen �вл�етс� объектом типа TPen, который содержит соответствующие методы и свойства, определ�ющие аттрибуты линии. Заполн�ют фигуры кистью, котора� определ�етс� свойством Brush, которое �вл�етс� объектом TBrush и содержит методы и свойства дл� определени� аттрибутов кисти. �екст рисуетс� с использованием указанного шрифта, который определ�етс� свойством Font, которое �вл�етс� объектом TFont и содержит все необходимые аттрибуты шрифта.

После того как вы определили любой из этих объектов, он будет распростран�тьс� на все дальнейшие функции рисовани�, дл� которых он требуетс� до тех пор, пока вы не изменили его свойства. Это значит, что если вы, например, установили перо в красный цвет и нарисовали красную линию, то дл� того чтобы нарисовать синюю линию, вам нужно снова изменить соответствующее свойство объекта Pen.

Далее будут подробнее рассмотрены эти объекты.

 
TPen
TPen �вл�етс� объектом, который служит дл� создани� перьев, с помощью которых рисуютс� линии. Св�зь этого объекта с TCanvas осуществл�етс� с помощью свойства Pen, которое используетс� каждым графическим методом TCanvas, который рисует линии.

Объект TPen определ�ет перо как объект состо�щий из:

Стил� линии: Style
Цвета линии: Color
�олщины линии: Width

Стиль линии определ�ет, будет ли лини� сплошной, штриховой, штрихпунктирной и т.д. Вы можете установить это свойство в одно из следующих значений:

psSolid - сплошна� лини�
psDash - штрихова� лини�
psDot - пунктирна� лини�
psDashDot - штрихпунктирна� лини�
psDashDotDot - лини� состо�ща� из комбинаций одного штриха и двух точек
psClear - пуста� (не рисуетс�)
psInsideFrame - сглаженна� (кра� линии закруглены)

�олщина линии указываетс� в виде числа. �олщина измер�етс� в пикселах.

Цвет линии может указыватьс� в виде специального шестнадцатеричного 4-х байтового значени�, где определены концентраци� красной, зеленой и синей составл�ющих. Вот как выгл�дит шаблон:

$00000000

Первые два нул� зарезервированы, вторые два разр�да используютс� как шестнадцатеричное представление концентрации зеленого цвета, вторые два разр�да дл� синей составл�ющей, и третие два разр�да дл� красной. В дес�тичном представлении концентраци� выражаетс� в диапазоне от 0 до 255, а в шестнадцатеричном, соответственно: от 00 до FF. Комбиниру� эти три параметра в разных концентраци�х можно добитьс� любого цвета из 16-милионной гаммы. Вот несколько примеров:

$00FF0000 - зеленый
$0000FF00 - синий
$000000FF - красный
$00FF00FF - желтый
$00FFFF00 - голубой
$0000FFFF - розовый
$00FFFFFF - белый

Можно, конечно, сидеть и набирать эти комбинации каждый раз, чтобы изменить цвет. Дл� создани� каких-либо красивых пейзажей и натюрмортов это даже необходимо. Однако если нужно просто нарисовать три линии красного, голубого и зеленого цвета, то пользу�сь этим методом можно потратить значительно больше времени чем можно было бы потратить. Дл� того, чтобы выполн�ть примитивные рисунки проще, был создан набор удобочитаемых констант, которые определ�ют часто-иснользуемые цвета. Пользу�сь ими, можно не набирать эти цвета с помощью этого 4-х байтового значени�:

clLime - светло-зеленый
clGreen - темно-зеленый
clAqua - светло-голубой
clTeal - темно-голубой
clRed - светло-красный
clMaroon - темно-красный
clBlue - светло-синий
clNavy - темно-синий
clFuchsia - светло-розовый
clPurple - темно-розовый
clYellow - светло-желтый
clOlive - темно-желтый
clWhile - белый
clBlack - черный
clSilver - стандартный серый используемый дл� кнопок, форм и т.д.
clLtGray - светло-серый
clGray - серый
clDkGray - темно-серый

Кому проще так, пользуйтесь, хот� это то же самое.

Пример установки пера:

Canvas.Pen.Style:=psDashDot;
Canvas.Pen.Width:=4;
Canvas.Pen.Color:=clLime;
Примечание: ни один стиль линии кроме сплошного не работает если Width:=1;
 
TBrush
Кисть используетс� дл� заполнени� фигур и содержит следующие параметры:

Стиль(узор) - Style
Цвет - Color
Картинка - Bitmap

Это значит, что любую фигуру можно заполнить либо цветом, либо узором с цветом, либо изображением из BMP-файла.

Узоры бывают следующие:

bsSolid - сплошное заполнение
bsCross - заполнение клеткой
bsDiagCross - заолнение косой сеткой
bsHorizontal - заполнение горизонтальными лини�ми
bsVertical - заполнение вертикальными лини�ми
bsBDiagonal - заполнение диагональными лини�ми ///////
bsFDiagonal - заполнение диагональными лини�ми \\\\\\\
bsClear - заполнени� нет

Цвет указываетс� также как и у пера, поэтому описывать второй раз не буду.

Картинка �вл�етс� объектом TBitmap, который содержит много интересных свойств и методов. Вообще использование битовых карт это очень обширна� тема котора� глубоко уходит в Win32 API и этому посв�щена отдельна� стать�. Здесь � не буду описывать все тонкости этого объекта. Дл� использовани� этого объекта в качестве кисти важно знать следующее: можно загрузить картинку из файла в переменную Bitmap и затем заполн�ть ей все что угодно. Причем, объект TBitmap �вл�етс� пустым изначально, так как система не предполагает что кажда� кисть будет использовать картинку и не выдел�ет под Bitmap ни одного байта. Поэтому нужно СОЗДА�Ь объект Bitmap перед тем как загружать туда что-то. Создание объектов осуществл�етс� с помощью метода Create, который начинает свое существование с TObject. Еще одна особенность картинок дл� кистей заключаетс� в том, что дл� кисти можно использовать картинки размером 8x8 пикселов. Обидно, подумаете вы. Но на кист�х мир клином не сходитс� и если вы хотите заполн�ть что-либо большими картинками, то их можно просто изображать на Canvas-е, а не заполн�ть ими через TBrush. Ладно, отвлекс� от темы. Итак у вас есть картинка 8x8 в файле и вы хотите заполнить ей что-либо. Дл� этого ее нужно загрузить в свойство Bitmap объекта TBrush. Как уже сказано ранее Bitmap носит тип TBitmap, и объект TBitmap содержит метод LoadFromFile, позвол�ющий загрузить картинку из файла на диске. Допустим у нас есть картинка Image1.bmp и мы хотим ее загрузить. Дл� этого мы пишем:

Canvas.Brush.Bitmap:=TBitmap.Create;
Canvas.Brush.Bitmap.LoadFromFile('image1.bmp')
Первой строчкой мы выдел�ем пам�ть дл� свойства Bitmap использу� переделанный объектом TBitmap метод Create. Затем мы загружаем картинку в Bitmap использу� метод LoadFromFile.

Все, далее мы можем заполн�ть все что угодно этой картинкой. Естественно, если вы заполн�ете картинкой, то свойства Color и Style не используютс�.

После того как картинка больше не нужна, нужно ее освободить, т.е. удалить. Дл� этого используетс� метод Free:

Canvas.Brush.Bitmap.Free.

ВАЖНО: Перед тем как загрузить другую картинку в Bitmap нужно ОЧИС�И�Ь старую методом Free.

 
TFont
Шрифты используютс� дл� рисовани� текста. Св�зь шрифта с TCanvas производитс� с помощью свойства Font, которое �вл�етс� объектом типа TFont. Дл� шрифта важны следующие свойства этого объекта:

Им� шрифта: Name
Размер шрифта: Height
Цвет шрифта: Color
Флаг равности символов: Pitch
Кодировка символов: Charset

Им� шрифта это строка в которой содержитс� его название, допустим 'Arial Cyr'. С размером шрифта вы тоже сталкивались при работе с любой программой Windows. Единственное, что можно дополнить, что здесь размер указываетс� со знаком минус, допустим -12, -14 и т.д. Цвет шрифта определ�етс� также как и цвет чего угодно другого. Идите в раздел где описываетс� TPen, чтобы узнать о том, как это делаетс�. Флаг равности символов указывает, имеют ли символы одинаковый размер или нет. Если этот флаг установлен в fpFixed, то все символы имеют одинаковый размер, если в fpVariable - разный. В данном случае подразумеваетс� ЛОГИЧЕСКИЙ размер. Физически символы не раст�гиваютс� и не сжимаютс�. Просто за размер беретс� размер самой большой буквы, допустим Ж и логический пр�моугольник вокруг каждого символа приравнивают к логическому пр�моугольнику этого символа. Просто рассто�ни� между маленькими буквами станов�тс� больше.

Кодировка символов это пон�тие, идущее из глубин Windows. Дело в том, что клавиатуры бывают разные, но общее у них одно: первые 128 символов включающих английский алфавит в нижнем и ВЕРХНЕМ регистрах, цифры, скобки, точки, зап�тые и т.д. Остальные 128 символов разные дл� каждой страны, они включают алфавит этой страны и другие символы. Поэтому было придумано такое пон�тие как КОДИРОВКА и дл� каждой страны эта кодировка разна�. Поэтому нужно установить правильную кодировку дл� вашей программы, в зависимости от того, дл� какой страны вы ее пишите. Названи� всех кодировок можно прочитать в справочнике. Дл� нашей страны нужно использовать кодировку RUSSIAN_CHARSET. Нужно присвоить это значение свойству Charset.

Итак, пример установки шрифта:

Canvas.Font.Name:='Arial Cyr';
Canvas.Font.Height:=-20
Canvas.Font.Color:=clRed;
Canvas.Font.Pitch:=fpVariable;
Canvas.Font.Charset:=RUSSIAN_CHARSET.

После этого весь текст будет рисоватьс� с использованием этих параметров до тех пор, пока вы их не измените.

 
И�ОГ
Итак мы знаем, что все параметры рисовани� объекта TCanvas сосредотачиваютс� в трех объектах: Pen, Brush и Font. Pen используетс� дл� рисовани� линий и требует чтобы в нем указали стиль линии (Style), �олщину (Width) и цвет (Color). Brush используетс� дл� заполнени� фигур и использует такие параметры как цвет (Color), узор (Style) и картинку (Bitmap). При использовании картинки Style и Color не используютс�. При использовании картинки ее нужно создать, а после использовани� уничтожить. Font используетс� дл� рисовани� текста и использует такие параметры как название шрифта (Name), размер(Height), цвет(Color), флаг равности символов (Pitch) и кодировку (Charset).

Итак, теперь мы знаем как заставить Canvas рисовать �АК, как нам надо. �еперь разберемс� Ч�О же можно рисовать с помощью объекта TCanvas.

 
Рисование в TCanvas
Прежде чем узнать о том, Ч�О рисовать, целесообразно знать ГДЕ рисовать. Хот� это не �вл�етс� фатальной вещью, однако та часть котора� выйдет за пределы контекста, будет просто отсечена. Поэтому желательно этого не допустить. В объекте TCanvas есть свойство ClipRect, в котором определены размеры пр�моугольника, за границы которого не нужно вылазить при рисовании. Это свойство имеет тип TRect, в котором имеютс� параметры:

Left - координата X левого кра� пр�моугольника
Right - координата X правого кра� пр�моугольника
Top - координата Y верхнего кра� пр�моугольника
Bottom - координата Y нижнего кра� пр�моугольника.

�аким образом можно рисовать ориентиру�сь на эти координаты и не вылазить за их пределы. Вот например программа котора� рисует параллелограмм с диагонал�ми, вписанный в окно:

Canvas.MoveTo(ClipRect.Left,ClipRect.Top);
Canvas.LineTo(ClipRect.Right,ClipRect.Top);
Canvas.LineTo(ClipRect.Right,ClipRect.Bottom);
Canvas.LineTo(ClipRect.Left,ClipRect.Bottom);
Canvas.LineTo(ClipRect.Left,ClipRect.Top);
Canvas.LineTo(ClipRect.Right,ClipRect.Bottom);
Canvas.MoveTo(ClipRect.Right,ClipRect.Top);
Canvas.LineTo(ClipRect.Left,ClipRect.Bottom);
�еперь вы знаете как вписыватьс� в рамки. �еперь о том, что же можно делать через TCanvas.

1. Можно рисовать примитивы: линии, пр�моугольники, дуги, окружности, эллипсы,многоугольники

2. Можно их заполн�ть

3. Можно рисовать текст

4. Можно вставл�ть изображени� из файлов

5. Можно брать куски одного канваса и вставл�ть в другой

6. Другие вспомогательные действи�

 
Рисование линий и пр�моугольников
Насчет линий вы уже знаете. Линии рисуютс� методом LineTo, где указываетс� куда идет лини� (координаты конца). Координаты начала задаютс� методом MoveTo. Это очень важный метод. Он задает координаты так называемого КУРСОРА, или можно сказать точки отсчета, на которой будут базироватьс� фигуры. После того как вы сделали LineTo, эта точка отсчета перемещаетс� в точку конца линии и начало следующей линии уже будет в этой точке. �о же самое касаетс� и других фигур.

Пр�моугольники бывают двух типов: заполненные и не заполненные. Незаполненный пр�моугольник рисуетс� с помощью метода Rectangle(X1,Y1,X2,Y2) где указываютс� координаты левого верхнего (X1,Y1) и правого нижено (X2,Y2) углов пр�моугольника.

Заполненные пр�моугольники рисуютс� с помощью метода FillRect(Rect:TRECT), который требует не X1,Y1,X2,Y2, а TRect структуру в качестве координат начала и конца. Я не думаю, что это создаст дл� вас проблему.

Далее идет пример использовани� этих методов:

var R1:TRect;
begin
  R1.Left:=ClipRect.Left+1;
  R1.Right:=ClipRect.Right-1;
  R1.Top:=ClipRect.Top+1;
  R1.Bottom:=ClipRect.Bottom-1;
  Canvas.Rectangle(Canvas.ClipRect.Left,Canvas.ClipRect.Top,
                                Canvas.ClipRect.Right,Canvas.ClipRect.Bottom);
  Canvas.FillRect(R1);
  Canvas.MoveTo(ClipRect.Left,ClipRect.Top);
  Canvas.LineTo(ClipRect.Right,ClipRect.Bottom);
  Canvas.MoveTo(ClipRect.Right,ClipRect.Top);
  Canvas.LineTo(ClipRect.Left,ClipRect.Bottom);
end;

В данном примере объ�вл�етс� структура R1 и ей присваиваетс� область котора� сплюснута на один пиксел по отношению к ограничивающему пр�моугольнику. Затем рисуетс� сначала пустой пр�моугольник использу� текущие параметры пера, затем в него вписываетс� заполненный пр�моугольник, использу� текущие параметры кисти. Затем рисуютс� две диагонали внешнего пр�моугольника.

Метод FillRect не обводит свой пр�моугольник, а просто рисует пр�моугольник, состо�щий из заполнени�.

�акже существует метод FrameRect, который �вл�етс� копией FillRect, однако рисует незаполненный пр�моугольник. Использу� его, можно заменить Rectangle следующим образом:

FrameRect(Canvas.ClipRect);

Проще, не правда ли.

�акже, можно рисовать пр�моугольники с закругленными кра�ми. Дл� этого используетс� метод RoundRect(X1,Y1,X2,Y2,X3,Y3). Здесь кроме координат начала и конца указываетс� кривизна в параметрах X3,Y3. Это, так называемые вертикальные и горизонтальные радиусы эллипса, дуга которого и будет скругл�ть каждый край пр�моугольника. Данный вид пр�моугольника обведен линией с текущими параметрами и заполнен кистью с текущими параметрами.

�акже можно нарисовать пр�моугольник в стиле пр�моугольника, который по�вл�етс� на кнопке, когда она получает фокус. Дл� этого используетс� метод DrawFocusRect(Rect:TRect);

Подведем итоги:

MoveTo(X,Y) - ставит координаты начала линии
LineTo(X,Y) - рисует линию из точки MoveTo в X,Y
Rectangle(X1,Y1,X2,Y2) - рисует незаполненный пр�моугольник использу� координаты левого верхнего и правого нижнего углов
FrameRect(Rect:TRect) - то же самое, только использует структуру Rect дл� координат
FillRect(Rect:TRect) - рисует заполненный и необведенный пр�моугольник
RoundRect(X1,Y1,X2,Y2,X3,Y3) - рисует заполненный и обведенный пр�моугольник с закругленными кра�ми. Дл� указани� кривизны используютс� радиусы логических эллипсов, прикрепленных к кра�м пр�моугольника.
DrawFocusRect(Rect:TRect) - рисует пр�моугольник, в стиле зафокусированного элемента управлени�.

 
Дуги, окружности и эллипсы
Дл� рисовани� дуги используетс� метод Arc(X1,Y1,X2,Y2,X3,Y3,X4,Y4). В данном случае X1,Y1,X2,Y2 это координаты пр�моугольника в который вписан эллипс. Затем из центра этого эллипса идут две логические линии в точки X3,Y3 и X4,Y4. Все, кроме той части эллипса, котора� находитс� между этими точками эллипса отсекаетс�. �аким образом получаетс� дуга.

�акже существует метод Chord(X1,Y1,X2,Y2,X3,Y3,X4,Y4), который рисует дугу и соедин�ет ее кра� линией. Это уже получаетс� замкнута� фигура, котора� обводитс� линией и заполн�етс� текущей кистью.

Эллипс рисуетс� с помощью метода Ellipse(X1,Y1,X2,Y2), где в качестве параметров указываютс� координаты логического пр�моугольника, в который вписываетс� эллипс. Эллипс �вл�етс� фигурой замкнутой и поэтому обводитс� текущей линией и заполн�етс� текущей кистью.

�акже можно нарисовать сектор эллипса с помощью функции Pie(X1,Y1,X2,Y2,X3,Y3,X4,Y4). �ехнологи� рисовани� сектора такова. Сначала рисуетс� эллипс, вписанный в пр�моугольник X1,Y1,X2,Y2 и затем из его центра рисуютс� линии концы которых идут в точки X3,Y3 и X4,Y4. Все, кроме того что находитс� между этими лин�ми убираетс� и полученна� фигура �вл�етс� сектором. Сектор, это тоже фигура замкнута� и поэтому обводитс� и заполн�етс�.

Подведем итоги:

Arc(X1,X2,Y1,Y2,X3,Y3,X4,Y4) - рисует дугу - часть эллипса между точками X3,Y3,X4,Y4
Chord (X1,Y1,X2,Y2,X3,Y3,X4,Y4)- рисует дуга, соединив ее кра� линией
Ellipse(X1,Y1,X2,Y2) - рисует эллипс, вписанный в логический пр�моугольник
Pie(X1,Y1,X2,Y2,X3,Y3,X4,Y4) - рисует сектор эллипса, наход�щейс� между его точками X3,Y3,X4,Y4.

 
Многоугольники и ломанные
Ломанную линию можно нарисовать с помощью метода PolyLine. В качестве параметра, эта функци� принимает массив точек. Кажда� точка это переменна� типа TPoint, у которой есть два параметра: X и Y. В массиве может быть любое количество точек. Данный метод просто соедин�ет их, образу� ломанную.

Вот пример:

var
  MyPnts: array[1..5] of TPoint;
begin
  MyPnts[1].X:=10; MyPnts[1].Y:=10;
  MyPnts(2].X:=15; MyPnts[2].Y:=5;
  MyPnts[3].X:=20; MyPnts[3].Y:=10;
  MyPnts[4].X:=25; MyPnts[4].Y:=5;
  MyPnts[5].X:=30; MyPnts[5].Y:=10;
  PolyLine(MyPnts);
end;

Этот пример рисует ломанную линию из четырех сегментов. Можно замкнуть ее, указав в качестве последней точки начало ломанной. �огда получитс� многоугольник, однако заполнен он не будет, так как все равно считаетс� ломанной.

А дл� того чтобы нарисовать заполненный многоугольник, используетс� метод Polygon, который также требует в качестве параметра массив точек и соедин�ет начало и конец ломанной за вас, образу� многоугольник. �акже он обводит его линией и заполн�ет текущей кистью.

Следующие два метода � не знал к чему отнести, то ли к кривым, то ли к многоугольникам. Однако отнес к многоугольникам, так как методы очень похожи на многоугольники по своей структуре. Эти методы предназначены дл� рисовани� кривых безье. Метод PolyBezier рисует ломанную линию преобразованную в дугу. Первый сегмент состоит из четырех точек: начала, конца и двух контрольных точек между ними, последующие сегменты состо�т из трех точек, так как используют конец предыдущего в качестве своего начала. Однако эта функци� все это просит в виде одного массива точек, как и предыдущие. Просто оно разбивает их на сегменты дл� того чтобы точнее и плавнее преобразовывать линии в дуги. Данна� функци� не заполн�ет получившуюс� фигуру.

�акже существует метод PolyBezierTo, который делает то же самое, что и PolyBezier, но устанавливает КУРСОР в конец последнего сегмента (просто выполн�ет MoveTo дл� этой точки).

Подведем итоги

Дл� рисовани� ломанных пр�мых линий и многоугольников существуют методы Polyline(Points: array of TPoint) и Polygon(Points: array of TPoint). Оба требуют массива точек, последний замыкает начало и конец ломаной образу� многоугольник и заполн�ет его.

Дл� рисовани� кривых ломанных линий используютс� методы PolyBezier(Points: array of TPoint) и PolyBezierTo(Points: array of TPoint), которые также требуют массив точек. Дл� точного преобразовани�, каждый сегмент состоит из четырех точек: начала, конца и двух контрольных точек между ними. По этим четырем точкам плавно проводитс� дуга. PolyBezierTo устанавливает курсор в позицию последней точки.

 
Работа с текстом
�екст непосредственно выводитс� с помощью функций TextOut(X,Y,S), где X,Y это координаты текста и S, это строка текста и TextRect(Rect:TRect,X,Y,S), где кроме всех этих параметров указываетс� Rect - логический пр�моугольник, в который этот текст должен быть вписан. Весь текст, который выходит за пределы этого пр�моугольника отсекаетс�.

�акже можно определ�ть ширину и высоту строки текста, прежде чем выводить его. Дл� этого используютс� функции TextWidth(S) и TextHeight(S). Перва� дл� ширины текста, а втора� дл� высоты. В обоих указываетс� строка. Эти функции можно присвоить переменным числового типа:

W:=Canvas.TextWidth('Привет');
H:=Canvas.TextHeight('Привет');

�акже существует функци� TextExtent(S), котора� возвращает значение типа TSize. TSize содержит параметры cx и cy, которые содержат длину и ширину строки. Это то же самое, что и использовать две предыдущие функции. Однако удобнее, так как меньше переменных и строк кода.

Подведем итоги:

�екст можно вывести в указанную точку с помощью метода TextOut(X,Y,S), а также в указанную точку ограничивающего пр�моугольника с помощью метода TextRect(Rect:TRect,X,Y,S);. Предварительно можно определить ширину (TextWidth(S)) и высоту(TextHeight(S)) текста. Либо все сразу - TextExtent(S).

 
Заполнение
Мы говорили раньше о том, что бывают заполненные фигуры или не заполненные. Почему бы не заполн�ть все что угодно? Дл� этого используетс� метод FloodFill(X,Y,Color,FillStyle).

�еперь подробнее о том, как работает этот метод. Он начинает работать, заполн�� все точки вокруг X,Y текущей кистью. Если FillStyle=fsSurface, то он заполн�ет только точки цвета Color и не ведет заполнение при встрече точки другого цвета, т.е пытаетс� ее обойти. Если этого не удаетс�, то метод прекращает работу. Если FillStyle=fsBorder, то метод заполн�ет все точки которые НЕ имеют цвет Color, а в остальном действует также как и в первом случае. Color в данном случае указываетс� как и любой другой цвет (см. описание объекта TPen в данном обзоре).

 
Работа с картинками
Как говорилось ранее, можно вставл�ть картинки из файлов на рабочую область TCanvas-а, а также брать куски одного Canvas-а, переносить их в другой. Здесь все эти хитрые манипул�ции будут рассмотрены.

Дл� того чтобы вставить картинку используетс� функци� Draw(X,Y,Bitmap). X,Y это координаты точки, в которую вставить картинку, а Bitmap это объект типа TBitmap, представл�ющий из себ� картинку. Дл� того чтобы поместить картинку в Canvas, нужно сначала выделить пам�ть под этот объект и загрузить в него картинку откуда-нибудь, с диска например:

var
  B1: TBitmap;
begin
  B1:=TBitmap.Create;
  B1.LoadFromFile('image1.bmp');
  Canvas.Draw(20,20,B1);
end;

Данный пример рисует картинку из файла image1.bmp в позиции 20,20 указанного Canvas-а.

Метод StretchDraw(Rect:TRect,Bitmap:TBitmap) рисует картинку вписыва� ее в указанный логический пр�моугольник Rect, при необходимости раст�гива� или сплющива� ее (измен�� масштаб, если быть культурнее).

�акже, можно очень хитро рисовать картинки. Самым хитрым методом дл� рисовани� картинки на Canvas-е � по праву считаю метод BrushCopy(Dest:TRect; Bitmap:TBitmap; Source:TRect; Color:TColor); Данный метод рисует кусок изображени� Bitmap ограниченный пр�моугольником Source в пр�моугольнике Dest, при необходимости раст�гива� или сплющива� его. �акже, этот метод не изображает все точки с цветом Color на Canvas-е, осуществл�� таким образом эффект прозрачности. Вот такие вот штуки можно Canvas-ом творить!

�акже можно копировать кусок одного Canvas-а в другой, т.е. часть изображени� из контекста одного элемента управлени�, (или формы, или окна или чего угодно другого) в указанное место контекста другого элемента управлени�. Это делаетс� методом CopyRect(Dest:TRect; Canvas:TCanvas; Source: TRect);. Данный метод копирует участок изображени� текущего Canvas-а, вписанный в пр�моугольник Source в пр�моугольник Dest указанного Canvas-a. При этом участок Canvas-а назначени� раст�гиваетс� или сплющиваетс� нужным образом.

 
Другие операции
Есть еще несколько методов, которые � ни к чему не смог отнести. Во первых это набор методов защиты от рисовани� других потоков данной программы в указанном Canvas-е. Это нужно делать в том случае, если ваша программа многопоточна и есть возможность, что другой поток может нарисовать что-то в то врем�, как Canvas текущего потока что-либо рисует. В этом случае результат может быть нежелательным. Чтобы предотвратить подобный эффект нужно "замкнуть Canvas" методом Lock, затем нарисовать все что нужно и "разомкнуть" его методом Unlock. �акже, если ваша программа настолько больша�, что вы уже сами не знаете, что натворили две недели назад, существует метод TryLock, который сначала проверит, замкнут ли данный Canvas или нет, и если нет, то замкнет.

�акже существует метод Refresh, который удал�ет текущие настройки Pen, Brush и Font, возвраща� их в состо�ние по умолчанию.

Естественно, как и в любом объекте, в объекте TCanvas существуют такие методы как Create и Destroy. Первый создает Canvas и выдел�ет под него пам�ть, второй уничтожает и освобождает выделенную пам�ть. Нежелательно уничтожать и создавать Canvas-ы, встроенные в элементы управлени�. За это отвечает Delphi. Этими методами вам придетс� пользоватьс� при создании своих собственных, логических Canvas-ов.

 
Заключение
Вот и все, что вы можете делать с TCanvas. Все методы работают основыва�сь на установках Pen, Brush и Font. Вот полный список:

ЛИНИИ И ПРЯМОУГОЛЬНИКИ

MoveTo(X, Y:Integer);
LineTo(X, Y:Integer);
Rectangle(X1, Y1, X2, Y2:Integer);
FrameRect(Rect:TRect);
FillRect(Rect:TRect);
RoundRect(X1, Y1, X2, Y2, X3, Y3:Integer);
DrawFocusRect(Rect:TRect);

ДУГИ

Arc(X1, Y1, X2, Y2, X3, Y3, X4, Y4:Integer);
Chord(X1, Y1, X2, Y2, X3, Y3, X4, Y4:Integer);
Ellipse(X1, Y1, X2, Y2:Integer);
Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4:Integer);

МНОГОУГОЛЬНИКИ

PolyLine(Points:array of TPoint);
Polygon(Points:array of TPoint);
PolyBezier(Points:array of TPoint);
PolyBezierTo(Points:array of TPoint);

�ЕКС�

TextOut(X, Y:Integer; S:String);
TextRect(Rect:TRect; X, Y:Integer; S:String);
TextWidth(S:String):Integer;
TextHeight(S:String):Integer;
TextExtent(S:String):TSize;

ЗАПОЛНЕНИЕ

FloodFill(X, Y:Integer; Color:TColor; FillStyle:TFillStyle);

КАР�ИНКИ

Draw(X, Y:Integer; Bitmap:TGraphic);
StretchDraw(Rect:TRect; Bitmap:TGraphic);
BrushCopy(Dest:Rect; Bitmap:TBitmap; Source:TRect; Color:TColor);
CopyRect(Dest:Rect; Canvas:TCanvas; Source:TRect);

ЗАЩИ�А

Lock;
UnLock;
TryLock;

ДРУГИЕ ОПЕРАЦИИ

Create;
Destroy;
Refresh;

ВСЕГО: 31 метод.

 
Внутренний механизм TCanvas
�о что � расскажу сейчас не потребуетс� дл� того чтобы нарисовать какую-нибудь картинку в форме. Это потребуетс� дл� того чтобы знать, как TCanvas ув�зан с графическим механизмом Windows.

Итак, каждый элемент управлени� в котором можно рисовать содержит Canvas. Объект TCanvas имеет свойство Handle типа HDC, это и есть контекст окна элемента управлени�. Каждый графичекий метод перекодируетс� в аналогичный графический метод (или набор) Win32 API, в котором �вно указываетс� эта ссылка на контекст. Допустим Canvas.LineTo(X,Y) перекодируетс� в аналогичную функцию Win32.API LineTo(Canvas.Handle,X,Y), где �вно указываетс� ссылка на контекст. �акже точно при установке пера, кисти и шрифта, устанавливаютс� соответствующие объекты Win32 API : HPEN, HBRUSH и HFONT помещаютс� в Handle. Вот как это в Win32 API делаетс�:

SelectObject(Canvas.Handle,Canvas.Pen.Handle);
SelectObject(Canvas.Handle,Canvas.Brush.Handle);
SelectObject(Canvas.Handle,Canvas.Font.Handle);

Дело в том, что дл� св�зи с Win32 API в объектах TPen, TFont и TBrush тоже есть свойство Handle, указывающее на данный объект уровн� Win32 API. В TPen - Handle имеет тип HPEN, в TBrush - Handle имеет тип HBRUSH и в TFont - Handle имеет тип HFONT.

�аким образом все направл�етс� на Handle объекта Canvas. �ак как Handle �вл�етс� контекстом, то естественно Windows правильно рисует в нем. Каким же образом это Handle инициализируетс�? Очень просто! Дело в том, что у всех ОКОННЫХ элементов управлени� тоже есть сво� Handle, котора� объ�влена на уровне TWinControl - предка всех оконных элементов управлени�. В данном случае Handle имеет тип HWND, а HWND это оконна� ссылка. Чтобы получить контекст, нужно указать окно, дл� которого его нужно получить. Окно в Win32 API указываетс� в виде ссылки. Контекст можно получить функцией Win32 API GetDC. Эту операцию вам делать не приходитс�, она происходит автоматически. Вот, например, как Delphi получает контекст дл� формы Form1.

Form1.Canvas.Handle:=GetDC(Form1.Handle);

Функци� GetDC берет ссылку на окно формы в качестве параметра.

Итак, алгоритм таков. Сначала TCanvas получает ссылку на контекст своего элемента управлени� использу� его оконную ссылку. Затем он выполн�ет графические операции на эту контекстную ссылку Handle, а при изменении параметров рисовани�, он пользуетс� услугами объектов TPen, TBrush и TFont, которые занос�т все изменени� в свои свойства более низкого уровн� HPEN, HBRUSH и HFONT. Эти свойства нужным образом передаютс� в Handle TCanvas-а.

Вот таким образом изнутри выгл�дит процесс рисовани� в окнах.

 
Общее заключение
Я думаю, что довольно детально разобрал TCanvas. Причем ИМЕННО TCanvas. Здесь также упоминались довольно важные вещи, такие как Win32 API или объект TBitmap. Второе здесь очень кратко затронуто, но � бы порекомендовал почитать об этом подробнее. По этому поводу у мен� есть стать�. TBitmap это фундаментальный объект рисовани� в Windows. �акже последний раздел может вселить определенные непон�тности. Дело в том, что многие элементы управлени� вообще не имеют свойства TCanvas, хот� и �вл�ютс� ОКНАМИ. Поэтому � изложил внутренний механизм работы TCanvas дл� того, чтобы вы пон�ли, что не на TCanvas-е мир клином сошелс�, что можно рисовать в любом окне. И в качестве продолжени� этой темы � порекомендовал бы почитать статью "Как рисовать где угодно", в которой изложен метод хитрого обмана Delphi, позвол�ющего рисовать в любых элементах управлени� и в любых их местах.

А теперь, пожалуй все. Прочтите это еще пару раз (не так уж и много!!!) и об�зательно пробуйте. Удачного Вам рисовани�.

С Уважением, А.Германов.