Среда, 20.09.2017, 21:27
Приветствую Вас Гость | RSS

Лекции

Меню сайта
Форма входа
Категории раздела
ТАУ (Теория автоматического управления) [31]
лекции по ТАУ
Экология [151]
учебник
Бухгалтерский учет и налогообложение в строительстве [56]
Дементьев А.Ю. - Практическое пособие
Психология [104]
Пип
информатика [80]
с# Карли Ватсон
современные стулья [0]
новинки
Поиск
Главная » 2010 » Февраль » 11 » Введение в GDI+
00:38
Введение в GDI+
Введение в GDI+
Настоящая глава является введением в программирование с использованием
классов Graphics Device Interface (GDH интерфейс графических устройств).
Приложения с графикой, игры, Computer Aided Design/Computer Aided Manufacture
(CAD/CAM — проектирование/производство с помощью компьютера), программы
для рисования, для создания графиков и многие другие типы приложений требуют
от разработчиков написания кода для работы с графикой. Использование создава-
емых пользователем управляющих элементов также предполагает работу с графи-
кой. Посредством своей последней библиотеки классов компания Microsoft сделала
написание кода для работы с графикой как никогда простым.
Писать код для работы с графикой — это наибольшее удовольствие из всех
программистских задач. Это очень здорово, когда ты вносишь изменения в про-
грамму и тут же наглядно видишь результаты этих изменений. Если вы создаете
собственное графическое окно, в котором нечто представляется новым, оригиналь-
ным способом, или, если вы создаете собственный управляющий элемент, который
облегчит использование вашего приложения и сделает его более приятным, то это
будет благосклонно приниматься широкой публикой.
Сначала объясним механизм рисования с помощью GDI+ и напишем несколь-
ко простых примеров графических программ. А затем рассмотрим с точки зрения
высокого уровня некоторые дополнительные возможности GDI + , включая:
• Работу с отдельными частями рисунков
• Вывод на печать
• Предварительный просмотр
• Пространство имен Drawing2D
• Пространство имен Imaging
После этого мы познакомимся с классами, которые необходимо использовать
для реализации этих возможностей, а также укажем литературу для дальнейшего
изучения. Знание возможностей и понимание иерархии классов — это уже поло-
вина успеха.
Обзор вывода графической информации
Первое, что необходимо усвоить при написании графического кода, это то, что
Microsoft Windows не запоминает, каким образом выглядит данное графическое
окно, если оно заслоняется другими окнами. Если закрытое ранее окно оказывается
Введение в GDI+ 427
на переднем плане и становится видимым, то система Windows сообщает нашему
приложению: "Ваше окно (или некоторая его часть) становится видимым. Не буде-
те ли так любезны нарисовать его?". На приложение возлагается только задача
рисования содержимого окна. Вывод границ окна, линейки с заголовком и прочих
графических составляющих самого окна система Windows возьмет на себя.
С точки зрения программирования когда мы создаем окно, в котором собираем-
ся что-либо нарисовать, то мы, скорее всего, объявляем класс, который является
производным от System.windows.Forms.Form. Если мы создаем собственный управ-
ляющий элемент, мы должны объявить класс, который является производным от
System.windows.Form.userControi. В обоих случаях придется переопределять вир-
туальную функцию onPaint (). В Windows будет происходить обращение к этой
функции всякий раз, когда возникает необходимость повторного рисования любой
части окна.
При наступлении этого события класс PaintEventArgs передается в качестве
аргумента. Представляют интерес два элемента информации, содержащейся в
PaintEventArgs,— объекты Graphics И ClipRectangle (вырезанный ПрямоугОЛЬ-
ник). Класс Graphics — это следующая тема, которую мы будем изучать. Вопроса
вырезания частей рисунка мы коснемся в общих чертах ближе к концу главы.
Класс Graphics
В классе Graphics инкапсулированы поверхности рисования GDI+. Есть три
основных типа поверхностей рисования:
• Окна и управляющие элементы на экране
• Страницы, посылаемые на принтер
• Растровые изображения в памяти
В классе Graphics предусмотрены функции, которые позволяют рисовать на
любой из этих поверхностей. Этот класс позволяет также рисовать дуги, кривые,
кривые Безье (Bezier), эллипсы, рисунки, прямые, прямоугольники и текст.
Объект Graphics для некоторого окна можно получить двумя путями. Первый
заключается в переопределении события onPainto — виртуального метода, кото-
рый класс Forms наследует от класса control. В этом случае объект Graphics мы
получаем из PaintEventArgs, который передается вместе с событием:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
// Рисуем здесь •:
В некоторых ситуациях может потребоваться выполнять рисование в окне не-
посредственно, не дожидаясь наступления события OnPainto. Это может оказать-
ся актуальным в том случае, если мы создаем код, предназначенный для выбора
в окне каких-либо графических объектов (аналогичный выбору иконок в Windows
Explorer), либо переносим некий объект с помощью мыши. В этом случае доступ
К Объекту Graphics МОЖНО ПОЛуЧИТЬ, обращаясь К методу CreateGraphicsO данной
формы, который представляет собой еще один метод, наследуемый классом Forms
от класса Control:
428 Глава 16
protected void Forml_Click(object sender, System.EventArgs e)
Graphics g = this.CreateGraphics();
// Рисуем здесь
••••• :g.. D i s p o s e : ( ) • ; • • // Э т о в а ж н ы й м о м е н т
}
Создание приложения, позволяющего переносить мышью и размешать графи-
ческие объекты, оказывается весьма непростым предприятием, рассмотрение ко-
торого выходит за рамки настоящей главы. Использование названного способа
встречается значительно реже. На начальных этапах мы будем почти всегда вы-
полнять рисование в качестве реакции на наступление события onPaint ().
Существуют также и другие способы получения объекта Graphics, но к их рас-
смотрению мы вернемся несколько позже.
Удаление объектов
Всегда вызывайте метод Dispose о для графических объектов.
Каждому из нас знакомо поведение Windows в тех случаях, когда ресурсы
оказываются исчерпанными. Система начинает работать очень медленно,
при этом приложения зачастую рисуются неправильно. Грамотно организованные
приложения должны освобождать используемые ими ресурсы сразу же,
как только они становятся ненужными. При разработке с использованием
.NET Framework существует несколько типов данных, для которых обращение
к методу Dispose о оказывается очень важным, поскольку в противном случае
определенные ресурсы никогда не будут освобождены. Эти классы реализуют
интерфейс iDisposabie. Класс Graphics является одним из таких классов.
Вызов метода Dispose о оказывается важным, однако, если мы получаем
объект Graphics посредством обращения К Методу CreateGraphicsO.
Когда >АЫ получаем объект Graphics от события OnPaint о , то этот объект
создается не нами, и, соответственно, ответственность за вызов метода Dispose о
также лежит не на нас, а в предшествующем примере эта ответственность
возлагается именно на нас.
Вызов метода Dispose о выполняется автоматически в деструкторе различных
классов, в которых реализуется интерфейс iDisposabie. Возможно, вы подумали,
что это освобождает вас от ответственности за вызов метода Dispose о , однако это
не так. Причина такого положения вещей заключается в том, что деструктор может
быть вызван только сборщиком мусора (GC, garbage collector), а заранее никогда
не известно, в какой момент GC будет запущен. В частности, на операционной
системе Windows 9X, использующей большие объемы памяти, GC может запус-
каться очень редко, и все ресурсы могут прекрасно использоваться до того, как GC
будет запущен. Исчерпание памяти приводит к запуску GC, а вот исчерпание дру-
гих ресурсов — нет. Система Windows 2000 оказывается гораздо менее чувствитель-
ной к исчерпанию ресурсов. В соответствии со спецификациями в Windows 2000
не существует каких-либо конкретных ограничений на эти типы ресурсов; автору,
тем не менее, приходилось сталкиваться с ситуацией, когда эта операционная сис-
тема начинала работать неправильно из-за большого количества открытых в ней
приложений, при этом закрытие нескольких приложений приводило к быстрому
восстановлению работоспособности системы. В любом случае, более правильным
стилем программирования является удаление всех "жадных до ресурсов" объектов
на регулярной основе.
Введение в GDI+ 429
В версии .NET Framework Beta предусмотрена новая конструкция, которая мо-
жет использоваться для принудительного обращения к методу Dispose о . Конст-
рукция using автоматически запускает метод DisposeO, как только происходит
выход из области действия данного объекта. Следующий код представляет собой
пример правильного использования ключевого слова using в этом контексте:
using {Graphics g = this.CreateGraphics())
Ш. {
g.DrawLine{Pens.Black,new Point(0,0) ,
new Point(3, 5));
}
В соответствии с документацией этот код абсолютно эквивалентен следующему:
Graphics g = t h i s . C r e a t e G r a p h i c s (•).;
V :•••: ' ' . • • '• t r y : { • • • • . : • . ••• . - , .;••••:•;-;: \ •" ;• ' :•' '
g.DrawLine(Pens.Black, newPoint(0, 0),
new Point(3, 5));
}
finally {
if (g i= null)
((IDisposable)g).Dispose ()•;•
}
He следует путать использование ключевого слова using в этом контексте с ис-
пользованием его в качестве директивы, которая приводит к созданию нового име-
ни пространства имен или позволяет использовать типы, описанные в некотором
пространстве имен, без необходимости применять полностью квалифицированные
имена. Это совершенно особый случай использования ключевого слова using.
В примерах, приводимых в настоящей главе, используются оба способа обра-
щения к методу DisposeO. Иногда мы будем вызывать метод Dispose о непосред-
ственно, а иногда прибегать к использованию конструкции using. Второй способ —
это гораздо более наглядное решение, что видно из приведенных выше отрывков
программ, хотя не существует никаких рекомендаций относительно того, какой из
этих двух способов является более предпочтительным.
Перед тем как перейти к созданию первого примера, нам необходимо изучить
два других аспекта рисования — систему координат и цвета.
Система координат
При разработке программы, которая должна осуществлять вывод сложной гра-
фики, представляется очень важным, чтобы код рисовал только то, что необходи-
мо, и ничего больше. Даже один нарисованный в неправильном месте пиксель
может оказать негативное влияние на восприятие целого изображения, поэтому
необходимо понимать, какие именно пиксели будут рисоваться при выполнении тех
или иных графических операций. Особую важность это имеет при создании собст-
венных управляющих элементов, которые обычно состоят из большого количества
прямоугольников, а также вертикальных и горизонтальных линий. Стоит при рисо-
вании линии захватить один лишний пиксель или наоборот — нарисовать линию
на один пиксель короче, как это тут же становится очень заметным. Такие ошибки
несколько менее заметны в случае вывода кривых, диагоналей и некоторых других
графических элементов.
В GDI+ используется система координат, построенная на основе воображае-
мых математических прямых, которые проходят через центры пикселей. Эти пря-
мые пронумерованы начиная с 0: пересечение этих прямых в левом верхнем
пикселе имеет координаты X = 0, Y = 0 во всех координатных пространствах.
430 Глава 16
В упрощенной нотации можно говорить о точке (1,2), что является сокращенным
вариантом записи X = 1, Y = 2. Каждое окно, в котором будут выводиться какие-
либо графические объекты, обладает своим координатным пространством. Если
создать собственный управляющий элемент, который в дальнейшем будет исполь-
зоваться в других окнах, то такой элемент также будет обладать своей системой
координат. Другими словами, при выводе графических объектов в этом элементе
его левый верхний угол будет иметь координаты 0, 0. И неважно, в каком месте
содержащего его окна он будет располагаться.
При рисовании прямых GDI+ центрирует пиксели,
находящиеся на заданной математической прямой.
Рисование горизонтальной прямой с целыми коор-
динатами можно представить себе как проведение
воображаемой математической линии таким образом,
что половина пикселя оказывается расположенной
выше нее, а вторая половина — ниже. Для рисования
горизонтальной прямой, толщина которой составля-
ет один пиксель и которая начинается в точке 1, 1
и заканчивается в точке 1, 5, будут использованы
пиксели, закрашенные на рисунке слева черным.
При рисовании вертикальной прямой толщиной
в один пиксель и длиной в четыре пикселя из точки 2, 1
в точку 2, 4 будут закрашены пиксели, как на рисунке
справа.
• о
1
2
3
5
0
I
...:.
,J..
•5: /
........
:•
i
I 2
Ц s ;
*' " ' ' • f
3
;J,
gJ
L
| i ;
4
i
• • s I i
| i«
.....1.
r
Ш
г
5 6 - ' 7
Iff!
. ,l,,:,,,:4..,,.
•f-4m ••;: •;•>:•:
Л:,.,,.;;:.:',::.;:г::.
• ^••••••:-;
: i - 1 - - . ; I
; ; - : Г ' - . ;:•:.;i-: :i.:;..-': :•' ";•:•: i
' • • ' <
• .
. , ; : ; .•;
:-r.-r;.. ;
Если мы рисуем диагональную линию между точ-
ками 1, 0 и 4, 3, то закрашенными окажутся пиксели,
как показано на рисунке слева.
•JJ
В№Ц
Прямоугольник, верхний левый угол которого распо-
лагается в точке 1, 0 и который имеет размеры 5, 4,
будет нарисован так, как это изображено на рисунке
справа.
Заметим, что ширина прямоугольника была зада-
на равной 5 пикселям, но на рисунке в горизонталь-
ном направлении оказались закрашенными 6 пикселей.
Однако если подсчитать количество математических
прямых, проходящих через составляющие заданный
прямоугольник пиксели, то можно убедиться, что
-я-
асстояние <
Введение в GDI+ 431
ширина прямоугольника составляет как раз пять пикселей, а проведенная линия
оставляет одну половину пикселя снаружи заданной математической прямой,
а вторую — внутри.
Если линия будет рисоваться в режиме сглаживания, то некоторые пиксели бу-
дут закрашиваться только наполовину, создавая иллюзию непрерывной линии
и позволяя частично избавиться от представления диагональных линий в виде "ле-
сенки".
Вот как выглядит линия, нарисованная без использова-
ния сглаживания (см. рис. слева).
А на рисунке справа показана та же линия, нарисован-
ная с использованием сглаживания.
При выводе с большим разрешением эта линия будет выглядеть гораздо более
плавной, без "лесенки".
Понимание взаимосвязи между координатами, передаваемыми графическим
функциям, и эффектом, к появлению которого на поверхности рисования это при-
ведет, позволяет точно представлять, какие именно пиксели будут задействованы
при данном вызове графической функции.
Существуют три структуры, которые мы будем наиболее часто использовать
ДДЯ Задания координат При рисовании: Point (точка), Size (размер) И Rectangle
(прямоугольник).
Point
В GDI+ Point используется для представления отдельной точки. Это точка,
расположенная на двумерной плоскости, которая определяет единственный пик-
сель. МНОГИМ фуНКЦИЯМ, ИСПОЛЬЗУЮЩИМСЯ В GDI + , таКИМ как DrawLineO, Point
передается в качестве аргумента. Мы объявляем и определяем точку следующим
образом:
Point p = new Point (1, 1);
У точки Point имеются общие свойства, которые позволяют узнавать и зада-
вать ее координаты X и Y.
Size
size в GDI+ используется для представления размера, выраженного в пиксе-
лях. Структура size определяет как ширину, так и высоту. Мы объявляем и опре-
деляем size следующим образом:
Size s = new Size(5, 5);
Узнавать и задавать ширину и высоту, определяемую структурой size, можно
с помощью соответствующих общих свойств.
Rectangle
Эта структура используется в GDI+ во многих различных местах для задания
координат прямоугольников. Структура Point описывает верхний левый угол пря-
моугольника, а структура size — его размеры. У Rectangle есть два конструктора.
Одному конструктору в качестве аргументов передаются координаты X, У — ширина
432 Глава 16
и высота. Второй конструктор принимает структуры Point и size. Ниже приводятся
два примера объявления И СОЗДаНИЯ структуры Rectangle:
Rectangle rl = new Rectangle(1, 2, 5, 6);
;; Point p = new Point (1, 2);
Size s = new Size (5 , 6); —
Rectangle r2 = new Rectangle (p, s) ;
Для определения и задания всех составляющих местоположения и размеров
прямоугольника используются общие свойства. Кроме того, существуют и другие
свойства и методы, которые позволяют осуществлять разные полезные вещи, на-
пример, проверять является ли прямоугольник пустым, определять, пересекается
данный прямоугольник с каким-либо другим прямоугольником, а также получать
пересечение и объединение двух прямоугольников. Подробнее эти вопросы осве-
щены в разделе, посвященном структуре Rectangle в .NET Framework Reference
(руководство по .NET Framework).
Структуры GraphicsPath
Есть два других, более важных типа данных, которые могут использоваться
в качестве аргументов, передаваемых различным функциям графического вывода
в GDI-K Класс GraphicsPath (графический путь) представляет собой последова-
тельность соединенных между собой прямых и кривых. Для создания графического
пути могут использоваться прямые, кривые Безье, дуги, секторы, многоугольники,
прямоугольники и многое другое. После определения сложного пути можно вывес-
ти его на экран посредством одной операции — обратившись к методу DrawPath ().
Для наполнения пути можно использовать метод FiliPathO.
Для создания структуры GraphicsPath используется массив точек и массив
pathTypes — массив байтов, в котором каждый элемент соответствует элементу
из массива точек и содержит информацию о том, как следует строить графический
путь через данную точку. Например, если точка является начальной точкой пути,
то тип пути для этой точки будет иметь значение PathPointType.start. Если эта
точка является точкой соединения двух линий, то тип пути для этой точки будет
иметь значение PathPointType.Line. Если точка используется для создания кривой
Безье между двумя точками, то тип пути для этой точки будет иметь значение
PathPointType.Bezier.
Ниже приводится пример программы, которая создает графический путь, состо-
ящий из четырех прямых участков:
GraphicsPath path;
path = new GraphicsPath (new Point []{
new Point(10, 10),
: new Point(150, 10),
new Point(200, 150),
new Point(10, 150),
new Point(200, 160)
}, new byte[}{
V (byte)PathPointType.Start,
(byte)PathPointType.Line,
(byte)PathPointType.Line,
(byte)PathPointType.Line,
• • . (byte)PathPointType.Line,
) ' • • ' • '" ' , ' . •••
• ^ • • • • • • • ^ • • • . : , : • • • • '."•• ); ' v:.
e.Graphics.DrawPath(Pens.Black, path);
Введение в GDI+ 433
Линия, которая будет нарисована с по-
мощью данного пути, показана на рисунке
справа.
Код, понадобившийся дая создания та-
кого пути, оказывается достаточно слож-
ным. КоНСТруКТОр GraphicsPath принимает
два аргумента. Первый из них — это мас-
сив структур Point, создаваемый непосред-
ственно здесь же. Для этого используется
принятый в С# синтаксис, позволяющий
объявлять и инициализировать массивы.
Мы последовательно вызываем конструк-
торы для каждой точки:
new Point [•]•{
new Point(10, 10),
new Point(150, 10),
new Point(200, 150),
new Point(10, 150),
new Point(200, 160)
В качестве второго аргумента используется массив байтов, который создается
во вторую очередь:
n e w - b y t e [ ] •{•
(byte)PathPointType.Start,
(byte)PathPointType.Line,
(byte)PathPointType.Line,
(byte)PathPointType.Line,
(byte)PathPointType.Line,
В завершение, в приведенном выше примере мы вызываем метод DrawPatho:
е.Graphics.DrawPath(Pens.Black, path);
Области
Класс Region представляет собой сложную графическую форму, которая состо-
ит из прямоугольников и путей. После того как структура Region создана, она мо-
жет быть выведена с помощью метода FiiiRegionO.
Следующая программа создает область, добавляет в нее сначала Rectangle, за-
тем GraphicsPath, после чего заполняет эту область синим цветом:
Rectangle rl = new Rectangle(10, 10, 50, 50) И
Rectangle r2 = new Rectangle(40, 40, 50, 50);
Region r = new Region (rl) ;
r.Union(r2);
GraphicsPath path = new GraphicsPath (new Point [] { ':;:;
new Point(45, 45),
new Point(145, 55),
new Point(200, 150),
new Point(75, 150),
new Point(45, 45)
}, newbyte[] {
(byte)PathPointType.Start,
: (byte)PathPointType.Bezier,
(byte)PathPointType.Bezier,
434 Глава 16
(byte)PathFointType.Bezier,
(byte) PathPointType. Line ,-'••
r«Union(path);
e.Graphics.FlllRegion(Brushes.Blue, r) ;
Этот код позволяет нарисовать форму, показанную на ри-
сунке слева.
Код, необходимый для создания области, оказывается до-
статочно сложным, что связано с построением путей, которые
потом пройдут через данную область. Создание области вклю-
чает в себя построение прямоугольников и путей с последую-
щим вызовом метода union о (объединение). Если требуется
изобразить пересечение пути и прямоугольника, то можно
ИСПОЛЬЗОВатЬ ВМеСТО метода Union() метод Intersection()
(пересечение).
Более подробная информация о графических путях и об-
ластях не является необходимой для ознакомления с GDI+.
Ее можно почерпнуть в .NET Framework Reference (Руковод-
ство по .NET Framework).
Цвета
Большая часть графических операций в GDI + предполагает выбор некоторого
цвета. Например, при рисовании линии или прямоугольника необходимо указы-
вать, каким цветом они должны рисоваться.
В GDI4- цвета инкапсулированы в структуру color. Можно синтезировать цвет,
передавая значения составляющих его красного, зеленого и синего цветов некото-
рой функции структуры Color, но необходимость в этом возникает крайне редко.
В структуре color содержится приблизительно 150 различных свойств, которые
предоставляют широкий выбор заранее определенных цветов. Забудьте о красном,
зеленом, синем, желтом и черном! Если требуется вывести какой-либо графиче-
ский объект цветом LightGoldenrodYellow (светло- золотисто -желтый) или цветом
LavenderBiush (бледно-лилово-розовый), то такие цвета заранее описаны специаль-
но для нас! Нам необходимо описать переменную типа color и присвоить ей в ка-
честве начального значения цвет, описанный в структуре color таким образом:
Color redColor - Color.red;
Color anotherColor = Color.LightGoldenrodYellow;
Мы уже практически готовы к тому, чтобы нарисовать что-нибудь, однако
прежде необходимо сделать пару замечаний.
Цвета могут представляться в двух различных видах. Один из них — это RGB.
Второй заключается в разбиении цвета на три компонента — Saturation (насы-
щенность), Hue (оттенок) и Brightness (яркость). В структуре color имеются спе-
циальные методы, которые позволяют осуществлять такое разбиение,— GetHueO,
GetSaturation() И GetBrightness().
Для того чтобы поэкспериментировать с цветами, можно воспользоваться при-
ложением Paint. Выберите в меню пункт Color | Edit Colors. Нажмите кнопку Define
Custom Colors (определение собственных цветов), и перед вами появится диалого-
вое окно, которое позволит выбирать цвет с помощью мыши и получать для него
соответствующие значения RGB. Существует также возможность получить для
выбранного цвета значения Hue, Saturation и Luminosity (Luminosity в данном
Введение в GDI+
435
случае — это то же самое, что Brightness). Кроме того, есть возможность непо-
средственно вводить значения RGB и наблюдать получаемый в результате цвет.
Цвета в GDI-f обладают еще четвертым компонентом — компонентом Alpha,
с помощью которого можно задавать затененность цвета, что позволяет создавать
эффекты "из затемнения"/"в затемнение". Такие эффекты используются в меню
Windows 2000. В данной главе использование компонента Alpha рассматриваться
не будет.
Вывод линий с помощью класса Реп
Первый пример будет посвящен рисованию линий. Мы будем рисовать линии
с помощью класса Реп, определяющего цвет, толщину и образец линии, которая
рисуется программой. Предназначение свойств Color (цвет) и Width (толщина)
очевидны, а образец позволяет определять, требуется ли нарисовать сплошную
линию или линию, состоящую из черточек и точек. Класс Реп находится в про-
странстве имен System.Drawing.
Практикум; Пример использования класса Реп
Запустите Visual Studio.NET и создайте новое С# Windows Application. При со-
здании нового проекта Visual Studio.NET создает также и новую пустую форму для
этого проекта, которая получает имя Formi. В модуле Formi.cs содержится код,
предназначенный ддя этой формы. Щелкните на форме правой кнопкой мыши
и выберите пункт View Code из открывшегося меню. В качестве альтернативы
можно щелкнуть правой кнопкой мыши на Formi.cs в Solution Explorer, чтобы вы-
брать пункт View Code из открывшегося меню. Добавьте в Formi. cs следующий код:
protected override void OnPaint(PaintEventArgs e)
{ - • ;; . " •
Graphics g = e.Graphics;
using (Pen blackPen = new Pen (Color. Black, 1))
{ *•'"* • ' '
for (int у = 0; у < ClientRectangle.Height;
у += ClientRectangle.Height /10)
• { •
g.DrawLine(blackPen, new Point(0, 0),
new Point(ClientRectangle.Width, y) ) ;
Теперь нажмите F5 и запустите программу. В результате
работы этой программы будет создано окно, представленное
на рисунке слева.
Как это работает
В приведенной выше программе в самом начале метода
создается экземпляр класса Graphics, для инициализации ко-
торого ИСПОЛЬЗуетСЯ класс PaintEventArgs:
Graphics g = е.Graphics;
Поскольку мы получаем ссылку на объект Graphics и нам
не приходится создавать его самим, то нет необходимости
явно вызывать для него метод Dispose о . Поскольку в данном
436 Глава 16
примере мы используем потенциально потребляющий много ресурсов объект реп,
то весь остальной код мы помещаем внутрь конструкции using;, что гарантирует
уничтожение объекта при первой же возможности.
При создании объекта Реп мы передаем его конструктору в качестве парамет-
ров цвет и ширину линии. В данном примере в качестве цвета выбран черный,
а ширина устанавливается равной единице. Вот строка кода, предназначенная для
создания этого объекта:
u s i n g (Pen blackPen = new Pen (Color .Black, 1))
Каждое окно, в котором что-либо рисуется, обладает пользовательской обла-
стью, обрамляемой границей и в точности соответствующей области, в которой
может располагаться рисунок. Получить пользовательскую область можно с помо-
щью ciientRectangie — общего свойства формы, доступного в режиме "только
чтение" (которое наследуется от класса control). В нем содержатся размеры (ши-
рина и высота) пользовательской области окна, в которую осуществляется графи-
ческий ВЫВОД. Следующий КОД Обращается К СВОЙСТВУ CiientRectangie:
for (int у = 0; у < CiientRectangie.Height;
у += CiientRectangie.Height / 10)
При рисовании каждой линии только что созданному объекту Реп передаются
начальная точка и конечная точка этой линии:
g.DrawLine(blackPen, new P o i n t ( 0 , 0 ) ,
new P o i n t ( C i i e n t R e c t a n g i e . W i d t h , y)) ;
Всегда ВЫЗЫВаЙте МетОД Dispose О ДЛЯ Объектов Pen.
! Как И ДЛЯ объектов Graphics, н е о б х о д и м о либо ВЫЗЫВаТЬ МеТОД Dispose ( )
i для объектов Реп после завершения его использования, либо использовать
для работы с ними конструкцию using, в противном случае приложение
может исчерпать ресурсы системы.
В данном примере мы используем объект Реп. Однако существует более про-
стая возможность получить такой объект. Класс Pens содержит свойства, необхо-
димые для получения приблизительно 150 объектов Реп — по одному на каждый
из предварительно описанных цветов. Следующая версия нашего примера работает
аналогично предшествующей, только вместо создания объекта Реп мы извлекаем
его из класса Pens:
protected override void OnPaint(PaintEventArgs e)
{ :
for (int у = 0; у < CiientRectangie.Height;
у += CiientRectangie.Height / 10)
{ - • • . • . . .
e.Graphics.DrawLine(Pens.Black, new Point(0, 0}, :
new Point(CiientRectangie.Width, y) ) ;
В данном случае объект Реп создается не нами, поэтому нет необходимости вы-
зывать метод Dispose().
Введение в GDI+ 437
Рисование фигур с помощью класса Brush
Следующий пример посвящен использованию класса Brush (кисть) для рисова-
ния различных фигур, таких как прямоугольники, эллипсы, секторы и многоуголь-
ники. Класс Brush — это абстрактный класс. Для создания экземпляра класса
Brush МЫ ИСПОЛЬЗуем КЛаССЫ, прОИЗВОДНЫе ОТ Класса Brush, такие как SolidBrush,
TextureBrush И LinearGradientBrush. Класс Brush находится В Пространстве имен
System.Drawing. Классы TextureBrush И LinearGradientBrush находятся В про-
CTpaHCTBe имен System.Drawing.Drawing2D. Вот ЧТО ПОЗВОЛЯет делать КЭЖДЫЙ ИЗ
этих классов:
• SolidBrush заполняет фигуру сплошным цветом.
• TextureBrush позволяет заполнять фигуру рисунком, хранящемся
в двоичном представлении. При создании такой кисти требуется
также задавать обрамляющий прямоугольник и режим обрамления.
Обрамляющий прямоугольник определяет, какую порцию рисунка мы
должны использовать при рисовании,— использовать весь рисунок
целиком совершенно необязательно. Для режима обрамления существует
несколько возможностей, включая Tile (черепица) — TileFiipx,
TileFiipY и TileFiipXY, позволяющих последовательно разбивать
изображение на Отдельные квадраты. С ПОМОЩЬЮ TextureBrush МОЖНО
создавать очень интересные и весьма впечатляющие эффекты.
• LinearGradientBrush СОДерЖИТ КИСТЬ, КОТОрая ПОЗВОЛЯет рИСОВаТЬ
плавный переход от одного цвета к другому, причем первый цвет
переходит во второй под определенным углом. Углы при этом задаются
в градусах. Угол, равный 0°, означает, что переход от одного цвета
к другому осуществляется слева направо. Угол, равный 90°, означает,
что переход от одного цвета к другому осуществляется сверху вниз.
Существует еще одна разновидность кисти — PathGradientBrush, позволяющая
создавать сложный эффект затенения, при котором используется изменение цвета
от середины рисуемого пути к его краям. Более детально ознакомиться с этим
классом вы можете в разделе PathGradientBrush .NET Framework Reference (руко-
водство no .NET Framework).
Всегда вызывайте метод Dispose () ДЛЯ объектов Brush.
Как И ДЛЯ объектов Graphics И Pens, необходимо либо вызывать меТОД Dispose ()
для создаваемых нами объектов Brush, либо использовать для работы с ними
конструкцию using, в противном случае приложение может исчерпать
ресурсы системы.
Практикум: пример использования класса Brush
Запустите Visual Studio.NET и создайте новое С# Windows Application. Щелк-
ните на форме правой кнопкой мыши и выберите пункт View Code из открывшего-
ся меню. Найдите конструктор класса Formi и добавьте в него обращение к методу
SetStyleO сразу за Обращением К методу InitializeComponent (). SetStyleO —
438 _____ Глава 16
это функция класса Form. Видоизмененный конструктор будет выглядеть следую-
щим образом:
public Forml()
{
//
// Необходимо для поддержки Windows Form Designer
• / /
InitializeComponent();
• SetStyle(ControlStyles.Opaque, true); .
//
// Следует сделать: Любой код, относящийся к конструктору,
// должен быть помещен после вызова метода InitializeComponent
Этот код изменяет поведение класса Form таким образом, что он не будет авто-
матически выполнять закрашивание фона окна. Если мы включаем в код эту стро-
ку, но не закрашиваем фон окна самостоятельно, то какое бы изображение ни
оказалось расположенным под данным окном на момент его создания, оно будет
оставаться видимым, что вряд ли может нас устроить.
В самое начало файла мы включим строку с оператором using, поскольку
в данном примере мы будем использовать класс LinearGradientBrush, который
НаХОДИТСЯ В Пространстве имен Drawing2D. После добавления ДИреКТИВЫ using
к пространству имен Drawing2D, код примет следующий вид:
using System;
using System.Drawing;
using System,Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;.
using System.Windows.Forms;
using System.Data;
Теперь необходимо добавить к нашему классу метод onPaint ():
protected override void OnPaint(FaintEventArgs e)
V • ..у!.'. . , - • . • . : • : . ; : • • • • • • • ••• . . ; • . : • • . • , ; . . • ; • , . . • у . . ' . ; . ' . - / . . . , : ; ' ; . . . . - , ' . : •
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, ClientRectangle);
g.FillRectangle(Brushes.Red, newRectangle(10, 10, 50, 50));
Brush linearGradientBrush -~: new LinearGradientBrush (
new Rectangle .(10, 60,: 50, 50), Color .Blue, Color .White, 45);
g.FillRectangle(linearGradientBrush, new Rectangle(10, 60, 50, 50));
// Вызываем метод Dispose() вручную
liriearGradientBrush. Dispose () ; "•
• g.Fi'llEllipse (Brushes. Aquamarine, new Rectangle (60, 20, 50, 30)) ;
g.FillPie( Brushes. Chartreuse, new Rectangle (60, 60, 50, 50) , 90, 210);
g.FillPolygon(Brushes.BlueViolet, new Point[3 {
new Point(110, 10),
new Point(150, 10) ,
new Point(160, 40),
new Point(120, 20),
new Point(120, 60),
Введение в GDI+ 439
Теперь нажмите клавишу/^ и запустите программу. В ре-
зультате ее выполнения будет создано окно, представленное
на рисунке слева.
Как это работает
Существует класс Brushes, в котором содержится прибли-
зительно 150 разновидностей кистей — по одной на каждый
заранее определенный цвет. Названный класс будет исполь-
зоваться нами для создания большинства кистей, с которыми
мы будем работать в данном примере, за исключением кисти
LinearGradientBrush, которую МЫ СОЗДадИМ СаМОСТОЯТелЬНО.
Первое обращение к методу FiliRectangleO позволяет
нарисовать фон клиентской области нашего окна:
g.FillRectangle(Brushes.White, ClientRectangle);
Создание LinearGradientBrush предполагает передачу прямоугольника с задан-
ными размерами, двух цветов, между которыми будет осуществляться переход,
и угол этого перехода, который в данном случае равен 45°:
Brush linearGradientBrush = new LinearGradientBrush(
new Rectangle(10, 60, 50, 50), Color.Blue, Color.White, 45);
g.FiliRectangle(linearGradientBrush, new Rectangle(10, 60, 50, 50));
linearGradientBrush.Dispose();
Когда мы задаем прямоугольник для кисти, то используем прямоугольник с ши-
риной, равной 50, и высотой, равной 50, что в точности совпадает с прямоугольни-
ком, использованным при описании кисти. В результате этого площадь кисти
соответствует закрашиваемой области. Попробуйте изменить размеры прямоуголь-
ника, описываемого при создании кисти, таким образом, чтобы его ширина и вы-
сота были равны 10, и посмотрите, что получится. Кроме того, попытайтесь
использовать для угла изменения цвета (который в вышеприведенной программе
описан как равный 45°) различные другие значения, и понаблюдайте, каким обра-
зом изменится эффект.
Графический вывод текста с помощью класс Font
Следующий пример будет посвящен графическому выводу текста с помощью
класса Font, который включает в себя три основные характеристики шрифта,
а именно: семейство, размер и стиль. Класс Font находится в пространстве имен
System.Drawing.
Согласно документации .NET, семейство шрифтов "определяет группу типов
представления литер, имеющих одинаковый базовый дизайн". Это довольно при-
чудливый способ объяснить, что Courier, Arial и Times New Roman представляют
собой семейства шрифтов.
Свойство size определяет размер данного типа шрифта. Однако в .NET Framework,
строго говоря, это свойство не является обязательно размером шрифта, вы-
раженным в пунктах. Оно может представлять собой такой размер, однако
существует возможность изменить свойство с названием Graphicsunit (единица
измерения графических объектов) посредством свойства unit, которое определяет
единицу измерения шрифтов. Один пункт составляет 1/72 дюйма, поэтому шрифт
в 10 пунктов будет иметь высоту 10/72 дюйма. С помощью перечислимого типа
440 Глава 16
Graphicsunit размер шрифта может задаваться с помощью следующих единиц из-
мерения:
• пункты
• особый шрифт (У75 дюйма)
• документ (Узоо дюйма)
• дюйм
• миллиметр
• пиксель
Это означает, что мы обладаем беспрецедентной гибкостью при задании требу-
емого размера шрифта. Одной из возможных областей применения этих размеров
может быть подпрограмма, предназначенная для графического вывода текста, ко-
торая должна надлежащим образом работать с дисплеями, обладающими высоким/
низким разрешением и с принтерами.
При выводе в графическом режиме текста каким-либо определенным шрифтом
на некоторой конкретной поверхности рисования зачастую бывает необходимо уз-
нать длину данной строки текста, выраженную в пикселях. Совершенно очевидно,
почему в результате использования различных шрифтов длина строки, выраженная
в пикселях, будет различной — меньший по размеру шрифт будет занимать мень-
шее количество пикселей. Однако не менее важно обладать информацией о по-
верхности рисования, поскольку разрешение различных поверхностей рисования,
выраженное в пикселях, также различно. Обычно экран имеет разрешение 72 пик-
селя на дюйм. У некоторых принтеров может быть разрешение 300 или 600 пик-
селей на дюйм, а иногда даже еще больше. Для определения длины строки для
данного Шрифта МЫ будем ИСПОЛЬЗОВаТЬ МеТОД MeasureString () объекта Graphics.
В качестве образца здесь использован некоторый код, который позволяет проде-
монстрировать, каким образом можно получить длину и высоту строки. После это-
го код выводит прямоугольник черного цвета, внутри которого синим цветом
выводится текст:
String str = "This is a string";
SizeF size — g.MeasureString (str^ Font) ;
g.DrawRectangle(Pens.Black, 0, 0, size.Width, size.Height);
g. Drawstring (str, Font/Brushes. Blue, new RectangleF (0 , 0 ,
size,Width, size.Height));
Свойство шрифта style (стиль) позволяет определять, выделяется ли текст
курсивом, жирным шрифтом, зачеркивается ли он или подчеркивается.
Всегда ВЫЗЫВаЙТе МеТОД Dispose О ДЛЯ Объектов Font.
Вызов метода Dispose о для создаваемых нами объектов Brush или использование
для работы с ними конструкции using представляется очень важным, поскольку
в противном случае приложение может исчерпать ресурсы системы.
При графическом выводе текста для задания граничных координат выводимого
текста используется Rectangle. Обычно высота этого прямоугольника должна
равняться высоте шрифта или быть кратной ей. Отступление от этого правила
допускается только в особых случаях для достижения специальных эффектов с ис-
пользованием отдельных частей текста.
Введение в GDI+ 441
В классе stringFormat содержится информация о внешнем представлении тек-
ста, включая выравнивание и интервалы, между строками. В следующем примере
демонстрируется выравнивание текста по правому краю и по центру с помощью
класса StringFormat.
Практикум: пример использования класса Font
Запустите Visual Studio.NET и создайте проект С# Windows Application. Щелк-
ните правой кнопкой Мыши на форме и выберите пункт View Code из раскрыв-
шегося меню. Найдите конструктор класса Formi и вставьте обращение к методу
setstyleO сразу после обращения к методу initiaiizeComponento. Нам также
потребуется изменить границы окна, что бы в нем было достаточно места для вы-
вода текста, который нам необходим. Измененный конструктор будет выглядеть
следующим образом:
public Formi ()
{
•//
// Необходимо для поддержки Windows Form Designer
//
InitializeComponentO;
SetStyle (ControlStyl.es.Opaque, true)
Категория: информатика | Просмотров: 2214 | Добавил: basic | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Календарь
«  Февраль 2010  »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

krutoto.ucoz.ru
Бесплатный конструктор сайтов - uCoz