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 | < Назад | Оглавление | Далее > |