Опубликован: 13.07.2010 | Доступ: свободный | Студентов: 891 / 20 | Оценка: 4.40 / 4.20 | Длительность: 77:34:00
Самостоятельная работа 16:

Рисование графических примитивов средствами 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. У него всего два возможных константных значения

Перечисление FillMode
Член Значение Пояснение
System.Drawing.Drawing2D.FillMode.Alternate 0 Задано по умолчанию, чередует закрашенные и незакрашенные области фигуры
System.Drawing.Drawing2D.FillMode.Winding 1 Закрашивает максимально возможное число внутренних областей фигуры

Режим заливки имеет значение лишь тогда, когда линии, определяющие многоугольник, пересекаются. Он определяет, какие из замкнутых областей будут закрашены, а какие - нет. Если режим заливки в методе 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 и проверьте его функциональность во всех построенных нами режимах