| netlib.narod.ru | < Назад | Оглавление | Далее > |
Дуга (по крайней мере в случае Windows Forms) — это сегмент эллипса. Чтобы определить дугу, нужно указать те же сведения, что и для определения эллипса, плюс углы для начальной и конечной точек дуги. В силу этих причин каждая из четырех версий метода DrawArc требует на два аргумента больше, чем их нужно для DrawEllipse:
Методы DrawArc класса Graphics
| void DrawArc(Pen pen, int x, int y, int cx, int cy, int iAngleStart, int iAngleSweep) |
| void DrawArc(Pen pen, float x, float y, float cx, float cy, float fAngleStart, float fAngleSweep) |
| void DrawArc(Pen pen, Rectangle rect, float fAngleStart, float fAngleSweep) |
| void DrawArc(Pen pen, RectangleF rectf, float fAngleStart, float fAngleSweep) |
Пара дополнительных аргументов задает утлы, определяющие начало дуги и ее длину. Эти углы (которые могут быть как положительными, так и отрицательными) измеряются по часовой стрелке в градусах и откладываются от горизонтальной оси справа от центра эллипса (стрелка часов в этом положении покажет 3 часа):

Вот программа, рисующая эллипс с пунктирным контуром. Угловой размер штрихов пунктира составляет 10o, промежутков между штрихами — 5o.
DashedEllipse.cs
//----------------------------------------------
// DashedEllipse.cs (C) 2001 by Charles Petzold
//----------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class DashedEllipse: PrintableForm
{
public new static void Main()
{
Application.Run(new DashedEllipse());
}
public DashedEllipse()
{
Text = "Dashed Ellipse Using DrawArc";
}
protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
{
Pen pen = new Pen(clr);
Rectangle rect = new Rectangle(0, 0, cx - 1, cy - 1);
for (int iAngle = 0; iAngle < 360; iAngle += 15)
grfx.DrawArc(pen, rect, iAngle, 10);
}
}
Полученный эллипс выглядит так:

В Win32 API есть функция RoundRect, рисующая прямоугольник с закругленными углами. Эта функция принимает 4 аргумента, указывающих координаты верхнего левого и правого нижнего углов прямоугольника плюс еще два, определяющие ширину и высоту эллипса, используемого для скругления углов прямоугольника.
В классе Graphics метода RoundRect нет, но мы вполне можем попытаться имитировать его.
RoundRect.cs
//------------------------------------------
// RoundRect.cs (C) 2001 by Charles Petzold
//------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class RoundRect: PrintableForm
{
public new static void Main()
{
Application.Run(new RoundRect());
}
public RoundRect()
{
Text = "Rounded Rectangle";
}
protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
{
RoundedRectangle(grfx, Pens.Red,
new Rectangle(0, 0, cx - 1, cy - 1),
new Size(cx / 5, cy / 5));
}
void RoundedRectangle(Graphics grfx, Pen pen, Rectangle rect, Size size)
{
grfx.DrawLine(pen, rect.Left + size.Width / 2, rect.Top,
rect.Right - size.Width / 2, rect.Top);
grfx.DrawArc(pen, rect.Right - size.Width, rect.Top,
size.Width, size.Height, 270, 90);
grfx.DrawLine(pen, rect.Right, rect.Top + size.Height / 2,
rect.Right, rect.Bottom - size.Height / 2);
grfx.DrawArc(pen, rect.Right - size.Width,
rect.Bottom - size.Height,
size.Width, size.Height, 0, 90);
grfx.DrawLine(pen, rect.Right - size.Width / 2, rect.Bottom,
rect.Left + size.Width / 2, rect.Bottom);
grfx.DrawArc(pen, rect.Left, rect.Bottom - size.Height,
size.Width, size.Height, 90, 90);
grfx.DrawLine(pen, rect.Left, rect.Bottom - size.Height / 2,
rect.Left, rect.Top + size.Height / 2);
grfx.DrawArc(pen, rect.Left, rect.Top,
size.Width, size.Height, 180, 90);
}
}
Написанному мной методу RoundedRectangle требуются такие аргументы: Rectangle, указывающий расположение и размер прямоугольника и Size, задающий ширину и высоту эллипса для скругления углов. Я написал этот метод, чтобы сохранить согласованность с размерами прямоугольника, нарисованного методом DrawRectangle. To есть, когда ширина и высота фигуры устанавливаются равными соответствующим измерениям клиентской области минус 1, будет видима вся фигура. Мой метод по очереди вызывает DrawLine и DrawArc, прорисовывает сначала верхний контур фигуры и продолжает рисовать остальные части контура по часовой стрелке.

Однако я не могу без колебаний рекомендовать этот способ как общий подход к рисованию прямоугольников с закругленными углами. Отдельные линии и дуги здесь рисуют отдельные вызовы методов DrawLine и DrawArc. Это значит, что у каждой из восьми частей контура фигуры будут прорисованы концы, а соединения между ними — нет. Правильный путь объединения прямых и кривых в цельную фигуру состоит в использовании графического контура (path). Как это делается, я покажу в главе 15.
У методов DrawPie те же аргументы, что и у DrawArc, но они отличаются тем, что соединяют концы дуги с центром эллипса линиями, создавая замкнутую область.
Методы DrawPie класса Graphics
| void DrawPie(Pen pen, int x, int y, int cx, int cy, int iAngleStart, int iAngleSweep) |
| void DrawPie(Pen pen, float x, float y, float cx, float cy, float fAngleStart, float fAngleSweep) |
| void DrawPie(Pen pen, Rectangle rect, float fAngleStart, float fAngleSweep) |
| void DrawPie(Pen pen, RectangleF rectf, float fAngleStart, float fAngleSweep) |
В мире деловой графики очень уважают круговые диаграммы — это факт. Проблема в том, что если уж пришлось программировать круговую диаграмму, хорошо бы украсить ее трехмерными и другими эффектами. Здесь у метода DrawPie меньше возможностей, чем вы думаете. Так или иначе, вот программа, строящая круговую диаграмму на основе массива значений (хранимого как поле), который я создаю специально для этой цели.
PieChart.cs
//-----------------------------------------
// PieChart.cs (C) 2001 by Charles Petzold
//-----------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class PieChart: PrintableForm
{
int[] aiValues = { 50, 100, 25, 150, 100, 75 };
public new static void Main()
{
Application.Run(new PieChart());
}
public PieChart()
{
Text = "Pie Chart";
}
protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
{
Rectangle rect = new Rectangle(50, 50, 200, 200);
Pen pen = new Pen(clr);
int iTotal = 0;
float fAngle = 0, fSweep;
foreach(int iValue in aiValues)
iTotal += iValue;
foreach(int iValue in aiValues)
{
fSweep = 360f * iValue / iTotal;
DrawPieSlice(grfx, pen, rect, fAngle, fSweep);
fAngle += fSweep;
}
}
protected virtual void DrawPieSlice(Graphics grfx, Pen pen,
Rectangle rect,
float fAngle, float fSweep)
{
grfx.DrawPie(pen, rect, fAngle, fSweep);
}
}
Обратите внимание на определение Rectangle в методе DoPage. Это единственная программа в данной главе, использующая абсолютные координаты и размеры, так как круговые диаграммы в форме эллипса не слишком привлекательны. Метод DoPage суммирует значения массива и рассчитывает угол для каждого сектора, деля значение для этого сектора на сумму значений всех секторов и умножая частное на 360o. Вот результат:

Простите, но я просто не могу позволить вам думать, что это лучшая диаграмма, которую я способен нарисовать! К счастью, я оказался достаточно прозорливым, чтобы поместить вызов DrawPie в виртуальную функцию в классе PieChart. Это позволяет легко переопределить метод в программе BetterPieChart.
BetterPieChart.cs
//-----------------------------------------------
// BetterPieChart.cs (C) 2001 by Charles Petzold
//-----------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class BetterPieChart: PieChart
{
public new static void Main()
{
Application.Run(new BetterPieChart());
}
public BetterPieChart()
{
Text = "Better " + Text;
}
protected override void DrawPieSlice(Graphics grfx, Pen pen,
Rectangle rect,
float fAngle, float fSweep)
{
float fSlice = (float)(2 * Math.PI * (fAngle + fSweep / 2) / 360);
rect.Offset((int)(rect.Width / 10 * Math.Cos(fSlice)),
(int)(rect.Height / 10 * Math.Sin(fSlice)));
base.DrawPieSlice(grfx, pen, rect, fAngle, fSweep);
}
}
Переменная fSlice — это угол между горизонтальной осью и центром сектора, преобразованный в радианы. Это значение понадобилось мне для расчета смещения по осям X и Y прямоугольников, определяющих размер и положение секторов диаграммы. В результате все секторы отошли от центра, и на изображении диаграммы они не соприкасаются:

На этом коллекция методов класса Graphics, рисующих линии, далеко не исчерпана. Методы DrawBezier, DrawBeziers, DrawCurve и DrawClosedCurve позволяют рисовать кривые посложнее, чем эллиптические дуги. Описание этих методов вы найдете в главе 13. Можно объединить набор прямых и кривых в графический контур и визуализировать его при помощи метода DrawPath. К этой теме мы обратимся в главе 15.
| netlib.narod.ru | < Назад | Оглавление | Далее > |