Рисование графических примитивов средствами 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 и проверьте его функциональность во всех построенных нами режимах