netlib.narod.ru< Назад | Оглавление | Далее >

Массивы гарнитур

FontFamily имеет еще одно статическое свойство и еще один статический метод. Они схожи и очень важны. Оба возвращают набор объектов FontFamily, соответствующий установленным в системе шрифтам TrueType и OpenType:


Статические свойства FontFamily (выборочно)



Тип Свойство Доступ

FontFamily[] Families Чтение


Если выполнить инструкцию

  FontFamily[] aff = FontFamily.Families;

каждый элемент массива aff будет объектом FontFamily. Если вам доводилось сталкиваться с перечислением шрифтов в программах Win32 API, вы оцените простоту такого подхода.

Этот массив позволяет легко получить список доступных шрифтов и вывести на внешнее устройство образцы текста с этими шрифтами:

NaiveFamiliesList.cs

  //--------------------------------------------------
  // NaiveFamiliesList.cs (C) 2001 by Charles Petzold
  //--------------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class NaiveFamiliesList: PrintableForm
  {
      public new static void Main()
      {
          Application.Run(new NaiveFamiliesList());
      }
      public NaiveFamiliesList()
      {
          Text = "Naive Font Families List";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          Brush        brush = new SolidBrush(clr);
          float        y     = 0;
          FontFamily[] aff   = FontFamily.Families;

          foreach (FontFamily ff in aff)
          {
              Font font = new Font(ff, 12);
              grfx.DrawString(ff.Name, font, brush, 0, y);
              y += font.GetHeight(grfx);
          }
      }
  }

Инструкция foreach перебирает все элементы FontFamily. Для каждого элемента конструктор Font создает 12-пунктный шрифт, DrawString использует его для вывода на монитор названия гарнитуры, a GetHeight готовит вертикальные координаты для вывода следующей строки.

Эта программа может не работать на некоторых компьютерах. На моем конструктор Font генерирует исключение для самой первой гарнитуры массива.

К ошибке приводит файл шрифта Ahronbd.ttf, который устанавливается с дистрибутивного диска Windows 2000 для поддержки гарнитуры Hebrew. Он содержит шрифт Aharoni Bold, единственный шрифт гарнитуры Aharoni (по крайней мере в Windows 2000). Это значит, что следующая инструкция будет работать

  font = new Font("Aharoni", 12, FontStyle.Bold)

А эта

  font = new Font("Aharoni", 12)

не будет, так как она равносильна

  font = new Font("Aharoni", 12, FontStyle.Regular)

а шрифт Aharoni с нормальным начертанием не реализован. (Вот лентяи!)

Эту проблему можно решить двумя способами. Первый — использовать конструкции try и catch. Поместите код из предыдущего цикла foreach в блок try. В блоке catch выведите название гарнитуры, из-за которой возникают проблемы, со знаком «звездочка», используя свойство формы Font:

  foreach (FontFamily ff in aff)
  {
      try
      {
          Font font = new Font(ff, 12);
          grfx.DrawString(ff.Name, font, brush, 0, y);
          y += font.GetHeight(grfx);
      }
      catch
      {
          grfx.DrawString("* " + ff.Name, Font, brush, 0, y);
          у += Font.GetHeight(grfx);
      }
  }

Вместе с тем лучше не использовать блоки try и catch, если есть другие способы. В нашем случае альтернативный подход состоит в применении метода IsStyleAvailable класса FontFamily. Вот лучшее решение задачи, которое работает независимо от того, установлен ли шрифт Aharoni Bold.

BetterFamiliesList.cs

  //---------------------------------------------------
  // BetterFamiliesList.cs (C) 2001 by Charles Petzold
  //---------------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class BetterFamiliesList: PrintableForm
  {
      public new static void Main()
      {
          Application.Run(new BetterFamiliesList());
      }
      public BetterFamiliesList()
      {
          Text = "Better Font Families List";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          Brush        brush = new SolidBrush(clr);
          float        y     = 0;
          FontFamily[] aff   = FontFamily.Families;

          foreach (FontFamily ff in aff)
          {
              if (ff.IsStyleAvailable(FontStyle.Regular))
              {
                  Font font = new Font(ff, 12);
                  grfx.DrawString(ff.Name, font, brush, 0, y);
                  y += font.GetHeight(grfx);
              }
              else
              {
                  grfx.DrawString("* " + ff.Name, Font, brush, 0, y);
                  y += Font.GetHeight(grfx);
              }
          }
      }
  }

Если у вас установлено большое количество шрифтов, этот подход не позволит вам увидеть все шрифты, даже на большом мониторе или на распечатке.

Если не рассматривать полосы прокрутки, правильнее сформатировать список в колонки. Следующая программа так и работает. А если и этого не хватит для вывода всех шрифтов, попробуйте изменить поле iPointSize на 10, 8 или 6.

FamiliesList.cs

  //---------------------------------------------
  // FamiliesList.cs (C) 2001 by Charles Petzold
  //---------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class FamiliesList: PrintableForm
  {
      const int iPointSize = 12;

      public new static void Main()
      {
          Application.Run(new FamiliesList());
      }
      public FamiliesList()
      {
          Text = "Font Families List";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          Brush        brush = new SolidBrush(clr);
          float        x = 0, y = 0, fMaxWidth = 0;
          FontFamily[] aff = GetFontFamilyArray(grfx);

          foreach (FontFamily ff in aff)
          {
              Font  font  = CreateSampleFont(ff, iPointSize);
              SizeF sizef = grfx.MeasureString(ff.Name, font);

              fMaxWidth = Math.Max(fMaxWidth, sizef.Width);
          }
          foreach (FontFamily ff in aff)
          {
              Font  font    = CreateSampleFont(ff, iPointSize);
              float fHeight = font.GetHeight(grfx);

              if (y > 0 && y + fHeight > cy)
              {
                  x += fMaxWidth;
                  y  = 0;
              }
              grfx.DrawString(ff.Name, font, brush, x, y);

              y += fHeight;
          }
      }
      protected virtual FontFamily[] GetFontFamilyArray(Graphics grfx)
      {
          return FontFamily.Families;
      }
      Font CreateSampleFont(FontFamily ff, float fPointSize)
      {
          if (ff.IsStyleAvailable(FontStyle.Regular))
              return new Font(ff, fPointSize);

          else if (ff.IsStyleAvailable(FontStyle.Bold))
              return new Font(ff, fPointSize, FontStyle.Bold);

          else if (ff.IsStyleAvailable(FontStyle.Italic))
              return new Font(ff, fPointSize, FontStyle.Italic);

          else
              return Font;
      }
  }

В методе DoPage два цикла foreach. В первом определяется ширина названия каждой гарнитуры с соответствующим шрифтом и запоминается максимальная ширина. Второй цикл использует эту величину для построения колонок.

Обратите внимание на метод CreateSampleFont в конце тела класса. Я применяю его в методе DoPage вместо конструктора Font. CreateSampleFont с помощью метода IsStyleAvailable определяет, какое использовать начертание — нормальное, курсивное или полужирное. Это позволяет вывести на экран образец текста со шрифтом Aharoni, тогда как предыдущая программа не могла этого сделать. Вот результат работы программы на моем компьютере:


Рис. 9.11.

Если у вас установлены некоторые восточные шрифты, то вы заметите, что межстрочный интервал слишком большой для отображаемого текста. Это вызвано тем, что такие шрифты разработаны для вывода алфавитов, отличных от латинского.

В программе FamiliesList инструкция, получающая массив объектов FontFamily изолирована в небольшом методе, который я назвал GetFontFamilyArray. Это сделано для того, чтобы в следующей программе мне было проще продемонстрировать использование единственного статического метода, реализованного в FontFamily. Этот метод очень похож на свойство Families, за исключением наличия аргумента типа Graphics.


Статический метод FontFamily



FontFamily[] GetFamilies(Graphics grfx)


Идея здесь в том, что для различных графических устройств вывода могут быть установлены различные шрифты; в частности, у некоторых принтеров есть встроенные шрифты, которые не могут быть отображены на экране. Следующая программа переопределяет метод GetFontFamilyArray, чтобы получать массив гарнитур из GetFamilies, а не из Families.

GetFamiliesList.cs

  //------------------------------------------------
  // GetFamiliesList.cs (C) 2001 by Charles Petzold
  //------------------------------------------------
  using System;
  using System.Drawing;
  using System.Windows.Forms;

  class GetFamiliesList: FamiliesList
  {
      public new static void Main()
      {
          Application.Run(new GetFamiliesList());
      }
      public GetFamiliesList()
      {
          Text = "Font GetFamilies List";
      }
      protected override FontFamily[] GetFontFamilyArray(Graphics grfx)
      {
          return FontFamily.GetFamilies(grfx);
      }
  }

Для моего принтера GetFamilies возвращает тот же самый массив, что и Families. Возможно, в будущих версиях Windows Forms мы увидим более развернутую поддержку принтерных шрифтов.


netlib.narod.ru< Назад | Оглавление | Далее >

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