| netlib.narod.ru | < Назад | Оглавление | Далее > |
Чтобы избежать написания таких методов, как MMConv, в GDI+ включен механизм автоматического масштабирования до заданного размера. В сущности этот механизм масштабирует координаты, передаваемые функциям рисования объекта Graphics, при помощи констант, как метод MMConv. Но при этом коэффициенты масштабирования задают не напрямую, а через свойства PageUnit и PageScale:
Свойства Graphics (выборочно)
| Тип | Свойство | Доступ |
| GraphicsUnit | PageUnit | Чтение/запись |
| float | PageScale | Чтение/запись |
В свойство PageUnit заносится одно из значений перечисления GraphicsUnit:
Перечисление GraphicsUnit
| Член | Значение | Описание |
| World | 0 | Не используется со свойством PageUnit |
| Display | 1 | Для дисплея то же, что Pixel; для принтера равно 1/100 дюйма (задано по умолчанию для принтера). |
| Pixel | 2 | Единицы измерения — пикселы (задано по умолчанию для дисплея) |
| Point | 3 | Единицы измерения — пункты (1/72 дюйма) |
| Inch | 4 | Единицы измерения — дюймы |
| Document | 5 | Единицы измерения — 1/300 дюйма |
| Millimeter | 6 | Единицы измерения — миллиметры |
Например, если вы хотите рисовать в координатах, исчисляемых сотыми долями дюйма, этой паре свойств надо задать такие значения:
grfx.PageUnit = GraphicsUnit.Inch; grfx.PageScale = 0.01f;
что эквивалентно указанию считать одно деление координатной оси равным 0,01 дюйма. После этого следующий вызов метода DrawLine нарисует линию длиной в 1 дюйм:
grfx,DrawLine(pen, 0, 0, 100, 0);
Если отпечатать такую линию на принтере, вполне можно ее измерить и убедиться, что ее длина действительно равна 1 дюйму; на дисплее этот дюйм равен grfx.DpiX пикселов. Аналогичный результат можно получить так:
grfx.PageUnit = GrapnicsUnit.Document; grfx.PageScale = 3;
или:
grfx.PageUnit = GraphicsUnit.Millimeter; grfx.PageScale = 0.254f;
или:
grfx.PageUnit = GraphicsUnit.Point; grfx.PageScale = 0.72f;
По умолчанию для дисплея задано значение GraphicsUnit.Pixel, а для принтера — GraphicsUnit.Display, для обоих устройств значение PageScale равно 1. Кстати, смысл значения GraphicsUnit.Display для дисплея и для принтера разный. Для дисплея это то же самое, что GraphicsUnit.Pixel, но для принтера оно задает единицы измерения, равные 1/100 дюйма.
Итак, чтобы заставить программу TenCentimeterRuler работать с принтером, достаточно присвоить свойству PageUnit значение GraphicsUnit.Pixel, и все будет хорошо. Новая версия метода OnPage устанавливает свойство PageUnit и вызывает метод DoPage из базового класса.
PrintableTenCentimeterRuler.cs
//------------------------------------------------------------
// PrintableTenCentimeterRuler.cs (C) 2001 by Charles Petzold
//------------------------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class PrintableTenCentimeterRuler: TenCentimeterRuler
{
public new static void Main()
{
Application.Run(new PrintableTenCentimeterRuler());
}
public PrintableTenCentimeterRuler()
{
Text = "Printable " + Text;
}
protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
{
grfx.PageUnit = GraphicsUnit.Pixel;
base.DoPage(grfx, clr, cx, cy);
}
}
В этой программе метод DoPage не использует аргументы сх и су. Размеры, определяемые этими аргументами (размеры клиентской области формы и области печати страницы принтера), исчисляются в единицах, определяемых значением PageUnit по умолчанию. В общем случае при изменении значения PageUnit размер страницы устройства вывода тоже должен быть пересчитан в идентичные единицы. Чуть ниже мы обсудим этот вопрос.
Теперь, даже если рисовать на принтере, задавая координаты в пикселах, вид шрифтов не исказится, а у шрифта, доступного через свойство формы Font, будет кегль 8 как на дисплее, так и на принтере. В главе 9 мы увидим, как это работает.
Однако в этой программе остается проблема с пером, определяемым версией метода DoPage, которая используется в программе TenCentimeterRuler:
Pen pen = new Pen(clr);
Толщина этого пера по умолчанию равна 1. Для дисплея это означает 1 пиксел, а для принтера это обычно 1/100 дюйма. Но если изменить значение PageUnit на GraphicsUnit.Pixel, то толщина 1 будет интерпретирована как 1 пиксел. На некоторых принтерах с высоким разрешением такая линия будет почти невидимой.
Чтобы не возиться с исходной версией программы, рисующей 10-сантиметровую линейку, задействуем преимущество свойств PageUnit и PageScale и избавимся от ручного преобразования координат.
TenCentimeterRulerAuto.cs
//-------------------------------------------------------
// TenCentimeterRulerAuto.cs (C) 2001 by Charles Petzold
//-------------------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class TenCentimeterRulerAuto: PrintableForm
{
public new static void Main()
{
Application.Run(new TenCentimeterRulerAuto());
}
public TenCentimeterRulerAuto()
{
Text = "Ten-Centimeter Ruler (Auto)";
}
protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
{
Pen pen = new Pen(clr, 0.25f);
Brush brush = new SolidBrush(clr);
const int xOffset = 10;
const int yOffset = 10;
grfx.PageUnit = GraphicsUnit.Millimeter;
grfx.PageScale = 1;
grfx.DrawRectangle(pen, xOffset, yOffset, 100, 10);
StringFormat strfmt = new StringFormat();
strfmt.Alignment = StringAlignment.Center;
for (int i = 1; i < 100; i++)
{
if (i % 10 == 0) // Сантиметровые метки
{
grfx.DrawLine(pen,
new PointF(xOffset + i, yOffset),
new PointF(xOffset + i, yOffset + 5));
grfx.DrawString((i/10).ToString(), Font, brush,
new PointF(xOffset + i, yOffset + 5),
strfmt);
}
else if (i % 5 == 0) // Полусантиметровые метки
{
grfx.DrawLine(pen,
new PointF(xOffset + i, yOffset),
new PointF(xOffset + i, yOffset + 3));
}
else // Миллиметровые метки
{
grfx.DrawLine(pen,
new PointF(xOffset + i, yOffset),
new PointF(xOffset + i, yOffset + 2.5f));
}
}
}
}
Кроме удаления метода MMConv, почти ничего не изменилось. Мой метод MMConv работал только со структурами PointF, поэтому в ранних версиях программы для рисования контуров линейки использовался метод DrawPolygon, а не DrawRectangle. Поскольку GDI+ одинаково масштабирует координаты и размеры, здесь можно применить метод DrawRectangle. Другое изменение коснулось метода DoPage. Теперь в начале DoPage программа создает перо толщиной 0,25 единицы:
Pen pen = new Pen(clr, 0.25f);
Программа также настраивает объект Graphics для рисования в миллиметровых координатах:
grfx.PageUnit = Graphics.Unit. Millimeter; grfx.PageScale = 1;
Возможно, вам любопытно знать, есть ли разница между установкой свойств PageUnit и PageScale перед созданием пера и созданием пера с заданной толщиной перед установкой этих свойств. Когда создано перо: до установки этих свойств или после нее — не имеет никакого значения, так как объекты Pen независимы от устройства! Пока не вызван ни один из методов рисования линий, объект Pen не связан ни с одним конкретным объектом Graphics. Лишь после привязки толщина пера интерпретируется в зависимости от текущих значений свойств PageUnit и PageScale. В данном случае толщина пера интерпретируется как 0,25 мм или около 1/100 дюйма. Чтобы увидеть различия на печати, можно попробовать меньшее значение (например, 0,10 мм).
Если толщина пера не включена в его конструктор, создается перо толщиной в 1 единицу. В данном случае это значит, что будет создано перо толщиной ровно 1 мм и все деления сольются в одно большое пятно (убедитесь сами!).
| netlib.narod.ru | < Назад | Оглавление | Далее > |