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

Отсечение и подгонка текста

Используя версию метода DrawString с аргументом RectangleF, вы определяете не только правую границу текста, которая влияет на переносы, но и нижнюю — ограничивающую общее количество выводимого текста.

А если текста много и он не помещается в прямоугольник?

Рассмотрим сначала стандартный случай: когда объект StringFormat не используется в качестве последнего аргумента DrawString. Если высота прямоугольника равна целому числу межстрочных интервалов, целое число строчек текста сможет поместиться в прямоугольнике. Последняя строчка текста будет содержать столько знаков, сколько сможет поместиться по ширине прямоугольника. Именно знаков, а не целых слов. Чтобы увидеть, как все это выглядит, модифицируем программу HuckleberryFinn из главы 3, чтобы она ограничивала текст по ширине и по высоте до половины клиентской области.

HuckleberryFinnHalfHelght.cs

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

  class HuckleberryFinnHalfHeight: Form
  {
      public static void Main()
      {
          Application.Run(new HuckleberryFinnHalfHeight());
      }
      public HuckleberryFinnHalfHeight()
      {
          Text = "\"The Adventures of Huckleberry Finn\"";
          BackColor = SystemColors.Window;
          ForeColor = SystemColors.WindowText;
          ResizeRedraw = true;
      }
      protected override void OnPaint(PaintEventArgs pea)
      {
          Graphics  grfx = pea.Graphics;
          int       cx   = ClientSize.Width;
          int       cy   = ClientSize.Height;
          Pen       pen  = new Pen(ForeColor);
          Rectangle rect = new Rectangle(0, 0, cx / 2, cy / 2);

          grfx.DrawString(     
               "You don't know about me, without you " +
               "have read a book by the name of \"The " +
               "Adventures of Tom Sawyer,\" but that " +
               "ain't no matter. That book was made by " +
               "Mr. Mark Twain, and he told the truth, " +
               "mainly. There was things which he " +
               "stretched, but mainly he told the truth. " +
               "That is nothing. I never seen anybody " +
               "but lied, one time or another, without " +
               "it was Aunt Polly, or the widow, or " +
               "maybe Mary. Aunt Polly\x2014Tom's Aunt " +
               "Polly, she is\x2014and Mary, and the Widow " +
               "Douglas, is all told about in that book" +
               "\x2014which is mostly a true book; with " +
               "some stretchers, as I said before.", 
               Font, new SolidBrush(ForeColor), rect);

          grfx.DrawLine(pen, 0,      cy / 2, cx / 2, cy / 2);
          grfx.DrawLine(pen, cx / 2, 0,      cx / 2, cy / 2);
      }
  }

Программа также рисует линии, обозначающие границы выводимого текста.

Если области прямоугольника не хватает для целого абзаца, последняя строчка в клиентской области может заканчиваться частью слова:


Рис. 9.20.

При увеличении высоты прямоугольника приходит момент, когда DrawString решает, что места для еще одной строки текста уже достаточно. Это наступает быстрее, чем можно было бы предположить! Метод DrawString выводит дополнительную строку текста, когда высота прямоугольника увеличивается на 25% от размера межстрочного интервала. Последняя строчка обрезается по краю прямоугольника.


Рис. 9.21.

Хотя она большей частью обрезана, можно увидеть, что эта новая строчка также содержит часть слова — первые две буквы слова «mainly».

Изменить этот алгоритм по умолчанию позволяет свойство Trimming класса StringFormat:


Свойства StringFormat (выборочно)



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

StringTrimming Trimming Чтение/запись


Свойство Trimming определяет, как будет заканчиваться последняя строка при использовании метода DrawString с параметром RectangleF, когда размеров прямоугольника не хватает для всего текста. Это свойство принимает значение одного из членов перечисления StringTrimming, применяемого только при работе с этим свойством:


Перечисление StringTrimming



Член Значение Описание

None 0 Как если бы не было нижней границы.
Character 1 Последняя строка заканчивается символом.
Word 2 Последняя строка заканчивается словом.
EllipsisCharacter 3 Последняя строка заканчивается символом, за которым идет многоточие (...).
EllipsisWord 4 Последняя строка заканчивается словом, за которым идет многоточие (...).
EllipsisPath 5 Многоточие перед последней директорией.


Следующая программа иллюстрирует действие этих параметров.

TrimmingTheText.cs

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

  class TrimmingTheText:PrintableForm
  {
      public new static void Main()
      {
          Application.Run(new TrimmingTheText());
      }
      public TrimmingTheText()
      {
          Text = "Trimming the Text";
      }
      protected override void DoPage(Graphics grfx, Color clr, int cx, int cy)
      {
          Brush        brush  = new SolidBrush(clr);
          float        cyText = Font.GetHeight(grfx);
          float        cyRect = cyText;
          RectangleF   rectf  = new RectangleF(0, 0, cx, cyRect);
          string       str    = "Those who profess to favor freedom and " +
                                "yet depreciate agitation. . .want " +
                                "crops without plowing up the ground, " +
                                "they want rain without thunder and " +
                                "lightning. They want the ocean without " +
                                "the awful roar of its many waters. " +
                                "\x2014 Frederick Douglass";
          StringFormat strfmt = new StringFormat();

          strfmt.Trimming = StringTrimming.Character;
          grfx.DrawString("Character: " + str, Font, brush, rectf, strfmt);

          rectf.Offset(0, cyRect + cyText);

          strfmt.Trimming = StringTrimming.Word;
          grfx.DrawString("Word: " + str, Font, brush, rectf, strfmt);

          rectf.Offset(0, cyRect + cyText);

          strfmt.Trimming = StringTrimming.EllipsisCharacter;
          grfx.DrawString("EllipsisCharacter: " + str, 
                          Font, brush, rectf, strfmt);

          rectf.Offset(0, cyRect + cyText);

          strfmt.Trimming = StringTrimming.EllipsisWord;
          grfx.DrawString("EllipsisWord: " + str, 
                          Font, brush, rectf, strfmt);

          rectf.Offset(0, cyRect + cyText);

          strfmt.Trimming = StringTrimming.EllipsisPath;
          grfx.DrawString("EllipsisPath: " + 
                          Environment.GetFolderPath
                               (Environment.SpecialFolder.Personal),
                          Font, brush, rectf, strfmt);

          rectf.Offset(0, cyRect + cyText);

          strfmt.Trimming = StringTrimming.None;
          grfx.DrawString("None: " + str, Font, brush, rectf, strfmt);
     }
}

Эта программа определяет объект RectangleF с высотой, достаточной для размещения только одной строки текста. Программа выводит текст, используя шесть возможных значений StringTrimming. Текст представляет собой цитату из Фредерика Дугласа для всех значений, кроме StringTrimming.EllipsisPath, где статический метод Environment.GetFolderPath служит для получения пути к папке My Documents (Мои документы). Можно изменить ширину окна и посмотреть, как это влияет на текст. Вот его типичный вид:


Рис. 9.22.

EllipsisCharacter и EllipsisWord выводят многоточие (...) в конце строки, показывая, что для вывода строки не хватает места. Character и EllipsisCharacter могут вывести в конце строки только часть слова.

Член EllipsisPath перечисления StringTrimming предназначен специально для вывода названия пути к файлу. Заметьте, что многоточие содержится в середине текста для того, чтобы можно было увидеть и начало, и конец пути.

Хотя None и Word привели к одинаковому результату, между ними есть разница, и мы увидим ее позднее.

Если в программе изменить значение cyRect с

  float cyRect = cyText;

на

  float cyRect = 1.5f * cyText;

и перекомпилировать программу, то в результате получим такое изображение:


Рис. 9.23.

Метод DrawString выводит теперь две строки текста, и, хотя вы не можете увидеть большую часть второй строки, ее вид определяется свойством Trimming.

Теперь посмотрим, как на вид текста влияет флаг NoWrap перечисления StringFormatFlags. Добавьте после создания объекта StringFormat, но перед вызовом метода DrawString следующую инструкцию:

  strfmt.FormatFlags |= StringFormatFlags.NoWrap;

Или можно выставить флаг в конструкторе StringFormat:

  StringFormat strfmt = new StringFormat(StringFormatFlags.NoWrap);

Как можно понять из названия, флаг NoWrap запрещает автоматический переход на новую строку в DrawString.

Текст все еще обрезается по правому краю прямоугольника. Но теперь ясно видно (если вы не сделали правую границу меньше клиентской области), что в случае StringTrimming.None последняя буква частично обрезается по правой границе.

Мы столкнулись с первым случаем, когда выводится часть буквы:


Рис. 9.24.

А теперь уберем флаг NoWrap, вернее, заменим его флагом NoClip:

  strfmt.FormatFlags = StringFormatFlags.NoClip;

который предписывает методу DrawString не отсекать текст, не помещающийся в прямоугольнике. В результате для любого значения перечисления, кроме StringTrimming.None, выводятся две полных строки текста:


Рис. 9.25.

Для случая с StringTrimming.None теперь выводится весь текст. Комбинация этого значения перечисления и флага NoClip устраняет эффект отсечения текста по нижней границе прямоугольника.

Если установить оба флага:

  strfmt.FormatFlags |= StringFormatFlags.NoClip;
  strfmt.FormatFlags |= StringFormatFlags.NoWrap;

то для всех значений StringTrimming, кроме None, результат будет таким же, как с флагом NoWrap. В случае с StringTrimming.None текст не переносится и может уходить за правую границу. Ситуация такая же, как если бы вы в методе DrawString указали аргумент типа PointF, a не RectangleF.

При выводе текста в прямоугольную область, надо следить за отсечением текста. Если высота прямоугольника будет равна целому числу межстрочных интервалов, проблемы с отсечением текста не будет. Вероятно, это лучшее решение. Иначе вы должны установить флаг NoClip для предотвращения отсечения. Однако тогда последняя строчка текста может частично выйти за нижнюю границу прямоугольника. В некоторых случаях (например, когда высота прямоугольника равна высоте клиентской области) последняя строчка текста будет всегда отсекаться, так как она достигает границы клиентской области. Убедитесь, что высоты прямоугольника хватает для вывода всех строк текста.

Если вы создаете объект StringFormat, используя конструктор по умолчанию:

  StringFormat strfmt = new StringFormat();

или вы создаете его с помощью статического свойства StringFormat:

  StringFormat strfmt = StringFormat.GenericDefault;

свойству Trimming изначально присвоено значение StringTrimming.Character. Если вы создаете объект StringFormat, используя статическое свойство:

  StringFormat strfmt = StringFormat.GenericTypographic;

свойству Trimming изначально присвоено значение StringTrimming.None, и выставлен флаг NoClip.


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

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