Класс
TCanvas
Этот класс — сердцевина графической подсистемы Delphi. Он объединяет в себе и "холст" (контекст конкретного устройства GDI), и "рабочие инструменты" (перо, кисть, шрифт), и даже "подмастерьев" (набор функций по рисованию типовых геометрических фигур). Будем называть его канвой.
Канва не является компонентом, но она присутствует в качестве свойства во многих других компонентах, которые должны уметь нарисовать себя и отобразить какую-либо информацию.
Читатели, знакомые с графикой Windows, узнают в TCanvas объектно-ориентированную надстройку над контекстом устройства Windows (Device Context, DC). Дескриптор устройства, над которым "построена" канва, может быть востребован для различных низкоуровневых операций. Он задается свойством:
property Handle: HDC;
Для рисования канва включает в себя шрифт, перо и кисть:
property Font: TFont; property Pen: TPen; property Brush: TBrush;
Кроме того, можно рисовать и поточечно, получив доступ к каждому пикселу. Значение свойства:
property Pixels[X, Y: Integer]: TColor;
соответствует цвету точки с координатами X, Y.
Необходимость отрисовывать каждую точку возникает нередко. Однако, если нужно модифицировать все или хотя бы многие точки изображения, свойство Pixels надо сразу отбросить — настолько оно неэффективно. Гораздо быстрее редактировать изображение при помощи свойства scanLine объекта TBitmap; об этом рассказано ниже.
Канва содержит методы-надстройки над всеми основными функциями рисования GDI Windows и свойства, которые приведены в табл. 10.4 и 10.5. При их рассмотрении имейте в виду, что все геометрические фигуры рисуются текущим пером. Те из них, которые можно закрашивать, закрашиваются с помощью текущей кисти. Кисть и перо при этом имеют текущий цвет.
Таблица 10.4. Методы класса TCanvas
Метод |
Описание |
procedure Arc (XI, Yl, Х2, Y2, ХЗ, Y3, Х4, Y4:Integer) ; |
Метод рисует сегмент эллипса. Эллипс определяется описывающим прямоугольником (X1.Y1)— (Х2, Y2); его размеры должны лежать в диапазоне от 2 до 32 767 точек. Начальная точка сегмента лежит на пересечении эллипса и луча, проведенного из его центра через точку (ХЗ, Y3). Конечная точка сегмента лежит на пересечении эллипса и луча, проведенного из его центра через точку (Х4, Y4). Сегмент рисуется против часовой стрелки |
procedure Chord (XI, Yl, X2, Y2, X3, Y3, X4, Y4: Integer) ; |
Рисует хорду и заливает отсекаемую ею часть эллипса. Эллипс, начальная и конечная точки определяются, как в методе Arc |
procedure Ellipse (XI, Yl, X2, Y2 : Integer); |
Рисует и закрашивает эллипс, вписанный в прямоугольник (Х1, Y1) - (Х2, Y2) |
procedure LineTo(X, Y: Integer) ; |
Проводит линию текущим пером из текущей точки в (X, Y) |
procedure MoveTo (X,Y: Integer); |
Перемещает текущее положение пера (свойство PenPos) в точку (X, Y) |
procedure BrushCopy (const Dest: TRect; Bitmap: TBitmap; const Source: TRect; Color: TColor) ; |
Производит специальное копирование. Прямоугольник Source из битовой карты Bitmap копируется в прямоугольник Dest на канве; при этом цвет Color заменяется на цвет текущей кисти (Brush. Color). С помощью этого метода можно нарисовать "прозрачную" картинку. Для этого нужно выбрать соответствующий фону цвет кисти и затем заменить на него фоновый или наиболее часто встречающийся цвет битовой карты (см. Bitmap. TransparentColor) |
procedure CopyRect (const Dest: TRect; Canvas: TCanvas; const Source: TRect ) ; |
Производит копирование прямоугольника Source из канвы Canvas в прямоугольник Dest в области самого объекта |
procedure FillRect (const Rect: TRect); |
Производит заливку прямоугольника (текущей кистью) |
procedure FrameRect (const Rect: TRect); |
Осуществляет рисование контура прямоугольника цветом текущей кисти (без заполнения) |
procedure Draw(X, Y: Integer; Graphic: Tgraphic) ; |
Осуществляет рисование графического объекта Graphic (точнее, вызов метода его рисования) в области с верхним левым углом (X, Y) |
procedure StretchDraw (const Rect: TRect; Graphic: TGraphic) ; |
Осуществляет рисование объекта Graphic в заданном прямоугольнике Rect. Если их размеры не совпадают, Graphic масштабируется |
procedure DrawFocusRect (const Rect: TRect); |
Производит отрисовку прямоугольной рамки из точек (как на элементе, имеющем фокус ввода). Поскольку метод использует логическую операцию ХОР (исключающее ИЛИ), повторный вызов для того же прямоугольника приводит изображение к начальному виду |
procedure FloodFill (X, Y: Integer; Color: TColor; FillStyle: Tf illStyle) ; TFillStyle = (fsSurface, fsBorder); |
Производит заливку области текущей кистью. Процесс начинается с точки (X, Y). Если режим FillStyle равен fsSurface, то он продолжается до тех пор, пока есть соседние точки с цветом Color. В режиме fsBorder закрашивание, наоборот, прекращается при выходе на границу с цветом Color |
procedure Pie (XI, Yl, X2, Y2, X3, Y3, X4, Y4: Integer); |
Рисует сектор эллипса, описываемого прямоугольником (Х1, Y1) — (Х2, Y2). Стороны сектора лежат на лучах, проходящих из центра эллипса через точки (ХЗ, Y3) и (Х4, Y4) |
procedure Polygon (const Points: array of TPoint); |
Строит многоугольник, используя массив координат точек Points. При этом последняя точка соединяется с первой и внутренняя область закрашивается |
procedure Polyline (const Points: array of TPoint); |
Строит ломаную линию, используя массив координат точек Points |
procedure PolyBezier (const Points: array of TPoint); |
Строит кривую Безье (кубический сплайн), используя массив координат точек Points |
procedure PolyBezierTo (const Points: array of TPoint); |
Строит кривую Безье (кубический сплайн), используя массив координат точек Points. Текущая точка используется в качестве первой |
procedure Rectangle (XI, Yl, X2, Y2: Integer); |
Рисует прямоугольник с верхним левым углом в (Х1, Y1) и нижним правым в (Х2, Y2) |
procedure RoundRect (XI, Yl, X2, Y2, X3, Y3: Integer) ; |
Рисует прямоугольник с закругленными углами. Координаты вершин — те же, что и в методе Rectangle. Закругления рисуются как сегменты эллипса с размерами осей по горизонтали и вертикали ХЗ и Y3 |
function TextHeight (const Text: string): Integer; |
Задает высоту строки Text в пикселах |
function TextWidth (const Text: string): Integer; |
Задает ширину строки Text в пикселах |
procedure TextOut (X, Y: Integer; const Text: string) ; |
Производит вывод строки Text. Левый верхний угол помещается в точку канвы (X, Y) |
procedure TextRect (Rect : TRect; X, Y: Integer; const Text: string); |
Производит вывод текста с отсечением. Как и в TextOut, строка Text выводится с позиции (X, Y); при этом часть текста, лежащая вне пределов прямоугольника Rect, отсекается и не будет видна |
Таблица 10.5. Свойства класса TCanvas
Свойство |
Описание |
property ClipRect: TRect; |
Определяет область отсечения канвы. То, что при рисовании попадает за пределы этого прямоугольника, не будет изображено. Свойство доступно только для чтения — его значение переустанавливается системой в контексте устройства, с которым связана канва |
property Per.Pos : TPoint; |
Содержит текущую позицию пера канвы (изменяется посредством метода MoveTo) |
Метод
procedure Refresh;
сбрасывает текущие шрифт, перо и кисть, заменяя их на стандартные, заимствованные из установок Windows (BLACK PEN, HOLLOW_BRUSH, SYSTEM_FONT).
Предусмотрено два события для пользовательской реакции на изменение канвы:
property OnChange: TNotifyEvent; property OnChanging: TNotifyEvent;
Эти события возникают при изменении свойств и вызове методов TCanvas, меняющих вид канвы (т. е. при любом рисовании. В методе MoveTo, например, они не возникают). Отличие их в том, что событие OnChanging вызывается до начала изменений, а событие OnChange — после их завершения.
Идентификатор (код) растровой операции при копировании прямоугольных блоков содержится в свойстве
property CopyMode: TCopyMode; TCopyMode = Longint;
и определяет правило сочетания пикселов, копируемых на канву, с ее текущим содержимым. При этом можно создавать разные изобразительные эффекты. В Delphi определены следующие константы кодов: cmBiackness, craDstlnvert, cmMergeCopy, cmMergePaint, cmNotSrcCopy, cmNotSrcErase, cmPatCopy, cmPatlnvert, cmPatPaint, cmSrcAnd, cmSrcCopy, cmSrcErase, cmSrdnvert, cmSrcPaint, cmWhiteness.
Все они стандартно определены в Windows, и подробное их описание можно найти в документации по GDI. Значением свойства CopyMode по умолчанию является cmSrcCopy — копирование пикселов источника поверх существующих.
Из возможностей, появившихся в классе TCanvas, следует отметить поддержку рисования кривых (полиномов) Безье. Эта возможность впервые
появилась в API Windows NT. Для построения одной кривой нужны минимум четыре точки — начальная, конечная и две опорные. По ним будет построена кривая второго порядка. Если задан массив точек, они используются для построения последовательных кривых, причем последняя точка одной кривой является первой для следующей кривой.
Хорошей иллюстрацией использования объекта TCanvas может служить пример GraphEx, поставляемый вместе с Delphi (папка \Demos\Doc\GraphEx). Есть только одно "но" — он приводится в неизменном виде, начиная с версии Delphi 1.0. Поэтому сделаем часть работы за программистов Borland. В нашем примере модернизированы Панели инструментов — они выполнены на компонентах TToolBar и TControlBar; добавлена поддержка файлов JPEG; и, наконец, добавлена возможность рисования кривых Безье. Обновленный внешний вид главной формы примера GraphEx показан на рис. 10.1.
Рис. 10.1. Так теперь выглядит главная форма примера GraphEx
Где же найти ту канву, на которой предстоит рисовать? Во-первых, ею снабжены все потомки классов TGraphicControl и TCustomControl, т. е. почти все визуальные компоненты из Палитры компонентов; в том числе и форма. Во-вторых, канву имеет растровая картинка (класс TBitmap); вы можете писать и рисовать не на пустом месте, а на готовом изображении (об этом см. ниже в разд. "Класс TBitmap" данной главы). Но иногда нужно рисовать и прямо на экране. В этом случае придется прибегнуть к использованию функций API. Функция Getoc возвращает контекст устройства заданного окна, если ей передается параметр 0 — то всего экрана:
ScreenCanvas := TCanvas.Create;
ScreenCanvas.Handle :=GetDC{0);
// Рисование на ScreenCanvas
ReleaseDC(0, ScreenCanvas.Handle);
ScreenCanvas.Free;
Пример необходимости рисования на экране — программы сохранения экрана (Screen savers).
Когда и где следует рисовать? Этот вопрос далеко не риторический, как может показаться с первого взгляда.
Помимо графических примитивов, таких как линии и фигуры, на канве можно разместить готовые изображения. Для их описания создан класс TGraphic.