Компьютерная графика. Лабораторная работа 1_2п. Лабораторная работа основы создания графических приложений в системе windows
Скачать 0.96 Mb.
|
GetStockObject . После окончания работы с предопределённым объектом его не нужно удалять при помощи функции DeleteObject . Предопределённые объекты существуют в системе постоянно. Любая линия рисуется в Windows с использованием графического объекта, называемого пером. Контекст устройства содержит перо по умолчанию – сплошное перо черного цвета толщиной 1 пиксел. Многие графические функции начинают рисование с так называемой текущей позиции пера. Одним из атрибутов контекста устройства является текущая позиция пера. Она определяется значением типа POINT . По умолчанию текущая позиция пера установлена в точку (0, 0). Если нужно изменить текущую позицию, вызывается функция MoveToEx : BOOL MoveToEx( HDC hdc, // дескриптор контекста устройства int X, // х-координата новой текущей позиции int Y, // у-координата новой текущей позиции LPPOINT IpPoint // предыдущая позиция пера ) ; Если предыдущая позиция пера не интересна, то следует передать последнему параметру значение NULL . В случае успешного завершения функция возвращает ненулевое значение. В любой момент можно получить значение текущей позиции пера, вызвав функцию GetCurrentPositionEx(hDC, &pt); Результат выполнения функции помещается в переменную pt типа POINT Для создания прямой линии используется функция LineTo : BOOL LineTo( HDC hdc, // дескриптор контекста устройства int xEnd, // х-координата конечной точки int yEnd // у-координата конечной точки ) ; Эта функция рисует отрезок, начиная с точки, в которой находится текущая позиция пера, до точки ( xEnd , yEnd ), не включая последнюю точку в отрезок. Координаты конечной точки задаются в логических единицах. Если функция завершается успешно, то она возвращает ненулевое значение, а текущая позиция пера устанавливается в точку ( xEnd , yEnd ). Последнее свойство функции можно использовать, если требуется нарисовать ряд связанных отрезков. Например, можно определить массив из пяти точек, задающих контур прямоугольника, в котором последняя точка совпадает с первой, и нарисовать прямоугольник, как показано в следующем фрагменте кода: POINT pt[5] = {{100,100}, {200,100}, {200,200}, {100,200}, {100.100}}; MoveToEx(hDC, pt[0].x, pt[0].y. NULL); for (int i = 0; i < 5; ++1) LineTo(hDC, pt[i].x, pt[i].y): Последовательность связанных отрезков гораздо проще нарисовать с помощью функции Polyline : BOOL Polуline(HDC hdc, CONST POINT *lppt, int cPoints); Второй параметр здесь – это адрес массива точек, а третий – количество точек. Предыдущий пример рисования прямоугольника теперь можно переписать так: POINT pt[5] = {{100,100}, {200,100}, {200,200}, {100,200}, {100.100}}; Polyline(hDC, pt, 5); Хотя результат выполнения этого фрагмента будет таким же, следует заметить, что функция Polyline не использует текущую позицию пера и не изменяет её. Функция PolylineTo также предназначена для рисования последовательности связанных отрезков: BOOL PolylineTo(HDC hdc, CONST POINT* lppt, DWORD cPoints); Она использует текущую позицию пера для начальной точки и после каждого своего выполнения устанавливает текущую позицию в конец нарисованного отрезка. Если есть необходимость применить её для рисования последовательности связанных отрезков, то вызов функции Polyline надо заменить двумя инструкциями: MoveToEx(hDC, pt[0].x, pt[0].y, NULL); PolylineTo(hDC, p t + 1 , 4); Наиболее важной геометрической фигурой в Windows является прямоугольник. Прямоугольники применяются при определении окон и клиентских областей, различных фигур с прямоугольным ограничивающим контуром, при отсечении и при форматировании текста. Поэтому в Windows API определены специальная структура данных для представления прямоугольников и многочисленные функции как для работы с этой структурой, так и для рисования прямоугольников. Эта структура имеет следующее определение: typedef struct tagRECT { LONG left; LONG top; LONG right; LONG bottom; } RECT; Поля структуры задают координаты левого верхнего угла ( left , top ) и правого нижнего угла ( right , bottom ) прямоугольника. Для установки всех полей структуры можно воспользоваться функцией SetRect имеющей прототип: BOOL SetRect(LPRECT lprc, int xLeft, int yTop, int xRight, int yBottom ); Альтернативный вариант – это установка значений полей, как показано ниже: RECT rect; rect.left = xLeft; rect.top = yTop; rect.right = xRight; rect.bottom = yBottom; Кроме этой функции Windows API предлагает ещё восемь функций для работы со структурами типа RECT . В табл. 6 показано использование этих функций. Таблица 6. Функции работы со структурой типа RECT Функция Описание SetRect(&rect, xLeft, yTop, xRight, yBottom); Установить коорзинаты прямоугольника в заданные значения OffsetRect(&rect, dX, dY); Переместить прямоугольник по координате X на величину dX , а по оси Y на величину dY InflateRect(&rect, dX, dY); Изменить ширину и высоту прямоугольника SetRectEmpty(&rect); Установить все поля структуры rect в 0 CopyRect(&DestRect, SrcRect); Скопировать один прямоугольник в другой IntersectRect(&DestRect, SrcRect1, SrcRect2); Получить пересечение прямоугольников UnionRect(&DestRect, SrcRect1, SrcRect2); Получить объединение прямоугольников bEmpty = IsRectEmpty(&rect); Определить, является ли прямоугольник пустым bInRect = PtInRect(&rect, point); Определить, является ли точка point внитри прямоугольника rect Для рисования прямоугольников предусмотрены функции Rectangle , FillRect , FrameRect , InvertRect и DrawFocusRect Функция Rectangle имеет следующий прототип: BOOL Rectangle( HDC hdc, int xLeft, int yTop, int xRight, int yBottom ); Она рисует прямоугольник, определяемый четырьмя координатами. Параметры xLeft и yTop задают положение левого верхнего угла, a xRight и yBottom – положение правого нижнего угла. Все координаты определяются в логических единицах. Стороны прямоугольника всегда параллельны горизонтальной и вертикальной сторонам экрана. На процесс рисования влияют многие атрибуты, содержащиеся в контексте устройства: • стиль и цвет пера; • толщина пера; • режим рисования (текущая бинарная растровая операция) Функция FillRect имеет следующий прототип: BOOL FillRect(HDC hdc. CONST RECT* lprc, HBRUSH hbr); Она закрашивает прямоугольник, определяемый структурой типа RECT , адрес которой указан в параметре lprc . Для закрашивания используется кисть, дескриптор которой передаётся через параметр hbr Следует обратить внимание на три важных свойства этой функции: • кисть передаётся функции непосредственно через третий параметр, поэтому её не нужно задавать в контексте устройства; • перо в этой функции вообще не используется; • функция не использует атрибут бинарной растровой операции в контексте устройства. Функция FrameRect имеет следующий прототип: BOOL FrameRect(HDC hdc, CONST RECT* lprc, HBRUSH hbr); Она закрашивает периметр прямоугольника lprc кистью hbr . Толщина рисуемой рамки равна одной логической единице. Рамка рисуется кистью, а не пером. Это позволяет получать интересные эффекты в случае использования растровой кисти. Функция InvertRect имеет следующий прототип: BOOL InvertRect(HDC hdc, CONST RECT* Iprc); Она инвертирует цвет каждого пиксела внутри заданного прямоугольника. Если графическое устройство использует палитру, то инвертируются индексы палитры. В устройствах без палитры чёрный цвет переходит в белый, белый цвет – в чёрный, а RGB-значение каждого пиксела инвертируется. При двукратном вызове функции InvertRect с одинаковыми параметрами восстанавливается первоначальное изображение. Функция DrawFocusRect имеет следующий прототип: BOOL DrawFocusRect(HDC hdc, CONST RECT* Iprc); По своему действию она напоминает функцию FrameRect , рисуя периметр прямоугольника шахматной узорной кистью с применением растровой операции «Исключающее ИЛИ». Повторный вызов функции с теми же параметрами восстанавливает первоначальное изображение. Функция DrawFocusRect также может использоваться при выводе «эластичных» прямоугольников. Для рисования эллипсов предназначена функция Ellipse , прототип которой приведён ниже: BOOL Ellipse( HDC hdc, int xLeft, int yTop, int xRight, int yBottom ); Функция рисует эллипс в ограничивающем прямоугольнике, заданном координатами xLeft , yTop , xRight , yBottom Все сказанное выше о влиянии атрибутов в контексте устройства на процесс рисования прямоугольников распространяется также и на рисование эллипсов функцией Ellipse Для рисования сегментов эллипса используется функция Chord : BOOL Chord( HDC hdc, int xLeft, int yTop, int xRight, int yBottom, int xStart, int yStart, int xEnd, int yEnd ); В этой функции параметры со второй по пятый задают вершины ограниченного прямоугольника. Начало и конец дуги определяются начальными и конечными углами, которые задаются косвенно через две дополнительные точки с координатами ( xStart , yStart ) и ( xEnd , yEnd ). Начало дуги – это пересечение эллипса с лучом, который начинается в центре эллипса и проходить через точку ( xStart , yStart ). Конец дуги – это пересечение эллипса с лучом, который начинается в центре эллипса и проходит через точку ( xEnd , yEnd ). На рис. 2 показано применение функции Chord Рис. 2. Применение функции Chord Сектор эллипса – это фигура, ограниченная дугой и двумя радиусами, проведёнными к концам дуги. Секторы рисуются функцией Pie , прототип которой приведён ниже: BOOL Piе( HDC hdc, int xLeft. int yTop. int xRight, int yBottom, int xStart, int yStart, int xEnd, int yEnd ); Функция принимает такой же набор параметров, что и функция Chord Направление рисования дуги и вид получаемой фигуры определяются так же, как и для функции Chord Прямоугольник с закруглёнными углами создаётся при помощи функции RoundRect , имеющей следующий прототип: BOOL RoundRect( HDC hdc, int xLeft, int yTop, int xRight, int yBottom, int roundWidth, int roundHeight ); Функция позволяет нарисовать прямоугольник, эллипс или любую промежуточную фигуру. Первые пять параметров функции совпадают с параметрами функции Rectangle . Последние два параметра определяют ширину и высоту маленьких эллипсов, используемых для закругления углов прямоугольника, как это показано на рис. 3. Рис. 3. Прямоугольник, нарисованный функцией RoundRect Прямоугольник является частным случаем многоугольника. Для рисования произвольного многоугольника предназначена функция Polygon : BOOL Polygon(HDC hdc, CONST POINT* IpPoints, int nCount); Работа этой функции напоминает рисование ломаных линий функцией Polyline . Второй параметр функции принимает адрес массива точек, а третий – количество точек. В отличие от Polyline , функция Polygon автоматически замыкает фигуру. Любая функция рисования линий и кривых, а также контуров замкнутых фигур использует перо (реп), выбранное в контексте устройства в данный момент. Если никакое перо не выбрано, то используется перо по умолчанию BLACK_PEN . Оно рисует сплошные чёрные линии толщиной 1 пиксел независимо от режима отображения. Для того, чтобы при рисовании линий придать им разный цвет, толщину или стиль, GDI позволяет создавать объекты логических перьев, которые представляют собой описание требований к перу со стороны приложения. Драйвер графического устройства может поддерживать собственные структуры данных, определяющие реализацию логического пера, – такие внутренние объекты называются физическими перьями. Структура данных логического пера находится под управлением GDI. Дескриптор созданного пера возвращается приложению и используется для ссылок на перо во время последующей работы. Объект пера обновляется следующим образом HPEN hPen; Логический объект пера поглощает ресурсы операционной системы, поэтому когда необходимость в нём отпадает, рекомендуется исключить его из контекста устройства и удалить функцией DeleteObject В GDI определены четыре стандартных типа пера, которые приведены в табл. 7. Таблица 7. Стандартные перья Индекс пера Описание BLACK_PEN Сплошное чёрное перо толщиной 1 пиксел. Установлено по умолчанию WHITE_PEN Сплошное белое перо толщиной 1 пиксел. NULL_PEN Пустое перо (ничего не рисует). Может использоваться для вывода фигур без внешнего контура DC_PEN Сплошное перо толщиной 1 пиксел. По умолчанию перо имеет чёрный цвет. Цвет может быть изменён функцией SetDCPenColor Для получения дескриптора стандартного объекта нужно вызвать функцию GetStockObject , передав ей индекс стандартного объекта, как показано в следующей инструкции: hPen = (HPEN)GetStockObject(WHITE_PEN); Функция GetStockObject возвращает значение типа HGDIOBJ , поэтому для корректного присваивания выполняется преобразование типа. Получив значение дескриптора, нужно выбрать объект пера в контекст устройства: SelectObject(hDC, hPen); После этого все функции, рисующие линии, будут использовать WHITE_PEN до тех пор, пока не будет выбрано другое перо в контекст устройства или не освобождён контекст устройства. Хорошим стилем считается сохранение предшествующего дескриптора объекта и возврат его в контекст устройства после завершения операций рисования с новым объектом, например, как показано в следующем фрагменте кода: HPEN hOldPen = (HPEN)SelectObject(hDC, GetStockObject(WHITE_PEN)); // ... рисуем с пером WHITE_PEN // возврат в контекст устройства предыдущего пера SelectObject(hDC, hOldPen); Все стандартные перья имеют сплошной цвет и единичную толщину. Чтобы рисовать прерывистые или более толстые линии, нужно использовать нестандартные объекты логического пера. Простые перья создаются вызовом функции CreatePen или CreatePenIndirect Функция CreatePen имеет следующий прототип: HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor); Первый параметр задаёт стиль пера, определяющий порядок следования пикселов и расположение линии. Возможные значения этого параметра приведены в табл. 8. Таблица 8. Стили простых перьев Стиль Вид линии Выравнивание Ограничение на толщину PS_SOLID Сплошная По центру Нет PS_DASH Пунктирная По центру nWidth <= 1 PS_DOT Точечная По центру nWidth <= 1 PS_DASHDOT Пунктирно-точечная По центру nWidth <= 1 PS_DASHDOTDOT Отрезок и две точки По центру nWidth <= 1 PS_NULL Не рисуется PS_INSIDEFRAME Сплошная Внутри контора nWidth > 1 Второй параметр функции CreatePen задаёт толщину линии в логических единицах. Параметру nWidth можно передать нулевое значение. В этом случае будет использоваться перо толщиной 1 пиксел независимо от режима отображения. Если задать точечный или пунктирный стиль ( PS_DASH , PS_DOT , PS_DASHDOT , PS_DASHDOTDOT ) с физической толщиной более единицы, то Windows будет использовать перо со стилем PS_SOLID . Таким образом, стилевые (прерывистые) линии можно рисовать только с толщиной 1 пиксел. Следует обратить внимание на то, что точки в стилевых линиях изображаются тремя пикселами. Третьему параметру функции CreatePen передаётся цвет пера в виде значения типа COLORREF . Обычно это значение задаётся либо с помощью макроса RGB , либо с помощью макроса PALETTERGB . Первый вариант используется, если устройство вывода поддерживает полный диапазон цветов, определяемый 24-битным RGB- значением, и, следовательно, приложению нет необходимости работать с палитрой. Второй вариант (макрос PALETTERGB ) необходимо использовать, если приложение работает с логической палитрой, например, для моделей дисплеев, которые поддерживают только 256 цветов. В последнем случае система Windows преобразует запрошенный RGB-цвет в наиболее подходящий индекс палитры. Характеристика пера, названная в табл. 8 «выравниванием», проявляется наиболее существенно, когда линия используется для обводки замкнутых фигур или для рисования дуг, являющихся частью эллипса. Для всех стилей, кроме PS_INSIDEFRAME , линия центрируется таким образом, что часть линии оказывается за пределами ограничивающего контура. Для стиля PS_INSIDEFRAME вся линия рисуется внутри ограничивающего контура. Эту разницу можно заметить, только если параметр nWidth имеет значение большее, чем единица. Если же параметр nWidth имеет единичное значение, то стиль PS_INSIDEFRAME совпадает со стилем PS_SOLID Ниже приведён пример использования функции CreatePen hPen = CreatePen(PS_SOLID, 5, RGB(255, 0, 0)); Этот вызов создаёт простое сплошное (однородное) перо красного цвета толщиной 5 логических единиц. Второй способ создания простых перьев связан с вызовом функции |