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

Сайт управляется системой uCoz