Диаграммы и графики

Компонент Chart

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

Компонент Chart является контейнером объектов Series типа TChartSeries − серий данных, характеризующихся различными стилями отображения. Каждый компонент может включать несколько серий. Например, при отображении графика каждая серия будет соответствовать одной кривой на графике. Очевидно, что в этом случае серии можно наложить друг на друга. В случае же диаграмм, например круговых, наложение затруднит понимание представленных данных. Однако в последнем случае можно задать для одного компонента Chart несколько серий одинаковых данных с разным типом диаграммы. Тогда, делая в каждый момент времени активной одну из них, можно предоставить пользователю выбор типа диаграммы, отображающей интересующие его данные.

Создайте для проекта приложения каталог (папку Windows), запустите C++Builder 6, создайте новый проект, назовите форму ДЕМОНСТРАЦИЯ КОМПОНЕНТА CHART и командой Сохранить все сразу сохраните файл модуля и проект под разными именами.

Разместите на пустой форме компонент Chart со страницы Additional и просмотрите открывшиеся в Инспекторе Объектов свойства. Поясним некоторые из них.

 

AllowPanning Определяет возможность пользователя прокручивать на-блюдаемую часть графика во время выполнения, нажимая правую кнопку мыши. Возможные значения: pmNone − прокрутка запрещена, pmHorizontal, pmVerticalили pmBoth − разрешена соответственно прокрутка только в горизонтальном направлении, только в вертикальном или в обоих направлениях
AllowZoom Позволяет пользователю изменять во время выполнения масштаб изображения, вырезая фрагменты диаграммы или графика курсором мыши
Title Определяет заголовок диаграммы
Foot Определяет подпись под диаграммой. По умолчанию от-сутствует. Текст подписи определяется подсвойством Text
Frame Определяет рамку вокруг диаграммы
Legend Легенда диаграммы − список обозначений
MarginLeft, MarginRight, MarginTop, MarginBottom Значения левого, правого, верхнего и нижнего полей
BottomAxis, LeftAxis, RightAxis Эти свойства определяют характеристики соответственно нижней, левой и правой осей. Задание этих свойств имеет смысл для графиков и некоторых типов диаграмм
LeftWall, BottomWall, BackWall Эти свойства определяют характеристики соответственно левой, нижней и задней граней области трехмерного ото-бражения графика
SeriesList Список серий данных, отображаемых в компоненте
View3D Разрешает или запрещает трехмерное отображение диа-граммы
View3DOptions Характеристики трехмерного отображения
Chart3DPercent Масштаб трехмерности (например, толщина диаграммы и ширина лент графика)

 

Рядом со многими из перечисленных свойств в Инспекторе Объектов расположены кнопки с многоточием, которые позволяют вызвать ту или иную страницу Редактора Диаграмм − многостраничного окна, позволяющего установить все свойства диаграмм. Вызов Редактора Диаграмм возможен также двойным щелчком на компоненте Chart или щелчком на нем правой кнопкой мыши и выбором команды Edit Chart во всплывшем меню.

 

Перейдем к проектированию приложения для построения диаграмм и графиков.

1.Сделайте двойной щелчок на компоненте Chart1. Появится окно Редактора Диаграмм (Editing Chart1) с открывшейся страницей Chart, которая имеет несколько закладок. На странице Series щелкните на кнопке Add… − добавить серию. В появившемся окне выбирают тип диаграммы или графика. Выберите Pie − круговую диаграмму. После щелчка на OK снова появится окно Редактора Диаграмм. Сместив его в сторону, увидите, что в компоненте Chart1 на форме отображается вид диаграммы с занесенными в нее условными данными. Благодаря этому пользователь сразу может наблюдать результат применения различных опций к приложению.

2.Перейдите на закладку Titles. В окне редактирования, которое в данный момент соответствует Title − заголовку диаграммы, сотрите TChart и напишите ДИАГРАММА РЕЗУЛЬТАТОВ ЭКЗАМЕНОВ. С помощью выпадающего списка перейдите в окно редактирования Foot и напишите Успеваемость студентов в %.

3.Перейдите на закладку Panel. Теперь можно задать вид панели, на которой отображается диаграмма. В частности, можно задать два варианта цвета панели − постоянный (кнопка Panel Color…) и градиентный (в группе Gradient после установки индикатора Visible задается начальный цвет панели кнопкой StartColor… и конечный − кнопкой EndColor…). Выберите и установите оба варианта цвета панели. Индикатор Visible позволяет переключать варианты.

4.На закладке 3D установите желаемый внешний вид диаграммы: размер, наклон, сдвиг по горизонтали и вертикали, толщину и т.д.

5.Изучите возможности закладки Legend, которая позволяет задать параметры отображения легенды диаграммы (списка обозначений) или вообще убрать ее с экрана.

6.Перейдите на страницу Series Редактора Диаграмм. На закладке Format включите опцию Circled Pie, которая обеспечит при любом размере компонента Chartотображение диаграммы в виде круга.

7.На закладке Marks кнопки группы Style определяют, что будет написано на ярлычках, относящихся к отдельным сегментам диаграммы: Value − значение, Percent − проценты, Label − названия данных и т.д. Включите кнопку Percent, а на закладке General установите шаблон процентов только с целыми процентами.

8.Добавьте на компонент Chart1еще одну тождественную серию, нажав на закладке Series страницы Chart кнопку Clone, а затем для этой новой серии нажмите кнопку Change… (изменить) и выберите другой тип диаграммы − Bar. Очевидно, что наложение двух разных типов диаграммы на одном рисунке затруднит понимание представленных данных. Поэтому выключите индикатор этой новой серии на закладке Series страницы Chart. На этом задание свойств первого компонента Chart1 завершается. Выйдите из Редактора Диаграмм.

9.Перенесите на форму второй компонент Chart2, разместив его под первым компонентом. Для задания свойств перейдите в Редактор Диаграмм Editing Chart2.

10.На закладке Series страницы Chart нажмите кнопку Add…и выберите тип диаграммы Line для графика. Нажав OK, на закладке Series страницы Chart нажмите кнопку Title и в открывшемся окне напишите SIN. Затем повторите все действия этого пункта, но только напишите COS.

11.Перейдите на закладку Axis для задания координатных характеристик осей. В группе Axis нажата кнопка Left. На закладке Title в окно редак-тирования Title: впишите F, в Angle: − 0, размер шрифта Font − равным 16. В группе Axis нажмите кнопку Bottom, в Title: впишите X тем же шрифтом.

12.Перейдите на закладку Titles и в окно редактирования для Title впишите ГРАФИКИ SIN И COS.

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

14.Изучите возможности закладки Walls для задания характеристик трехмерных граней графика.

15.Перейдите на закладку 3D и выключите индикатор 3Dimensions. Изучите другие возможности задания свойств графика на этой закладке.

16.Для задания толщины графиков перейдите на страницу Series, а в ней − на закладку Format. В группе Line нужно нажать кнопку Border и в окне Border Color Editor установить Width равным 3.

 

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

Для задания отображаемых значений используют методы серий Series.Метод Clear очищает серию от занесенных ранее данных.

Метод Add

long int Add(const double AValue, const String ALabel, TColor AColor);

позволяет добавить в диаграмму новую точку. Параметр AValue соответствует добавляемому значению, параметр ALabel− название, которое будет отображаться на диаграмме и в легенде, AColor −цвет. Параметр ALabel −необязательный, его можно задать пустым: “ ”.

Метод AddXY

long int AddXY(double AXValue, double AYValue, const String ALabel, TColor);

позволяет добавить новую точку в график функции. Параметры AXValue и AYValue соответствуют аргументу и функции. Параметры ALabelи AColor− те же, что и в методе Add.

 

17.Поместите на форме вверху, справа, кнопку Button1 и назовите ее КОНЕЦ, а в обработчик щелчка на этой кнопке впишите Close();.

18.Ниже поместите вторую кнопку Button2 и назовите ее НАРИСОВАТЬ, а в обработчик щелчка на ней впишите:

 

void __fastcall TForm1::Button2Click(TObject *Sender)

{

int A1=5;

int A2=8;

int A3=5;

int A4=2;

const Pi=3.14159;

Series1->Clear();

Series2->Clear();

Series1->Add(A1,"двоешники",clYellow);

Series1->Add(A2,"троешники",clBlue);

Series1->Add(A3,"хорошисты",clRed);

Series1->Add(A4,"отличники",clPurple);

Series3->Clear();

Series4->Clear();

for(int i=0; i<=100; i++)

{

Series3->AddXY(0.02*Pi*i,sin(0.02*Pi*i),"",clRed);

Series4->AddXY(0.02*Pi*i,cos(0.02*Pi*i),"",clBlue); }

Series2->Assign(Series1);

Series2->Active=false;

}

 

Первый из двух последних операторов загружает данные из диаграммы Pie в диаграмму Bar и делает последнюю в первый момент невидимой. Смена типа диаграммы происходит при щелчке на диаграмме компонента Chart1. Чтобы это реализовать, выделите компонент Chart1и в обработчик его события OnClickSeriesвпишите:

 

void __fastcall TForm1::Chart1ClickSeries(TCustomChart *Sender,

TChartSeries *Series, int ValueIndex, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

Series1->Active=!Series1->Active;

Series2->Active=!Series2->Active;

}

 

19.В заголовочный файл модуля впишите #include <math.h>. Сохраните проект и запустите на выполнение. Убедитесь, что при щелчке на диаграмме меняется ее вид. Убедитесь также, что левой кнопкой можно увеличивать фрагменты графика, а правой кнопкой − перемещать график.

 

Компонент Image

Компонент Image находится на странице Дополнительно библиотеки компонентов. Он имеет свойство Canvas (канва, холст), представляющее собой область компонента, на которой можно рисовать или отображать готовые изображения. Канва содержит свойства и методы, существенно упрощающие графику C++Builder.

Каждая точка канвы имеет координаты X и Y. Система координат канвы, как и везде в C++Builder, имеет началом левый верхний угол канвы. Координата Xвозрастает при перемещении слева направо, а координата Y− при перемещении сверху вниз.

Координаты измеряются в пикселах. Пиксел − это наименьший элемент поверхности рисунка, с которым можно манипулировать. Важнейшее свойство пиксела − его цвет. Для описания цвета используется тип TColor. В C++Builder определено множество констант типа TColor. Одни из них непосредственно определяют цвета (например, clBlue − синий), другие определяют цвета элементов окон, которые могут меняться в зависимости от выбранной пользователем палитры цветов Windows (например, clBtnFace − цвет поверхности кнопок).

 

Рисование по пикселам

Для рисования по пикселам используется свойство канвы Pixels. Это свойство представляет собой двумерный массив Canvas->Pixels[int X][int Y], который отвечает за цвета канвы. Например, Canvas->Pixels[10][20]соответствует цвету пиксела, 10-го слева и 20-го сверху. С массивом пикселов можно обращаться как с любым свойством: изменять цвет, задавая пикселу новое значение, или определять его цвет по хранящемуся в нем значению. Например, Canvas->Pixels[10][20]=clBlack −это задание пикселу черного цвета.

Предположим, нужно нарисовать график некоторой функции F(X) на канве компонента Image1, если известен диапазон ее изменения Ymaxи Yminи диапазон изменения аргумента Xminи Xmax. Это можно сделать так:

float X,Y; // координаты функции

int PX,PY; // координаты пикселов

for(PX=0;PX<=Image1->Width;PX++)

{

// X - координата, соответствующая пикселу с координатой PX

X=Xmin+PX*(Xmax-Xmin)/Image1->Width;

Y=F(X);

// PY - координата пиксела, соответствующая координате Y

PY=Image1->Height-(Y-Ymin)* Image1->Height/(Ymax-Ymin);

// Устанавливается красный цвет выбранного пиксела

Image1->Canvas->Pixels[PX][PY]=clRed;

}

 

Цикл выполняется по всем значениям горизонтальной координаты пикселов PX компонента Image1. Сначала выбранное значение PX пересчитывается в соответствующее значение X. Затем производится вызов функции и определяется ее значение Y. Это значение пересчитывается в вертикальную координату пиксела PY. И в заключение цвет пиксела с координатами (PX, PY) устанавливается красным.

Ниже приведено приложение для функции sin(X), для которой Xmin=0, Xmax=4 (2 периода), Ymin=-1 и Ymax=1.

 

Рисование пером

У канвы есть свойство − Pen − перо. Это объект, в свою очередь имеющий ряд свойств. Одно из них Color − цвет, которым наносится рисунок. Второе свойство − Width (ширина линии). Ширина задается в пикселах. По умолчанию ширина равна 1.

Свойство Style определяет вид линии и может принимать следующие значения:

 

psSolid Сплошная линия
psDash Штриховая линия
psDot Пунктирная линия
psDashDot Штрих-пунктирная линия
psDashDotDot Линия, чередующая штрих и два пунктира
psClear Отсутствие линии
psInsideFrame Сплошная линия, но при Width>1 допускающая цвета, отличные от палитры Windows

 

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

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

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

 

Нарисуем по пикселам и пером графики синуса и сравним качество графиков.

1.Создайте для проекта приложения каталог (папку Windows), запустите C++Builder 6, создайте новый проект, назовите форму ДЕМОНСТРАЦИЯ КОМПОНЕНТА IMAGE и командой Сохранить все сразу сохраните файл модуля и проект под разными именами.

2.На пустую форму перенесите два компонента Imageи разместите их по горизонтали рядом. Размеры обоих компонентов сделайте абсолютно одинаковыми, так как на этом для экономии размера кода основана программа. Сделать размеры компонентов абсолютно одинаковыми можно, выделив их оба и воспользовавшись командой всплывающего меню Size.

3.Над первым, левым компонентом поместите первую метку Label1 и назовите ее рисунок по пикселам, над вторым −Label2, с названием рисунок пером.

4.В правом верхнем углу поместите кнопку Button1 и назовите ее КОНЕЦ. В обработчик щелчка кнопки впишите Close();.

5.Под компонентами поместите вторую кнопку Button2, назовите ее НАРИСОВАТЬ, а в обработчик щелчка впишите:

 

void __fastcall TForm1::Button2Click(TObject *Sender)

{

#define Pi 3.14159

float X,Y; // координаты функции

int PX,PY; // координаты пикселов

// Переводится перо в начало координат второго графика -

// на левый край канвы в середину ее высоты

Image2->Canvas->MoveTo(0,Image2->Height/2);

// Устанавливается красный цвет рисования пером

Image2->Canvas->Pen->Color=clRed;

// Устанавливается ширина линии рисования в три пиксела

Image2->Canvas->Pen->Width=3;

for(PX=0;PX<=Image1->Width;PX++)

{

// X - координата, соответствующая пикселу с координатой PX

X=PX*4*Pi/Image1->Width;

Y=sin(X);

// PY - координата пиксела, соответствующая координате Y

PY=Image1->Height-(Y+1)* Image1->Height/2;

// Устанавливается красный цвет выбранного пиксела

Image1->Canvas->Pixels[PX][PY]=clRed;

// Проводится линия на втором графике

Image2->Canvas->LineTo(PX,PY);

}

}

 

6.В заголовочный файл модуля впишите #include <math.h>. Сохраните проект и запустите на выполнение. Нетрудно видеть, что качество графиков сильно различается . В левом на крутых участках сплошной линии нет − она распадается на отдельные точки − пикселы. А правый график весь сплошной. Это показывает, что при прочих равных условиях рисовать лучше не по пикселам, а пером.

 

Отметим еще одно ценное свойство компонента Image и его канвы − можно задавать координаты пикселов, выходящие за пределы размеров канвы. Это позволяет не заботиться о том, какая часть рисунка попадает в рамку Image, а какая нет. Например, соответствующий оператор изменим так: Y=2*sin(X);. Сохраним проект и выполним. Увидим, что изобразилась только та часть рисунка, которая помещается в рамку канвы. Это позволяет без затруднений осуществлять приложения, в которых пользователю предоставляется возможность увеличивать и просматривать в деталях какие-то фрагменты графиков.