Основы алгоритмизации и программирования - Учебное пособие (Струков В.М.)

8. графика

8.1. Общие положения

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

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

К первой группе средств можно отнести:

визуальные компоненты;

готовые графические элементы, созданные с помощью других инструментальных систем (например, графических редакторов Paint, PhotoShop и т.п.).

Ко второй группе средств отнесем инструментальные средства создания простейших графических объектов (примитивов), таких как линии, прямоугольники, окружности и т.п., и инструменты создания сложных графических объектов, таких как графики, диаграммы и т.п.

Для создания любого графического объекта всегда необходимы два средства: 1) на чем рисовать – поверхность рисования (далее будем называть его холстом или графическим контейнером) и 2) чем рисовать (инструменты рисования). В качестве графического контейнера используются компоненты, обладающие свойством Canvas. К таким компонентам относятся, к примеру, форма Form, графический образ Image и др. А, например, компонент Button этим свойством не обладает и, следовательно, он не может быть графическим контейнером.

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

Каждый графический контейнер в процессе рисования представляет собой прямоугольную матрицу графических точек – пикселей. Положение каждой точки на плоскости объекта-контейнера характеризуется двумя целыми числами - координатами Х (по горизонтали) и Y (по вертикали). Начало системы координат (0,0) располагается в левом верхнем углу графического контейнера. Таким образом, значения координат возрастают вниз и вправо от начала координат.

В качестве инструментов создания графических объектов используются: перо (Pen),  кисть (Brush)  и  шрифт (Font). Перо применяется для вычерчивания линий и границ геометрических фигур. Кистью заливают внутренность замкнутой геометрической фигуры, например, прямоугольника или окружности. Инструмент «шрифт» используется для вывода текстовых обозначений на поверхности рисования. Pen, Brush  и Font являються свойствами  объекта Canvas. Эти свойства, также как и Canvas, являются невизуальнымии свойствами и доступны только во время выполнения программы.  Вместе с тем, заметим, что не все графические контейнеры, обладающие свойством Canvas, обладают его подсвойствами Pen, Brush  и Font.

8.2. Перо.

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

Таблица 8.1. Свойства объекта Pen

Имя свойства

Назначение

Color

Цвет линии контура

Width

Толщина линии в пикселях

Style

Стиль линии (применяется только для линий толщиной в 1 пиксель)

Mode

Задает способ определения цвета линии

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

Таблица 8.2. Значения свойства Pen.Color

Цвет

Значение

Цвет

Значение

Черный

clBlack

Серебристый

clSilver

Каштановый

clMaroon

Красный

clRed

Зеленый

clGreen

Салатный

Clime

Оливковый

clOlive

Синий

clBlue

Темно-синий

clNavy

Бирюзовый

clAqua

Темно-розовый

clPurple

Розовый

clFuchsia

Серый

clGray

Белый

clWhite

Темно-зеленый

clTeal

 

 

Свойство Style определяет вид вычерчиваемой линии – непрерывная, штрих-пунктирная и т.п. Значения свойства приведены в таблице 8.3.

Таблица 8.3. Значения свойства Pen.Style

Значение свойства

Тип линии

psSolid

Сплошная линия

psDash

Пунктирные длинные штрихи

psDot

Пунктирные короткие штрихи

psDashDot

Пунктирная, чередование длинных и коротких штрихов

psDashDotDot

Пунктирная, чередование одного длинного и двух коротких штрихов

psClear

Линия не отображается

Значение psClear используется в тех случаях, когда необходимо нарисовать тело фигуры, а границу – не нужно.

Свойство Mode задает способ формирования цвета линии в зависимости от цвета точек холста, по которым она вычерчивается (цвета фона). По умолчанию линии вычерчиваются текущим цветом, который задается свойством Pen.Color. Однако, может возникнуть ситуация, когда цвет линии совпадает с цветом фона. Для того, чтобы исключить такую возможность, можно, например, задать такой режим рисования, при котором линия всегда рисуется цветом, инверсным по отношению к цвету фона. В таком случае, независимо от того, над какими участками будет проходить вычерчиваемая линия, она всегда будет видна (различима) на экране.

В таблице 8.4 приведены некоторые значения свойства Mode, которые наиболее часто используются на практике.

Таблица 8.4. Значения свойства Pen. Mode

Значение свойства

Цвет линии

pmBlack

Черный, не зависит от значения Pen.Color

pmWhite

Белый, не зависит от значения Pen.Color

pmCopy

Цвет линии определяется значением Pen.Color

pmNotCopy

Цвет линии является инверсным по отношению к значению Pen.Color

pmNot

Цвет линии является инверсным по отношению к цвету точки, через которую она проходит

pmMask

Общие цвета пера и фона

pmNotMask

Инверсия общих цветов пера и фона

8.3. Кисть.

Каждая плоская геометрическая фигура может быть нарисована одним из трех способов:

контурный рисунок (рисуется только контур фигуры);

бесконтурный рисунок (рисуется только внутренность фигуры – т.е., вся внутренняя полость фигуры окрашивается каким-либо цветом, отличным от фонового, а контур фигуры не рисуется);

полный рисунок (закрашивается внутренность фигуры и рисуется контур фигуры цветом, отличным от цвета фона и цвета заливки внутренности фигуры).

Кисть Brush применяется во втором и третьем случаях. Причем заливка фигуры может выполняться также одним из трех способов:

фигура заливается равномерно по всей площади каким-то одним цветом,

внутренность фигуры заштриховывается определенным образом (стилем, шаблоном) на фоне контейнера, 

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

Способ закрашивания внутренности фигуры называется стилем заливки.

Объект Brush обладает следующими основными свойствами:

Color – свойство типа TColor, определяет цвет, которым закрашивается или заштриховывается фигура;

Style – свойство типа TBrushStyle, определяет стиль заполнения фигуры;

BitMap – свойство типа TBitMap, содержит растровое изображение, которое используется кистью для заливки фигуры; если это свойство задано, то свойства Color и  Style игнорируются.

Возможные  значения  стиля закрашивания фигуры приведены в таблице 8.5.

Таблица 8.5. Значения стиля заливки Brush.Style

Значение свойства

Тип заливки

bsSolid

Сплошная заливка

bsClear

Фигура не заливается

bsHorizontal

Горизонтальная штриховка

bsVertical

Вертикальная штриховка

bsFDiagonal

Диагональная штриховка с наклоном линий вперед

bsBDiagonal

Диагональная штриховка с наклоном линий назад

bsCross

Горизонтально-вертикальная  штриховка в клетку

bsDiagCross

Диагональная штриховка в клетку

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

 

Для заливки фигуры рисунком из файла можно воспользоваться свойством Brush.BitMap. При этом нужно иметь в виду, что размеры рисунка и фигуры, которую он заливает, могут не совпадать. В качестве примера ниже приведен фрагмент программы, в котором прямоугольник заливается картинкой из файла:

 

Результатом выполнения этой подпрограммы будет окно, представленное на рисунке 8.2.

 8.4. Вычерчивание графических примитивов.

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

Для прорисовки графических примитивов применяются методы объекта Canvas. Рассмотрим некоторые из них.

Точка (Pixel).

Для прорисовки одной точки поверхности рисования используется свойство Pixels. Это двумерный массив типа TColor, с помощью которого можно задать цвет  любой точки поверхности рисования, т.е. “нарисовать» точку. Это свойство доступно для чтения и для записи.

Пример прорисовки точек:

.  .  .

Var   i,x,y:integer;

Begin

Randomize;

For i:=1 to 25 do

Begin

         X:= Random(Form1.ClientWidth);

         Y:= Random(Form1.ClientHeight);

         Form1.Canvas.Pixels[x,y]:=clWhite;

End;

Линия (LineTo).

Для вычерчивания линии в Delphi используется стандартная процедура LineTo, являющаяся методом объекта Canvas. Формат обращения к ней следующий:

<Графический контейнер>.Canvas.LineTo(<X>,<Y>);

Действие процедуры: вычерчивает прямую линию заданного типа от текущей точки до точки с координатами  <X,Y>. <X>,<Y> - целочисленные выражения. Если текущее положение начальной точки линии нас не устраивает, то для перехода в нужную точку используется процедура MoveTo. Формат обращения к ней следующий:

<Графический контейнер>.Canvas.MoveTo(<X>,<Y>);

Действие процедуры: текущая позиция устанавливается в точку с координатами <X>,<Y>.

Параметры вычерчиваемой линии (цвет, толщина и стиль) задаются свойствами Color, Width, Style, Mode объекта Pen.

Таким образом, для того чтобы нарисовать на форме прямую сплошную линию черным цветом и толщиной в два пикселя  от точки с координатами (20,50) до точки с координатами (100,150), нужно выполнить следующую последовательность операторов:

Form1.Canvas.Pen.Color:=ClBlack;

Form1.Canvas.Pen.Width:=2;

Form1.Canvas.Pen.Style:=psSolid;

Form1.Canvas.MoveTo(20,50);

Form1.Canvas.LineTo(100,150);

Отметим, что в Турбо Паскале имеется процедура Line, которая вычерчивает отрезок, заданный координатами начальной и конечной точек. В языке Object Pascal такая процедура отсутствует.

Прямоугольник (Rectangle).

В Delphi прямоугольник может вычерчиваться тремя способами:

1) вычерчивается только контур прямоугольника;

2) вычерчивается только закрашенная внутренность прямоугольника;

3) контур вычерчивается одним цветом, а внутренность закрашивается другим цветом и, кроме того, может заштриховываться  определенным  стилем.

Для вычерчивания обычного прямоугольника (с острыми углами) применяется стандартная процедура Rectangle. Формат обращения к ней следующий:

<Графический контейнер>.Canvas.Rectangle(<X1>,<Y1>,<X2>,<Y2>);

Действие процедуры: вычерчивает прямоугольник со сторонами, параллельными осям координат, размещение которого в контейнере задается координатами левого верхнего угла (<X1>,<Y1>) и правого нижнего  - (<X2>,<Y2>). Вид линии контура и стиль заполнения внутренней части прямоугольника определяется значениями свойств объектов Pen и Brush. По умолчанию контур рисуется сплошной тонкой линией черного цвета, а внутренность прямоугольника «прозрачна» (имеет цвет и стиль фона). Отметим, что внутренность прямоугольника, кроме стандартных стилей штриховки, может заливаться рисунком из графического файла. Примеры программы и ее реализации приведены выше на рисунках 8.1 и 8.2.

В Delphi имеется также процедура, которая вычерчивает прямоугольник со скругленными углами – RoundRect, обращение к которой имеет следующий формат:

<Графический контейнер>.Canvas.RoundRect(<X1>,<Y1>,<X2>,<Y2>,<X3>,<Y3>);

Здесь параметры <X1>,<Y1>,<X2>,<Y2>  имеют тот же смысл, что и в предыдущей процедуре, а параметры <X3>,<Y3> - это размеры прямоугольника, описывающего эллипс, одна четверть которого используется для вычерчивания скругленного угла:

В Delphi имеются еще две процедуры, которые вычерчивают прямоугольник – FillRect (вычерчивает закрашенный прямоугольник, в котором контур закрашивается тем же цветом, что и внутренность) и FrameRect (вычерчивает только контур прямоугольника).

Окружность и эллипс (Ellipse).

В Delphi, в отличие от Турбо Паскаля, для вычерчивания окружности и эллипса применяется одна и та же процедура – Ellipse. Формат обращения к ней имеет следующий вид:

<Графический контейнер>.Canvas.Ellipse(<X1>,<Y1>,<X2>,<Y2>);

где  <X1>,<Y1>,<X2>,<Y2>  - координаты верхнего левого и правого нижнего углов прямоугольника, внутри которого вычерчивается эллипс или окружность (если прямоугольник является квадратом).

Вид линии контура и стиль заполнения внутренней части прямоугольника определяется значениями свойств объектов Pen и Brush. По умолчанию контур рисуется сплошной тонкой линией черного цвета, а внутренность эллипса «прозрачна».

Пример:

Form1.Canvas.Ellipse(100,80,300,180);

8.5. Вывод текста.

Для вывода текстовых сообщений, сопровождающих элементы графики на форме приложения, в Delphi используется процедура TextOut, обращение к которой имеет следующий формат:

<Графический контейнер>.Canvas. TextOut (<X>,<Y>,<Текст>);

Здесь <X>,<Y> - координаты левого верхнего угла воображаемого прямоугольника, который описывает выводимое текстовое сообщение. Параметры шрифта текста определяются значением свойства Font. Ниже в таблице 8.6 приведены подсвойства свойства Font, которые используются процедурой TextOut.

Таблица 8.6.

Имя свойства

Назначение

Name

Название используемого шрифта, например, Arial Cyr

Size

Размер шрифта в пунктах

Style

Стиль начертания символов, который может быть нормальным (fsNormal), полужирным (fsBold), подчеркнутым (fsUnderline), курсивным (fsItalic), перечеркнутым (fsStrikeOut). Значением свойства Style является в общем случае множество, что позволяет сочетать различные стили, например:

Form1.Canvas.Font.Style:=[fsBold,fsItalic];

Color

Задает цвет символов

 

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

Ниже  приведен пример, в котором на форму выводится текстовое сообщение шрифтом Times New Roman, полужирным курсивом, символами черного цвета:

With Form1.Canvas do

Begin

         Font.Name:='Times New Roman';

         Font.Size:=14;

         Font.Style:=[fsItalic,fsBold];

         Font.Color:=clBlack;

         Brush.Color:=Form1.Color;

         TextOut(10,10,'Text!');

end;

8.6. Комплексный пример.

Рассмотрим подробно пример, в котором используются многие из описанных в предыдущих параграфах данной главы объектов и их свойств. Создадим программу, которая рисует график произвольной функции на поверхности формы. В качестве примера приводится график функции sin(x)/(2*x+1).

Текст программы приведен ниже:

{1} unit Grfunk;

{2} interface

{3} uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

{4} type

TForm1 = class(TForm)

Button1: TButton;

procedure Start;

procedure Button1Click(Sender: TObject);

{5} private

{ Private declarations }

{6} public

{ Public declarations }

{7}end;

{8} var Form1: TForm1;

{9} implementation

{$R *.dfm}

{10} procedure GrafFunc;

{11} var  XStart,XFin:real;

{12}  ymin,ymax:real;

{13}  x,y:real;

{14}  dx:real;

{15}  left,bott:integer;

{16}  widt,heigh:integer;

{17}  kx,ky:real;

{18}  x0,y0:integer;

{19}  Function f(x:real):real;

{20}  begin

{21}  f:=1/(2*x+1)*sin(x);

{22}  end;

{23} begin

   // Формирование области вывода графика

{24}  left:=10;

{25}  bott:=Form1.ClientHeight-30;

{26}  heigh:=Form1.ClientHeight-50;

{27}  widt:=Form1.ClientWidth-30;

{28}  XStart:=0;

{29}  XFin:=25;

{30}  dx:=0.01

{ Поиск максимального и минимального значений функции

  для масштабирования: kx,ky – коэффициенты масштаба }

{31}  ymin:=f(XStart);

{32}  ymax:=f(XStart);

{33}  x:=XStart;

{34}  repeat

{35}  y:=f(x);

{36}  if y<ymin then ymin:=y;

{37}  if y>ymax then ymax:=y;

{38}  x:=x+dx;

{39}  until (x>=XFin);

{40}  ky:=heigh/abs(ymax-ymin);

{41}  kx:=widt/abs(XFin-XStart);

// Построение осей координат

{42}  x0:=left;

{43}  y0:=bott-Abs(Round(ymin*ky));

{44}  with form1.Canvas do

{45}  begin

{46}  MoveTo(left,bott); LineTo(left,bott-heigh);

{47}  MoveTo(x0,y0); LineTo(x0+widt,y0);

{48}  TextOut(left+5,bott-heigh,FloatToStrF(ymax,ffGeneral,4,0));

{49}  TextOut(left+5,bott,FloatToStrF(ymin,ffGeneral,4,0));

// Построение графика

{50}  x:=XStart;

{51}  repeat

{52}  y:=f(x);

{53}  Form1.Canvas.Pixels[x0+Round(x*kx),y0-Round(y*ky)]:=clBlack;

{54}  x:=x+dx;

{55}  until (x>XFin);

{56} end;

{57} end;

{58} procedure TForm1.Start;

{59} begin

{60}  GrafFunc;

{61} end;

{62} procedure TForm1.Button1Click(Sender: TObject);

{63} begin

{64}  Button1.Visible:=false;

{65}  Form1.Start;

{66} end;

{67} end.

 

В строках 24-30 формируется область вывода графика – отступы слева, справа, сверху и снизу от края формы. Область вычерчивания графика формируется таким образом, что график заполняет всю область, независимо от стартового размера формы (для этой цели используются свойства формы ClientHeight и  ClientWidth).

В строках 31-41 вычисляются коэффициенты масштабирования по вертикали и по горизонтали – ky и  kx, которые впоследствии используются для того, чтобы график заполнял всю область вывода, независимо от максимальных и минимальных значений функции и размера отрезка [XStart, XFin], на котором строится график. При этом следует иметь в виду, что в силу такого масштабирования исходная картинка графика искажается – сжимается или растягивается по горизонтали и по вертикали.

Операторы в строках 42-49 строят простейшие (без стрелок) оси координат. Здесь функция преобразования FloatToStrF используется для ограничения количества выводимых цифр в отображаемых максимальном и минимальном значениях функции.

Операторы в строках 50-56 непосредственно строят график заданной функции. Отметим, что программа имеет возможность построить график практически произвольной функции, для чего в строке 21 необходимо вписать формулу нужной функции.

Результат работы программы:

8.7. Использование готовых рисунков из файлов.

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