Отображение графической информации

Если вы в душе немного художник, то у вас наверняка появилось чувство, что в мире Delphi все выглядит как в казино. Кнопки, окна, метки – все это здорово и выглядит красиво, но несколько стандартно. А если захочется нарисовать что-то свое, оригинальное, построить график или вывести на экран собственный портрет или репродукцию картины Рафаэля? К счастью, Delphi поможет вам и в этом! В ней имеется богатейший набор средств решения как перечисленных, так и множество других задач. После прочтения этой главы вы научитесь с ними работать и решение любой графической проблемы станет не только простым, но и достаточно интересным делом.

Два способа вывода графической информации

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

Существует два способа вывода графической информации:

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

Создание и отображение картинок

Из предыдущих глав вы уже знаете, что разместить на форме готовую картинку можно с помощью компонента Image. Поэтому позволим себе воздержаться от повтора и рассмотрим проблему создания картинки для компонента lmage. Специально для создания картинок разработчики фирмы Borland включили в состав Delphi небольшой, но достаточно мощный графический редактор Image Editor (если он для вас слабоват, купите Adode Photoshop).

Основное назначение Image Editor – создание и редактирование несложных точечных рисунков. Мы рекомендуем его как профессионалам, так и новичкам. Графический редактор Image Editor запускается из среды Delphi по команде меню Tools I Image Editor. Выполните эту команду и через несколько секунд на экране появится следующее окно редактора (рис.9.1).

Теперь откройте выпадающее меню File I New(рис. 9. 2.)

Как видите, Image Editor позволяет создавать не только точечные рисунки (bitmap), но и значки (icon) , и курсоры (cursor), причем один проект может состоять из нескольких картинок различного формата(для создания таких проектов служат два первых пункта выпадающего меню New…) Пока нас интересует создание точечного рисунка, поэтому выберите пункт меню Bitmap file (. Bmp). В ответ Image Editor попросит вас создать размеры изображения в пикселах необходимым цветом (рис. 9.3.)

Размеры должны быть уже задуманы, поэтому смело установите нужные вам параметры картинки и щелкните на кнопке ОК. Окно Bitmar Properties закроется и вы увидите окно редактора картинки (рис. 9.4).

Image Editor имеет интуитивно понятный интерфейс. Вы быстро найдете там "холст", "кисть" и "краски", поэтому не будем тратить время на скучное описание управляющих элементов окон и команд меню, изучите рисунок и все станет понятно. Для тренировки попробуйте что-нибудь нарисовать. Когда рисунок готов, сохраните его в файле с помощью команды меню File | Save.

Теперь переключитесь на среду Delphi и установите только что созданную картинку в компоненте Image. Напомним, что для этого надо установить значение свойства Picture (рис.9.5) 

Специфика отображения картинки регулируется свойствами компонента Image.

Отображение геометрических фигур

Наш рисунок довольно сложный, совсем не обязательно рисовать целую картину, чтобы показать простую геометрическую фигуру, например прямоугольник, эллипс и т.п. Намного проще и лучше воспользоваться компонентом Shape. Он находится в Палитре Компонентов рядом с компонентом Image (рис.9.6 ).

Таблица 9.1. Важнейшие свойства компонента Shape

Свойство

Описание

Brush

Pen

Shape

Цвет и штриховка для заполнения фигуры.

Цвет линий и способ вывода фигуры.

Вид геометрической фигуры

Вид геометрической фигуры задается свойством Shape , заполнение ее внутреннего пространства - составным свойством Brush, а отрисовка внешних границ - составным свойством Pen . Эти свойства стоят нескольких замечаний.

Перебирая значения свойства Shape, вы получите все виды геометрических фигур, поддерживаемые компонентом Shape (рис.9.7.) :

Метод заполнения внутреннего пространства фигуры определяется значением свойства Drush.Style. Если оно равно dsSolid, то фигура заливается цветом, заданным в свойстве Brush.Color. Если стиль кисти равен dsClear, то фигура рисуется прозрачной. Остальные значения стиля задают всевозможные варианты штриховки внутренней области. Цвет штриховочнфых линий определяется значением свойства Brush.Color = clWhite ( рис.9.8)

Цвет граничной линии содержится в свойстве Pen.Color, а ее толщина – в свойстве Pen.Width. Если толщина равна 1, то изменив значение свойства Pen. Style, можно выбрать другой тип линии. Следующий рисунок демонстрирует всевозможные типы линий (стили пера), принимая цвет пера черным (Pen.Color = clBlack) (рис.9.9)

Исследуя составное свойство Pen, вы обнаружите еще один очень важный параметр – Mode. Это режим наложения графической фигуры на экран или другую поверхность отображения. Отметим, что режим наложения действует не только на контур фигуры, но также на ее внутреннюю область, контролируемую кистью. Возможные значения свойства Mode описаны в таблице 9.2.

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

Значение

Описание

PmBlack

PmWhite

PmNop

PmNot

PmCopy

PmNotCopy

PmMask

PmMaskPenNot

PmMaskNotPen

PmNotMask

PmMerge

PmMergePenPenNot

PmMergeNotPen

PmNotMegre

PmXor

PmNotXor

Результирующий пиксел всегда черный.

Результирующий пиксел всегда белый.

FinalColor : =ScreenColor

FinalColor : = njt ScreenColor

FinalColor : = PenColor

EinalColor : = not PenColor

FinalColor : = PenColor and ScreenColor

FinalColor : = PenColor and not ScreenColor

FinalColor : = not PenColor and ScreenColor

FinalColor : = not(PenColor and ScreenColor)

FinalColor : = PenColor or ScreenColor

FinalColor : = PenColor or not ScreenColor

FinalColor : = not PenColor or ScreenColor

FinalColor : = not (PenColor or ScreenColor)

FinalColor : = PenColor xor ScreenColor

FinalColor : = not(PenColor xor ScreenColor)

Поясним используемые в таблице имена : FinalPixel означает цвет результирующего пиксела; PenColor – цвет пера; ScreenColor – цвет фона.

Различные режимы наложения позволяют создавать очень интересные эффекты при выводе графических фигур. Взгляните на приведенный ниже рисунок – такое впечатление, будто на картинку попал солнечный “ зайчик”. Вас интересует, как получить такой результат? Поместите в форму компонент lmage и загрузите в него картинку из файла Delphi 2.0\ Images\Splash\16color\Chip.bmp. Сверху картинки поместите компонент Shape и установите в нем следующие свойства

Brush.Color = clSilver

Brush.Style = dsSolid

Pen.Mode = pmMergeNotPen

Pen.Style = psCleer

Shape = stCircle 

Внимание! Получаемый результат зависит от глубины цвета в графическом адаптере (количество бит видеопамяти, приходящегося на одну точку экрана)апример, данный рисунок получен в режиме 256 цветов – 8 бит на одну точку.

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

Формирование изображений программным способом

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

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

Стратегия управления экраном дисплея в Windows отличается от традиционной стратегии, принятой в DOS-приложение распоряжается экраном монопольно и полностью отвечает за то, что на нем изображено. В противоположность ему Windows-приложение вынуждено делить экран дисплея с другими приложениями. Совместное использование экрана обеспечивают прямоугольные окна, в которых отображаются формы. Можете представить окно как проекцию объемной формы на плоский экран.

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

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

В те моменты времени, когда загруженность операционной системы снижается, у каждого окна проверяется область обновления. Если область обновления некоторого окна оказывается непустой , то его владельцу – приложению – посылается сообщение с требованием перерисовать содержимое окна. Приложение передает сообщение соответствующей форме. Форма восстанавливает утраченные части своего изображения собственными средствами. С точки зрения формы сообщение о перерисовке – это системное событие, а формирование изображения – это реакция на него. Явление событийного формирования изображения называется отображением (painting). Этот термин не следует путать с термином рисование (drawing), подразумевающим любой вывод графических примитивов.

Отображение формы выполняется следующим образом. Сначала рисуются системные части формы (заголовок, рамка и т.д.) . Это делается без участия программиста. Затем рисуются рабочая область формы, которая служит фоном для управляющих элементов. По умолчанию она заливается цветом, указанным в значении свойства Color . Наконец, по форме отображаются управляющие элементы. Они, как и форма, рисуют себя сами. Программист имеет возможность определить свой стиль рисования рабочей области формы. Это делается в обработчике событий OnPaint. Интересно что рисуя на рабочей области формы, вы рисуете как бы под управляющими элементами, которые на ней находятся. Иначе говоря, программное рисование не исключает использования готовых управляющих элементов Delphi.

Понятие холста

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

 

Pen – объект для рисования линий и границ геометрических фигур;

Brush – объект для заполнения фигур ;

Font – объект для вывода текста ;

PenPos – объект для хранения текущей позиции рисования ;

Pixels[X, Y : Integer] – массив для записи и считывания пикселов холста.

Первые три свойства представляют собой объекты, известные как инструменты для рисования. Сами по себе эти объекты не умеют рисовать, но зато они хранят в своих свойствах все необходимые холсту параметры. Структура объектов Pen и Brush вам знакома по одноименным свойствам компонента Shape, а структура объекта Font – по одноименному свойству формы.

Холст поддерживает такое понятие как текущая позиция рисования. Текущая позиция хранится в свойстве PenPos и используется при рисовании прямых (прямая рисуется от текущей позиции до заданной). Выражение PenPos.X возвращает горизонтальную позицию, а PenPos.Y – вертикальную.

Благодаря свойству Pixels холст интерпретируется как двумерная матрица пикселов. Элемент, стоящий на пересечении столбца X и строки Y матрицы Pixels, кодирует цвет пиксела. Координатная система объекта Canvas выбрана таким образом, что левый верхний пиксел изображения имеет координаты [ 0, 0 ], ось Х направлена вправо, а ось Y – вниз.

Шаг 1. Вывод графических примитивов выполняется с помощью методов объекта Canvas. Для их практического изучения вам понадобится новый проект, поэтому выполните команду меню File | New Application. На экране появится чистая форма.

Шаг 2. Активизируйте в Инспекторе Объектов страницу Events и отыщите на ней событие OnPaint . Сделайте двойной щелчок мышм в поле зрения. В результате откроется Редактор Кода с заготовкой обработчика события. В этом обработчике вы будете проверять работу изучаемых методов.

Procedure TForm1 . FormPaint (Sender : Tobject);

begin

{Здесь выполняется рисование }

end ;

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

Рисование прямых, ломаных и кривых линий

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

MoveTo(X, Y: Integer) – перемещает указатель текущей позиции в заданную точку.

Внимание! Этот метод должен использоваться вместо явной перезаписи свойства PenPos.

LineTo(X, Y : Integer) – рисует прямую линию от текущей позиции рисования (PenPos.X, PenPos.Y) до заданной ( X, Y) и перемещает указатель текущей позиции в точку с координатами ( X, Y).

Polyline(Points: array of Tpoint) – рисует ломаную линию, соединяя точки массива Points. Для получения элемента массива по двум координатам может использоваться функция Point(X, Y : Integer): Tpoint.

Arc(X1, Y1, X2, Y2, X3, Y3, X4, Y4 : Integer) – рисует дугу эллипса, вписанного в прямоугольник с координатами (X1, Y1) и ( X2, Y2) . Дуга определяется двумя радиусами эллипса, приходящимися через точки (X3, Y3) и (X4, Y4) . Дуга рисуется против часовой стрелки от точки пересечения эллипса с первым радиусом до точки пересечения со вторым радиусом. Смысл параметров поясняется ( рис. 9.10)

Сhord (X1, Y1, X2, Y2, X3, Y3, X4, Y4 : Integer) – рисует хорду эллипса, вписанного в прямоугольник с координатами (X1,Y1) и (X2, Y2) Хорда лежит на прямой, проходящей через точки (X3, Y3) и (X4, Y4). Смысл параметров поясняется (рис. 9.11)

Шаг 3. Давайте выберем какой-нибудь метод и попробуем что-нибудь нарисовать. Например, с помощью метода Poleline можно легко нарисовать контур треугольника (сматалог / Chap9/ Drawing/ Stepl на компакт-диске ) .

Procedure Tform1. FormPaint (Sender : Tobject);

begin

with Canvas do

begin

(Использовать пунктирную линию)

Pen.Style : = psDot;

(использовать цвет формы для фона)

Brush.Color : = Color ;

(Нарисовать треугольник)

Polyline ([Point (20,100), Point (100, 20), Point(180, 100), Point(20, 100)]);

end ;

end;

  Рисование геометрических фигур

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

Rectangle (X1,Y1,X2,Y2: Integer) – рисует прямоугольник с левым верхним углом в точке (X1,Y1) и нижним правым углом в точке (X2,Y2). Прямоугольник рисуется текеущими атрибутами кисти и пера.

RoundRect (X1,Y1,X2,Y2,X3,Y3: Integer) – рисует прямоугольник с закругленными углами. Углы рисуются как четверти эллипса с шириной X3 и высотой Y3. Смысл параметров поясняет рисунок (рис. 9.12)

Ellipse (X1,Y1,X2,Y2, : Integer) – рисует эллипс, вписанный в прямоугольник с левым верхним углом в точке (X1,Y1) и нижним правым углом в точке (X2,Y2). Прямоугольник рисуется текущими пером и кистью. Смысл параметров поясняет рисунок (рис. 9.13)

Polygon (Points: array of Tpoint) – рисует ломаную линию, соединяя точки массива Points. Ломаная замыкается отрезком из последней точки в первую, и полученная фигура заполняется текущей кистью.

Pie (X1,Y1,X2,Y2,X3,Y3,X4,Y4 : Integer) – рисует сектор эллипса, вписанного в прямоугольник с координатами (X1,Y1) и (X2,Y2). Сектор определяется двумя радиусами эллипса, проходящими через точки (X3,Y3) и (X4,Y4). Смысл параметров поясняет рисунок (рис. 9.14)

Шаг 4. Давайте нарисуем какую-нибудь геометрическую фигуру. Ради интереса усложним пример, потребовав, чтобы размеры фигуры были пропорциональны размерам формы. Пусть это будет эллипс, вписанный в рабочую область формы (см. каталог Chap9/Drawing/Step2 на компакт-диске .

Procedure Tform1. FormPaint (Sender : Tobject) ;

begin

with Canvas do

begin

(Использовать очень толстое перо)

Pen. Width : = 10 ;

(Уменьшить фигуру, чтобы она уложилась в форму)

Pen. Style : = psInsideFrame ;

(Нарисовать эллипс)

Ellihse (0, 0, ClientWidth, ClientHeight) ;

end ;

end;

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

В чем же дело? Оказывается, для ускорения графического вывода Windows оптимизирует перерисовку, выполняя отсечение. В результате отсечения на экране отображаются лишь те области формы, которые не были видны до перерисовки. Рисование за границами области отсечения игнорируется. Это, кстати говоря, очень хорошо. Представьте, что происходило бы на экране, если бы все содержимое формы перерисовывалось при любом, даже незначительном изменении ее видимой области. На экран было бы просто неприятно смотреть!

Шаг 5. Указанная оптимизация имеет побочный эффект при отрисовке изображений, размеры которых рассчитываются из размеров формы. Этот эффект вы как раз и наблюдали на рисунке выше. Чтобы его преодолеть, необходирмо определить в форме обработчик события OnResize, поместив в него вызов метода Invalidate :

Procedure Tform1. FormResize (Sender : Tobject) ;

begin

Inbalidate;

end ;

МетодInvalidate помечает всю рабочую область формы как подлежащую обновлению. После его вызова форма не будет перерисована сразу. Перерисовка произойдет только при очередном событии OnPaint. Если необходимо перерисовать форму немедлено, то вызов Invalidate следует заменить на вызов метода Refresh.

Заполнение внутреннего пространства фигур

Для заполнения внутреннего пространства фигур используются следующие методы объекта Canvas :

FillRect(const Rect: Trect) – заполняет прямоугольник, используя текущую кисть. Для получения прямоугольника по его координатам может использоваться функция Rect(X1,Y,X2,Y2 : Integer) : Trect).

FloodFill (X,Y : Integer ; Color: Tcolor; FillStyle: TfillStyle) – заливает область экрана, используя атрибуты кисти. Заливка начинается в точке (X, Y) и продолжается во всех направлениях до достижения цветовой границы. Способ заполнения области определяется параметром FillStyle. Если параметр FillStyle равен fsBorder, заливка заполняется до тех пор, пока не обнаружится граница с цветом, указанным в параметре Color. Если же параметр FillStyle равен fsSurface, заливка выполняется, пока не обнаруживается цвет, указанный в параметре Color.

Шаг 6. Давайте, например, воспользуемся функцией FillRect для создания плавного перехода от желтого цвета к черному.

Procedure TForm1. FormPaint (Sender : Tobject);

var

I : Integer ;

C : Byte ;

begin

for I : = 0 to ClientHeight - 1 do

begin

C : = 255 - Round (255 / ClientHeight * I) ;

Canvas. Brush. Color : = RGB (C, C, 0) ;

Canvas. FillRect (Rect( 0, I, ClientWidth, I + 1)) ;

end ;

end;

Заливка рабочей области происходит по строкам. За одну итерацию цикла заливается строка высотой в один пиксел. Цвет строки формируется функцией RGB, которая возвращает значение цвета по интенсивности трех его составляющих: красной, зеленой и синей. Интенсивность каждой составляющей цвета кодируется байтом и изменяется в диапазоне от 0 до 255. В примере выше красная и зеленая составляющие сначала равны 255 и уменьшаются по мере заливки строк до значения 0. Синяя составляющая отсутствует в результирующем цвете (имеет нулевую интенсивность).

Заменив в примпере выражение RGB (C, C, 0 ) на RGB ( 0, 0, C) вы получите красивый переход от синего цвета к черному в стиле инсталляторов фирмы Microsoft. Заметим, что качество перехода зависит от каличества используемых цветов и разрешающей способности видеоадаптера.

Вывод текста программным способом

Для вывода текста служат следующие методы объекта Canvas :

TextOut (X, Y: Integer; const Text : string) - выводит текущим шрифтом строку текста

Text в прямоугольнике с левым верхним углом в точке (X, Y).

TextRect(Rect: Trect; X, Y : Integer; const Text: string) - выводит текст в прямоугольнике Rect. Вывод за границы прямоугольника отсекается. См. метод TextOut.

TextHeight(const Text: string): Integer - возвращает высоту (в пикселах) строки Text при выводе ее текущим шрифтом.

TextWidth(const Text: string): Integer - возвращает ширину (в пикселах) строки Text при выводе ее текущим шрифтом.

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

Вывод картинок программным способом

Вывод картинок программным способом используется в тех случаях, когда компонент Image по каким-либо причинам неприменим. Методы объекта Canvas позволяют отображать картинки самых разных графических форматов : точечный рисунок (bitmap), значок (icon), метафайл (metafile). Вот эти методы:

Draw(X, Y: Integer; Graphic: TGraphic) - выводит картинку Graphic в точке (X, Y),

Tgraphic - это абстрактный базовый класс для классов Tbitmap, Tlcon, Tmetafile, реализующих картинки конкретных форматов (смправку по среде Delphi)

StretchDraw(const Rect; Trect; Graphic: Tgraphic) - выводит картинку Graphicб масштабируя ее до прямоугольника Rect.

CopyRect(Dest: Trect; Canvas: Tcanvas; Source: TRect) - копирует прямоугольную область Source с холста Canvas . Результирующая картинка масштабируется до прямоугольника Dest.

Способ комбинации точек исходной картинки с точками холста определяется свойством холста CopyMode. Возможные значения этого свойства приведены в следующей таблице (смабл. 9.3) :

Таблтца 9.3. Значение свойства CopyMode

Значение

Описание

CmBlackness

CmWhiteness

CmSrcCopy

CmSrcPaint

CmSrcAnd

CmSrclnvert

CmSrcErase

CmNotSrcCopy

CmNotSrcErase

CmDstlnvert

CmMergePaint

CmMergeCopy

CmPatCopy

CmPatPaint

CmPatlnvert

Все результирующее изображение черное

Все результирующее изображение белое

FinalPixel := SrcPixel

FinalPixel := SrcPixel or DestPixel

FinalPixel := SrcPixel and DestPixel

FinalPixel := SrcPixel xor DestPixel

FinalPixel := SrcPixel and ( not DestPixel)

FinalPixel := not SrcPixel

FinalPixel := not (SrcPixel or DestPixel)

FinalPixel := not DestPixel

FinalPixel := (not (SrcPixel) or DestPixel

FinalPixel := BrushPixel) and SrcPixel

FinalPixel := BrushPixel

FinalPixel := BrushPixel or (not SrcPixel) or DestPixel

FinalPixel := BrushPixel xor DestPixel

Поясним используемые в таблице имена: FinalPixtl означает цвет результирующего пиксела; SrePixel – цвет пиксела копируемой картинки; DestPixel – цвет исходного пиксела полотна; BrushPixel – цвет кисти полотна.

Шаг 7. В качестве примера работы с картинками рассмотрим вывод точечного рисунка, хранящегося в файле с именем с: \Windows\Forest.dmp. Программу построим следующим образом. В классе формы определим объект картинки :

type

Tform1 = class (TForm)

. . .

private

Picture : Tpicture ;

end ;

Объект класса Tpicture удобен тем, что может содержать картинку любого формата : точечный рисунок, значок, метафайл.

Шаг 8. При создании формы, т.е. по событию формы OnCreate, сконструируем объект Picture и загрузим в него точечный рисунок :

procedure TForm1 . FormCreate (Sender : TObject) ;

begin

Picture : = Tpicture . Create;

Picture . LoadFromFile (‘ C : \ Windows\Forest . dmb’) ;

end ;

Загрузку картинки выполняет метод объекта LoadFromFile, который сам определяет ее формат.

Шаг 9. По событию OnPaint выведем картинку с помощью метода Draw. Однако объект Picture – это не сама картинка, а только ее контейнер, приспособленный для работы с картинками различных форматов. Доступ к графической информации объекта Picture обеспечивает свойство Graphic :

procedure TForm1 . FormPaint (Sender : TObject) ;

begin

Canvas . Draw ( 0, 0, Picture. Graphic) ;

end ;

Шаг 10. При закрытии формы разрушим объект картинки :

procedure TForm1 . FormDestroy (Sender : TObject) ;

begin

Picture . Free ;

end ;

Определив форму и ее обработчики так, как указано выше, выполните компиляцию проекта и запустите приложение (сматалог \Chap9\Drawing\Step4 на компакт-диске). Результат будет следующим . 

Рисование в ограниченном прямоугольнике

На практике бывает необходимо рисовать не на всей форме, а в ограниченном прямоугольнике. Для этого применяется компонент PaintBox, который находится в Палитре Компонентов на странице System (рис.9.15)

Компонент PaintBox генерирует событие OnPaint, в ответ на которое вы можете рисовать в его области все, что угодно. Например, давайте рассмотрим рисование “звездного неба”.

Шаг 1. Начинайте новый проект и сделайте новую форму окном диалога. Для этого установите свойство формы BorderStyle в значение dsDialog.

Шаг 2. Поместите в нижней части формы кнопку типа BitBtn и установите ему следующий обработчик события OnPaint :

procedure TForm1 . PaintBox1Paint (Sender : TObject) ;

var

I : Integer ;

begin

with PaintBox1 do

begin

( Использовать темно-синюю кисть для фона )

Canvas . Brush . Color : = c1Navy ;

( Заполнить фон)

Canvas. FillRect (Rect ( 0, 0, Width, Heiight));

(Нарисовать 200 точек в случайных местах)

for I : = to 200 do

Canvas . Pixels [ Random (Width) , Random (Height)] : = cIWhite;

end ;

end;

После компиляции и запуска проекта вы получите форму, изображенную на рисунке (сматалог \Chap9\Drawing\Step5 на компакт-диске) .

Непосредственный доступ к графической системе WINDOWS

Графические классы Delphi основаны на мощной аппаратно-независимой графической системе Windows, называемой GDI (Graphics Device Interface). Интерфейс графической системы очень сложный и к тому же процедурно-ориентированный. Вполне понятно, что он не мог быть предложен в качестве графического интерфейса такой простой и концептуально выверенной среды как Delphi . Поэтому в библиотеку компонентов была включена специальная иерархия графических классов. Классы Delphi избавляют программистов от непродуктивных потерь времени на управление ресурсами графической системы и позволяют сконцентрироваться на прикладной стороне поставленной задачи. Однако, как всегда бывает, за дополнительные удобства нужно платить. Плата состоит в отсутствии некоторых возможностей, без которых отдельные задачи очень сложно программируются

Разработчики Delphi поступили дальновидно, предоставив программисту возможность комбинировать объекты библиотеки компонентов с процедурами и функциями графической системы Windows . Для доступа к графической системе все графические объекты имеют целочисленное свойство Handle . Свойство Handle содержит дескриптор системного объекта Windows, связанного с графическим объектом Delphi. Зная дескриптор, вы можете вызывать программы графической системы Windows наряду с методами объекта. Заметим, что в большинстве случаев это не нужно и даже вредно, поскольку снижает мобильность программы (возможность простого переноса на другие платформы, в частности из 16-разрядной Windows 3,1 в 32-разрядную Windows 95 или Windows NT). И все-таки есть круг вопросов, оставленный без внимания разработчиками библиотеки компонентов :

Уважаемый читатель, если вы не первый год программируете в Windows , то тематика этих вопросов вам хорошо известна. Если же вы новичок, лучше отложите изучение графической системы Windows до того времени, пока необходимость в более глубоких знаниях не станет насущной.

Отображение диаграмм

Проектирование диаграммы

При программировании бизнес-приложений часто приходится иметь дело с различными диаграммами. Диаграммы стали настолько распространенным средством представления информации, что компания Borland решила включить в состав Delphi несколько специальных компонентов, облекчающих их построение. Наиболее мощным из них является ChartFX, он присутсвует во всех редакциях Delphi , поэтому его мы и рассмотрим. Компонент ChartFX находится в Палитре Компонентов на странице ОСХ (рис.9.16).

Для тех, кто не знает , что такое ОСХ, дадим несколько пояснений. Расширение ОСХ (от анг. JLE Custom Control Extension – управляющие элементы OLE) носят файлы, в которых содержатся ОСХ – компоненты, - управляющие элементы пользовательского интерфейса, взаимодействующие с приложением по протоколу OLE. Разработанная фирмой Microsoft технология ОСХ –компонентов позволяет создавать независимые от среды программирования компоненты, которые могут многократно использоваться многими приложениями. Она призвана заменить технологию VBX –компонентов, ставшую непригодной с переходом в мир 32-разрядных приложений (VBX –компоненты поддерживались в Delphi 1.0). Delphi 2.0 полностью поддерживает ОСХ – компоненты, пример тому – компонент ChartFX (по сути это слегка доработанный VBX – компонент, который присутствует еще в Delphi 1.0).

Шаг 1. Для изучения компонента ChartFX начинайте новое приложение и установите свойства формы : выпишите заголовок Chart и сделайте форму в полтора раза больше.

Поместите компонент ChartFX в левый верхний угол формы и растяните его на всю рабочую область формы (рис.9.17).

Ба! Да это же настоящий мастер диаграмм. Больше не будем добавлять на форму новых компонентов, поскольку ChartFX отсутствует. Программная настройка размеров требует перехвата события формы OnResize :

procedure TForm1 . FormResize (Sender : Tobject) ;

begin

ChartFX1 . Width : = ClientWidth ;

ChartFX1 . Height : = ClientHeight ;

end ;

Даже при беглом взгляде на свойства компонента ChartFX понятно, что подобрать с их помощью нужный вид диаграммы – дело непростое. Слава Богу, что разработчики снабдили этот компонент специальным окном установки свойств, которое превращает эту задачу в приятное и увлекательное занятие. Окно утановки свойств вызывается с помощью команды локального меню Properties( рис.9.18) .

Шаг 3. Щелкните правой кнопкой мыши на компоненте и выберите в меню эту команду. На экране появится многостраничное окно ChartFX Properties ( рис. 9.19) .

С помощью этого окна диалога полностью настраивается внешний вид диаграммы, включая подбор шрифтов, цвета, стилей линий и т.д. Причем, нажимая кнопку Appiy, можно наблюдать эффект действия установок, не закрывая окна диалога. Вы обнаружите поразительное разнообразие видов которые может отображать компонент ChartFX :

Единственное, чего вы не можете сделать в окне Chart FX Properties, - так это задать значения данных, но об этом чуть позже.

Шаг 4. А сейчас давайте изменим некоторые параметры диаграммы, например развернем диаграмму в пространстве. Для этого активизируйте страницу 3DView ( рис. 9.20 ).

Шаг 5. Поворот диаграммы осуществляется с помощью двух ползунков в виде красного и синего шариков. Установите их так, как показано на рисунке, затем включите переключатель 3DView, разрешив пространственный поворот.

Шаг 6. Теперь давайте создадим на диаграмме панель инструментов, палитру красок, палитру заполнителей, которые позволяют пользователю настраивать диаграмму во время работы приложения. Активизируйте в окне Chart FX Properties страницу Tools и включите переключатели ToolBar (отображать панель инструментов), PaletteBar (отображать палитру красок, чтобы пользователь мог перекрашивать наборы данных) и PattermBar (отображать палитру штриховок, чтобы пользователь мог штриховать наборы данных ) ( рис.9.21) .

Шаг 7. Завершите настройку щелчком на кнопке ОК (рис.9.22) .

Вы увидите диаграмму и на ней панель инструментов, палитру красок и палитру штриховок . Следующий рисунок поясняет смысл отдельных кнопок инструментальной панели (рис.9.23) .

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

Установка данных для программы

Настало время заняться исходными данными, ради которых диаграмма собственно и создавалась. Первые данные, отображаемые при проектировании, генерируются случайным образом, чтобы вы видели результаты своего труда. Ваша задача – установить свои значения для данных. Чтобы это зделать, необходимо знать структуру данных в компоненте ChartFX.

Последовательность экспериментальных данных, отображаемых на диаграммпе одним цветом, называется серией. Число серий и количество значений в одной серии задаются при проектировании с помощью свойства Nseries и Nvalues доступны только для чтения, соответствующие им величины устанавливаются при записи данных в диаграмму и остаются неизменными до следующей операции записи данных.

Установка данных может выполняться пользователем или программистом. Пользователь получает возможность устанавливать данные, нажав кнопку Т (Инструменты) и выбрав во всплывающем меню команду Data Editor (редактор данных). После этих действий в том месте, где была диаграмма, появляется таблица значений (рис.9.24) :

Столбцы таблицы представляют собой серии, а строки – номера значений в серии. Для установки нового значения выполните двойной щелчок на пересечении нужного вам столбца и строки. Фон
редактируемой ячейки станет желтым и появиться текстовый курсор. Используя цифровые клавиши для ввода чисел, а также клавиши Tab и Shift + Tab для перемещения между ячейками, приведите таблицу данных в состояние, показанное на рисунке выше. После этого нажмите клавишу ESC для вывода из режима редактирования. Наконец, закройте редактор данных, выбрав еще раз команду Data Editor во всплывающем меню кнопки Инструменты. Результат этих действий показан на рисунке ниже (рис.9.25).

Все ли вас устраивает в этой диаграмме ? Наверняка нет. Количество отображаемых значений по вертикали слишком велико, поэтому столбцы диаграммы получились маленькими. Чтобы исправить положение, сделайте вот что. Щелкните в инструментальной панели на кнопке (Режимы Отображения) – появится окно диалога View Options (рис9.26.)

Здесь устанавливается много всяких параметров. Вам нужно запомнить следующие :

Установите для параметра Мах значение 20, а для параметра Scale Gap – значение Fixed 5.00. После этого щелкните на кнопке ОК. Готово, теперь диаграмма выглядит подобающим образом (рис.9.27). При этом ни строчки кода. Фантастика !

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

Установка данных программным способом

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

Шаг 8. Возьмем за основу уже имеющийся проект. Перейдите в Редактор Кода и добавьте в список подключаемых модулей CFXOCX2. В этом модуле содержатся определения необходимых для работы констант.

Внимание ! Файл с исходным кодом модуля CFXOCX2 расположен по маршруту Delphi 2.0\Ocx\Chartfx. Если при компиляции вы получите сообщение об ошибке вида “File not found : ‘ CFXOCX2’”, откройте окно Project Options и добавьте маршрут к этому файлу в список маршрутов для поиска.

Шаг 9. Установку данных диаграммы выполним при создании формы по событию OnCreate:

procedure TForm1 . FormCreate (Sender : Tobject);

begin

with ChartFx1 do

begin

OpenDataEx (COD _ VALUES, 2, 4 );

ThisSerie : = 0;

Value [ 0 ] : = 10 . 0;

Value [ 1 ] : = 15 . 0;

Value [ 2 ] : = 14 . 0;

Value [ 3 ] : = 14 . 0;

ThisSerie : = 1;

Value [ 0 ] : = 8 . 0;

Value [ 1 ] : = 9 . 0;

Value [ 2 ] : = 12 . 0;

Value [ 3 ] : = 12 . 0;

CloseData ( COD _ VALUES) ;

end;

end;

В данном примере обращение к методу OpenDataEx открывает канал с номером COD_VALUES ( именно этот канал соответствует просматриваемым данным). Во втором и третьем параметрах метода передаются число серий и число значений в серии. Эти значения впоследствии можно получить, обратившись к свойствам Nseries и Nvalues.

После того как канал открыт, выполняется запись каждой серии данных, При этом сначала в значении свойства ThisSerie устанавливается номер текущей серии (нумерация идет от нуля), а уже затем в свойство-массив Values записываются данные этой серии. Наконец, обращение к методу CloseData с параметром COD_VALUES закрывает канал данных.

Шаг 10. Поменяем для диаграммы некоторые параметры вертикальной шкалы. Откройте окно Chart FX Properties, активизируйте страницу Data Values и в группе Y Axis установите параметр МАХ в значение 20, а параметр Gap – в значение 5 (рис.9.28).

Закройте окно диалога, нажав кнопку ОК, и запустите приложение на выполнение. Результат будет таким, как на рисунке в предыдущем разделе.

Обозначение на диаграмме

Для того чтобы пользователь видел, что показывает диаграмма, используются условные обозначения (legends). Компонент ChartFX обеспечивает максимальную гибкость при комментировании диаграммы и поддерживает целое множество условных обозначений. Каждому отдельному условному обозначению в компоненте ChartFX соответствует отдельный массив. Самые важные условные обозначения: массив SerLeg - поясняет смысл каждой серии; массив KeyLeg – поясняет смысл точек на горизонтальной шкале.

Шаг 11. Давайте дополним предыдущий пример условными обозначениями серий и точек на горизонтальной шкале :

procedure TForm1 . FormCreate (Sender : TObject);

begin

with ChartFX1 do

begin

OpenDataEx (COD _ VALUES, 2, 4 );

ThisSerie : = 0;

Value [ 0 ] : = 10 . 0;

Value [ 1 ] : = 15 . 0;

Value [ 2 ] : = 14 . 0;

Value [ 3 ] : = 14 . 0;

ThisSerie : = 1;

Value [ 0 ] : = 8 . 0;

Value [ 1 ] : = 9 . 0;

Value [ 2 ] : = 12 . 0;

Value [ 3 ] : = 12 . 0;

CloseData ( COD _ VALUES) ;

SerLeg [ 0 ] : = ‘ 1994 ‘ ;

SerLeg [ 1 ] : = ‘ 1995 ‘ ;

KeyLed [0] : = ‘I guater’ ;

KeyLed [0] : = ‘II guater’ ;

KeyLed [0] : = ‘III guater’ ;

KeyLed [0] : = ‘IV guater’ ;

end;

end;

Шаг 12. Осталось разрешить показ условных обозначений серий. Для этого в окне Chart FX Properties необходимо активизировать страницу Tools и поместить пункт Legend (рис.9.29.)

После укомпиляции и запуска проекта (смалатог \Chap9\Chart на компакт-диске) вы получите на экране конечную диаграмму.

ИТОГИ

Вы узнали практически все, что нужно знать для решения 90% графических задач :