Рисование графических примитивов средствами GDI+
Упражнение 13. Рисование секторов
Рисование секторов выполняется функцией DrawPie() класса Graphics. От метода DrawArc() эта функция отличается только тем, что соединяет концы дуги с центром эллипса линиями, создавая замкнутую область, а аргументы сохраняют те же смысловые значения. Этот метод часто применяют для построения круговых диаграмм. Метод имеет 4 перегруженных версии
Приведем пример, строящий круговую диаграмму на основе массива значений, хранимых как поле класса
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
public class PieChart : PrintableForm
{
private int[] aiValues = {50, 100, 25, 150, 100, 75};
public PieChart()
{
this.Text = "Рисование круговой диаграммы (PieChart)";
}
// Перегруженная функция базового класса PrintableForm
protected override void DoPage(Graphics graphics, Color color, int cx, int cy)
{
Rectangle rect = new Rectangle(50, 50, 200, 200);
Pen pen = new Pen(color);
int iTotal = 0;
float fAngle = 0;
Single fSweep; // Структура Single равноценна типу float
foreach(int iValue in aiValues)
iTotal += iValue;
foreach(int iValue in aiValues)
{
fSweep = 360.0F * iValue / (Single)iTotal;
DrawPieSlice(graphics, pen, rect, fAngle, fSweep);
fAngle += fSweep;
}
}
// Создание замещаемого метода
protected virtual void DrawPieSlice(Graphics gr, Pen pn, Rectangle rect,
Single fAngle, Single fSweep)
{
gr.DrawPie(pn, rect, fAngle, fSweep);
}
}
}
Листинг
16.22.
Круговая диаграмма (PieChart.cs)
Упражнение 14. Улучшенное рисование секторов
Метод DoPage() суммирует значения массива и рассчитывает угол каждого сектора, деля значение для этого сектора на сумму значений всех секторов и умножая частное на 360o. Мы специально определили метод DrawPieSlice() виртуальным, чтобы можно было просто написать улучшенный вариант программы, используя класс PieChart как базовый
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
public class BetterPieChart : PieChart
{
public BetterPieChart()
{
this.Text = "Рисование круговой диаграммы (BetterPieChart)";
this.Height += 20;
}
// Создание замещаемого метода
protected override void DrawPieSlice(Graphics gr, Pen pn,
Rectangle rect, Single fAngle, Single fSweep)
{
Single fSlice = Convert.ToSingle(2 * Math.PI / 360 * (fAngle + fSweep / 2));
rect.Offset(Convert.ToInt32((double)rect.Width / 10 * Math.Cos(fSlice)),
Convert.ToInt32((double)rect.Height / 10 * Math.Sin(fSlice)));
base.DrawPieSlice (gr, pn, rect, fAngle, fSweep);
}
}
}
Листинг
16.23.
Еще одна версия круговой диаграммы (BetterPieChart.cs)
Упражнение 15. Заливка прямоугольников, эллипсов и секторов
Для некоторых функций рисования контуров класс Graphics содержит аналогичные методы, которые вместо префикса Draw начинаются с Fill. Например
Есть еще один метод, который похож на метод DrawPolygon(), но имеет один дополнительный параметр FillMode.
FillMode - это статическое перечисление, определяемое в пространстве имен System.Drawing.Drawing2D. У него всего два возможных константных значения
Режим заливки имеет значение лишь тогда, когда линии, определяющие многоугольник, пересекаются. Он определяет, какие из замкнутых областей будут закрашены, а какие - нет. Если режим заливки в методе FillPolygon() не задан, по умолчанию используется режим Alternate. При этом замкнутая область заполняется, если она отделена от бесконечности нечетным числом границ.
Классический пример - пятиконечная звезда. Ее внутренний пятиугольник закрашивается в режиме Winding, но остается свободным в режиме Alternate
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Test
{
public class FillModesClassical : PrintableForm
{
public FillModesClassical()
{
this.Text = "Заливка сложной фигуры (FillModesClassical)";
this.ClientSize = new Size(2 * this.ClientSize.Height,
this.ClientSize.Height);
}
// Перегруженная функция базового класса PrintableForm
protected override void DoPage(Graphics graphics, Color color, int cx, int cy)
{
SolidBrush brush = new SolidBrush(color);
Point[] apoint = new Point[5];
int iMax = apoint.GetUpperBound(0); // Верхнее значение индекса-ключа
// Первая звезда
for(int i = 0; i <= iMax; i++)
{
Double rAngle = (i * 0.8 - 0.5) * Math.PI;
apoint[i].X = Convert.ToInt32(cx * (0.25 + 0.24 * Math.Cos(rAngle)));
apoint[i].Y = Convert.ToInt32(cy * (0.5 + 0.48 * Math.Sin(rAngle)));
}
graphics.FillPolygon(brush, apoint, FillMode.Alternate);
// Вторая звезда
for(int i = 0; i <= iMax; i++)
apoint[i].X += cx / 2;
graphics.FillPolygon(brush, apoint, FillMode.Winding);
}
}
}
Листинг
16.24.
Заливка фигуры в разных режимах (FillModesClassical.cs)
Экранный результат имеет вид
-
Откомпилируйте
проект в режиме Release и проверьте его функциональность во всех построенных
нами режимах






