Симон Робинсон - C# для профессионалов. Том II
Невозможно использовать BitBlt для областей, которые не являются прямоугольными, что можно легко смоделировать. Один из способов состоит в пометке некоторого цвета как прозрачного для целей BitBlt поэтому данная область цвета в изображении-источнике не будет перезаписывать существующий цвет соответствующего пикселя на получающем устройстве. Можно также определить, что в процессе выполнения BitBlt каждый пиксель получающегося изображения будет сформирован перед BitBlt некоторой логической операцией (такой, как побитовое AND) на цветах этого пикселя в изображении-источнике и в получающем устройстве. Такие операции поддерживаются аппаратным ускорителем и могут использоваться для задания ряда тонких эффектов. Не рассматривая детали процесса, отметим что объект Graphics реализует другой метод DrawImage(). Он аналогичен методу DrawImageUnscaled(), но поставляется с большим числом перезагружаемых версий, которые позволяют определить более сложные формы BitBlt для использования в процессе рисования. DrawImage() позволяет также рисовать (BitBlt) только определенную часта изображения, или выполнить на нем некоторые другие операции, такие как масштабирование (увеличение или уменьшение размера) при его рисовании.
Рисование текста
Мы отложили рисование текста на экране до этого момента, так как эта очень важная тема является в целом более сложной задачей, чем рисование графики. Необходимо уточнить это утверждение. Вывод одной или двух строк текста без учета их вида является очень простым, требуя вызова одного из методов экземпляра Graphics, Graphics.DrawString(). Однако при попытке вывести документ, содержащий большое количество текста, быстро обнаруживается значительное усложнение процесса. Это обусловлено двумя причинами:
□ Первое: для получения аккуратного изображения необходимо понимать шрифты. Там, где для рисования фигуры используются кисти и перья в качестве вспомогательных объектов, процесс рисования текста требует соответственно шрифтов в качестве вспомогательных объектов. Понимание шрифтов является не простой задачей. В следующем разделе будет предоставлено краткое введение в предмет. Заметим, однако, что детали шрифтов являются более сложными, чем кистей и перьев.
□ Второе: текст необходимо очень аккуратно разместить в окне. Пользователя обычно ожидают слова, которые естественно следуют одно за другим выровненными с пробелами между словами. Сделать это труднее, чем кажется. Обычно заранее неизвестно, сколько места на экране потребуется для слова (в отличие от фигуры). Это должно вычисляться (не беспокойтесь, это не придется делать вручную, так как существует метод Graphics.MeasureString(), который это сделает). Также пространство занимаемое словом на экране, будет влиять на местоположение каждого последующего слова документа. Если приложение выполняет перенос строк, то ему придется тщательно оценивать размеры слов, прежде чем решить, где поместить разрыв. Посмотрев внимательно на работу Word for Windows, можно заметить, что Word непрерывно изменяет положение текста при вводе, изменении шрифта, вырезании, вставке, и т. д. При этом выполняется большая обработка, включающая некоторые очень тщательно отработанные алгоритмы. Конечно, проектируемое приложение GDI+ не обязательно должно быть таким же сложным, как Word, но если потребуется вывести произвольный текст, то многие из таких же рассмотрений будут по-прежнему в силе. Поэтому конечная часть этой главы посвящена примеру, допускающему простые манипуляции с текстом, чтобы дать некоторое представление о проблемах, которые возникают в подобных приложениях, и об их возможных решениях.
Обработка текста с хорошим качеством не является невозможной, она просто сложна для правильного выполнения. Как было упомянуто ранее, реальный процесс вывода строки текста на экран при условии знания шрифта и места вывода трудности не представляет. Поэтому далее будет дан краткий пример, показывающий, как выводить фрагменты текста. В оставшейся части главы вы найдете обзор некоторых принципов Fonts и Font Families, прежде чем мы перейдем к более реалистичному примеру обработки текста CapsEditor, который продемонстрирует аспекты размещения текста на экране, а также покажет, как обрабатывать пользовательский ввод.
Простой пример с текстом
Пример является обычным результатом работы Windows Forms. В этот раз метод OnPaint() переопределяется следующим образом:
protected override void OnPaint(PaintEventArgs e) {
Graphics dc = e.Graphics;
Brush blackBrush = Brushes.Black;
Brush blueBrush = Brushes.Blue;
Font haettenschweilerFont = new Font("Haettenschweiler", 12);
Font boldTimesFont = new Font("Times New Roman", 10, FontStyle.Bold);
Font italicCourierFont = new Font("Courier", 11, FontStyle.Italic | FontStyle.Underline);
dc.DrawString("This is a groovy string", haettenschweilerFont, blackBrush, 10, 10);
c.DrawString("This is a groovy string " +
"with some very long text that will never fit in the box", boldTimesFont, blueBrush,
new Rectangle(new Point(10, 40), new Size(100, 40)));
dc.DrawString("This is a groovy string", italicCourierFont, blackBrush,
new Point(10, 100)); base.OnPaint(e);
}
Выполнение этого примера создает вывод:
Этот пример демонстрирует использование метода Graphics.DrawString() для рисования элементов текста. Существует несколько перезагружаемых версий DrawString(), из которых показаны три. Все различные версии требуют параметры, указывающие выводимый текст, шрифт для рисования текста и кисть, которая должна использоваться для создания различных линий и кривых, составляющих символы текста. Для оставшихся параметров существуют альтернативы. В целом, однако, можно определить либо Point (или эквивалентно два числа), либо Rectangle. Если определяется Point, то текст начнется своим верхним левым углом в этой точке Point и развернется вправо. Если определить Rectangle, то экземпляр Graphics поместит строку внутри этого прямоугольника. Если текст не впишется в границы прямоугольника, то он будет обрезан, как видно на снимке экрана. Передача прямоугольника в DrawString() означает, что процесс рисования продолжится дольше, так как DrawString() необходимо определить, где поместить разрывы строки, но результат может выглядеть лучше (если строка вписывается в прямоугольник).
Этот пример показывает также способы создания шрифтов. Всегда требуется имя шрифта и его размер (высота). Можно также при желании передать различные стили, изменяющие вид текста (жирный, подчеркивание и т. д.).
Шрифты и семейства шрифтов
Все интуитивно считают, что достаточно хорошо понимают шрифты. В конце концов мы видим их почти постоянно. Шрифт точно описывает, как должна выводиться каждая буква. Выбор подходящего шрифта, а также предоставление разумного множества шрифтов в документе является важным фактором улучшения читабельности документа. Можно просто взглянуть на страницы этой книги, чтобы увидеть, сколько использовалось шрифтов. Нужно тщательно выбирать шрифты, поскольку плохой выбор шрифта может существенно повредить как привлекательности, так и использованию приложения. Многие при вопросе о названии шрифта скажут что-нибудь типа 'Arial' или 'Times New Roman' или 'Courier'. Фактически это не шрифты вообще, это семейства шрифтов. Шрифты будут чем-нибудь типа Arial 9-point italic. Семейство шрифтов сообщает в общих терминах визуальный стиль текста и является ключевым фактором в общем представлении приложения. Большинство людей способны распознавать стили наиболее распространенных семейств шрифтов, даже если и не осознают этого. Шрифт добавляет дополнительную информацию, определяя размер текста, а также применение к тексту определенных модификаций. Например, будет ли это жирный, курсив или подчеркнутый текст, выведется ли он ЗАГЛАВНЫМИ БУКВАМИ или как подстрочный индекс. Такие модификации технически называются стилями, хотя в некотором смысле термин вводит в заблуждение, поскольку только что было отмечено, что визуальное представление определяется в основном семейством шрифта.
Размер текста определяется его высотой. Высота измеряется в пунктах (points) — традиционная единица измерения, которая представляет 1/72 дюйма (для людей, живущих за пределами Великобритании и США, пункт равен 0.351 мм). Поэтому, например, буквы в 10-пунктовом шрифте имеют в высоту 10/72 дюйма (или приблизительно 1/7", или 3.5 мм). Из этого объяснения может показаться, что семь строк текста с размером шрифта 10 разместятся по вертикали на одном дюйме экрана или пространства бумаги. Фактически их будет немного меньше, так как необходимо также обеспечить интервалы между строками.
Строго говоря, измерение высоты не так просто, как может показаться, поскольку есть несколько различных высот, которые необходимо учитывать. Например, существует высота высокой буквы, такой как А или f (этот размер мы действительно имеем в виду, когда говорим о высоте), дополнительная высота, занимаемая любым акцентом над буквой типа Å или Ń (внутренняя высота строки), и дополнительная высота ниже базовой линии, необходимая для нижних частей букв типа у или g (спуск). Однако для данной главы это несущественно. Если определено семейство шрифтов и основная высота, такие дополнительные высоты задаются автоматически — нельзя независимо выбрать их значения.