лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows
.pdf
Замкнутые фигуры |
101 |
|
|
|
|
|
|
|
Значение |
Описание |
|
|
|
|
|
BS_DIBPATTERN8X8 |
Òî æå, ÷òî è BS_DIBPATTERN |
|
BS_DIBPATTERNPT |
Растровая кисть, рисунок которой задается аппаратно-независимым |
|
|
растровым изображением (DIB). Поле lbHatch содержит указатель на DIB- |
|
|
изображение |
|
|
|
Поле lbColor задает цвет кисти. Его интерпретация зависит от значения поля lbStyle и поясняется в табл. 2.12.
Таблица 2.12. Интерпретация поля lbColor
Значения поля lbStyle |
Интерпретация поля lbColor |
|
|
BS_HOLLOW èëè BS_PATTERN |
Игнорируется |
BS_HATCHED èëè BS_SOLID |
Значение типа COLORREF |
BS_DIBPATTERN èëè BS_DIBPATTERNPT |
Младшая часть слова lbColor должна иметь значение |
|
DIB_PAL_COLORS или DIB_RGB_COLORS. Первое |
|
значение указывает на то, что в массиве bmiColors, |
|
являющемся членом структуры BITMAPINFO, содер- |
|
жатся 16-разрядные индексы цветов в логической |
|
палитре, второе значение — на то, что в массиве |
|
bmiColors содержатся явные RGB-коды цветов |
|
|
Поле lbHatch задает стиль штриховки. Его интерпретация также зависит от зна чения поля lbStyle и поясняется в табл. 2.13.
Таблица 2.13. Интерпретация поля lbHatch
Значения поля lbStyle |
Интерпретация поля lbHatch |
|
|
BS_SOLID èëè BS_HOLLOW |
Игнорируется |
BS_PATTERN |
Дескриптор растрового объекта GDI (bitmap’а) |
BS_HATCHED |
Одно из значений HS_HORIZONTAL, HS_VERTICAL, |
|
HS_BDIAGONAL, HS_FDIAGONAL, HS_CROSS, HS_DIAGCROSS |
BS_DIBPATTERN |
Дескриптор упакованного DIB-растра |
BS_DIBPATTERNPT |
Указатель на упакованный DIB-растр |
|
|
Структура LOGBRUSH также используется при создании расширенных перьев, которые рассматривались ранее. Например, третья фигура на рис. 2.11 была нари сована с использованием данной структуры.
Замкнутые фигуры
Напомним, что любая замкнутая фигура рисуется в Windows с использованием текущего пера, которым обводится контур фигуры, и текущей кисти, которая ис пользуется для заливки внутренней области фигуры. По умолчанию в контексте устройства выбрана сплошная кисть белого цвета.
Прямоугольники
Наиболее важной геометрической фигурой в Windows является прямоуголь ник. Прямоугольники применяются при определении окон и клиентских
102 |
Глава 2. GDI — графический интерфейс устройства |
|
|
областей, различных фигур с прямоугольным ограничивающим контуром, при отсечении и при форматировании текста. Поэтому в Win32 API определены специальная структура данных для представления прямоугольников и много численные функции как для работы с этой структурой, так и для рисования прямоугольников.
Прямоугольник как структура данных
Эта структура данных уже рассматривалась в главе 1, но все же напомним ее оп ределение:
typedef struct tagRECT { LONG left;
LONG top; LONG right; LONG bottom;
} RECT;
Поля структуры задают координаты левого верхнего угла (left, top) и правого нижнего угла (right, bottom) прямоугольника.
Допустим, что в программе определена переменная этого типа:
RECT rect;
Для установки всех полей структуры rect при обычной записи вам пришлось бы написать примерно следующий код:
rect.left = x_left; rect.top = y_top; rect.right = x_right; rect.bottom = y_bottom;
Но если воспользоваться функцией SetRect, имеющей прототип:
BOOL SetRect(LPRECT lprc, int xLeft, int yTop, int xRight, int yBottom);
то четыре строчки кода можно заменить одной:
SetRect(&rect, x_left, y_top, x_right, y_bottom);
Кроме этой функции Win32 API предлагает еще восемь функций для работы со структурами типа RECT. В табл. 2.14 показано использование этих функций.
Таблица 2.14. Функции для работы со структурами типа RECT
Функция |
Описание |
|
|
SetRect(&rect, xLeft, yTop, xRight, yBottom); |
Установить координаты прямоугольника |
|
в заданные значения |
OffsetRect(&rect, dX, dY); |
Переместить прямоугольник по оси X на |
|
величину dX и по оси Y на величину dY |
InflateRect(&rect, dX, dY); |
Уменьшить или увеличить ширину и высоту |
|
прямоугольника |
SetRectEmpty(&rect); |
Установить все поля структуры rect в нуль |
CopyRect(&DestRect, &SrcRect); |
Скопировать один прямоугольник в другой |
IntersectRect(&DestRect, &SrcRect1, &SrcRect2); |
Получить пересечение двух прямоугольников |
UnionRect(&DestRect, &SrcRect1, &SrcRect2); |
Получить объединение двух прямоугольников |
bEmpty = IsRectEmpty(&rect); |
Определить, является ли прямоугольник пустым |
bInRect = PtInRect(&rect, point); |
Определить, содержится ли точка point внутри |
|
прямоугольника rect |
|
|
Замкнутые фигуры |
103 |
|
|
|
|
Рисование прямоугольников
Для рисования прямоугольников предусмотрены функции Rectangle, FillRect,
FrameRect, InvertRect и DrawFocusRect.
Rectangle
Функция Rectangle имеет следующий прототип:
BOOL Rectangle(HDC hdc, int xLeft, int yTop, int xRight, int yBottom);
Она рисует прямоугольник, определяемый четырьмя координатами. Парамет ры xLeft и yTop задают положение левого верхнего угла, а xRight и yBottom — положе ние правого нижнего угла. Все координаты определяются в логических единицах. Стороны прямоугольника всегда параллельны горизонтальной и вертикальной сто ронам экрана.
Хотя в MSDN утверждается, что необходимо выполнять условия xLeft < xRight и yTop < yBottom, экспериментальная проверка показывает, что если второй и тре тий параметры задают правый нижний угол, а четвертый и пятый параметры — левый верхний угол, то Windows справляется с этой «головоломкой» и рисует требуемый прямоугольник.
На процесс рисования влияют многие атрибуты, содержащиеся в контексте устройства:
графический режим, который может быть совместимым (GM_COMPATIBLE) или расширенным (GM_ADVANCED);
стиль и цвет пера;
толщина пера;
режим рисования (текущая бинарная растровая операция).
Рисунок 2.16 иллюстрирует результаты применения функции Rectangle при разных атрибутах контекста устройства.
Рис. 2.16. Рисование прямоугольников функцией Rectangle
Рисование выполнялось черным пером, за исключением второго прямоуголь ника, нарисованного пустым пером, и серой стандартной кистью (GRAY_BRUSH), выбранной в контекст устройства.
Прежде всего отметим, что в совместимом графическом режиме, который ус тановлен по умолчанию1, прямоугольник рисуется так, что действительное поло жение его правого нижнего угла определяется точкой (xRight × 1, yBottom – 1).
1 См. раздел «Системы координат и преобразования».
104 |
Глава 2. GDI — графический интерфейс устройства |
|
|
В этом режиме нарисованы первый, второй, четвертый и пятый прямоугольники. И только в расширенном графическом режиме, в котором был нарисован третий прямоугольник, действительное положение правого нижнего угла определяется точкой (xRight, yBottom).
Когда прямоугольник рисуется пустым пером PS_NULL, то его размеры умень шаются на один пиксел по ширине и на один пиксел по высоте.
Назовем базовой линией ту линию, которая рисуется при единичной толщине пера. Если толщина пера nWidth больше единицы, то один пиксел рисуется на ба зовой линии, (nWidth – 1)/2 пикселов рисуются снаружи от этой линии и еще столько же пикселов рисуются внутри прямоугольника. Но что происходит, ког да величина nWidth является четным числом и (nWidth – 1) не делится нацело на два? Остаток в виде половины пиксела трансформируется в утолщение на один пиксел сверху для горизонтальных линий и на один пиксел слева — для верти кальных линий.
Все сказанное выше о толстых линиях справедливо для всех стилей пера, кро ме стиля PS_INSIDEFRAME. Этот стиль задает выравнивание внутри контура. На крайнем справа прямоугольнике хорошо виден механизм его работы. Один пик сел рисуется на базовой линии, а все остальные — внутри прямоугольника.
Текущая растровая операция в контексте устройства распространяется как на периметр, так и на внутреннюю часть прямоугольника.
FillRect
Функция FillRect имеет следующий прототип:
BOOL FillRect(HDC hdc, CONST RECT* lprc, HBRUSH hbr);
Она закрашивает прямоугольник, определяемый структурой типа RECT, адрес которой указан в параметре lprc. Для закрашивания используется кисть, дескрип тор которой передается через параметр hbr.
Действительное положение правого нижнего угла прямоугольника определя ется точкой (lprc.right – 1, lprc.bottom – 1), независимо от используемого графи ческого режима.
Следует обратить внимание на три важных свойства этой функции:
кисть передается функции непосредственно через третий параметр, поэтому ее не нужно задавать в контексте устройства;
перо в этой функции вообще не используется;
функция не использует атрибут бинарной растровой операции в контексте ус тройства.
FrameRect
Функция FrameRect имеет следующий прототип:
BOOL FrameRect(HDC hdc, CONST RECT* lprc, HBRUSH hbr);
Она закрашивает периметр прямоугольника lprc кистью hbr. Толщина рисуе мой рамки равна одной логической единице.
Обратите внимание на то, что рамка рисуется кистью, а не пером. Это позволя ет получать интересные эффекты в случае использования растровой кисти. На пример, можно создать растровую кисть с «шахматным» узором», когда в растре черные и белые пикселы чередуются, как на шахматной доске. Если передать
Замкнутые фигуры |
105 |
|
|
|
|
дескриптор этой кисти функции FrameRect, то периметр прямоугольника будет на рисован «настоящей» точечной линией1.
InvertRect
Функция InvertRect имеет следующий прототип:
BOOL InvertRect(HDC hdc, CONST RECT* lprc);
Она инвертирует цвет каждого пиксела внутри заданного прямоугольника. Если графическое устройство использует палитру, то инвертируются индексы па литры. В устройствах без палитры черный цвет переходит в белый, белый цвет — в черный, а RGB значение каждого пиксела инвертируется.
При двукратном вызове функции InvertRect с одинаковыми параметрами вос станавливается первоначальное изображение.
DrawFocusRect
Функция DrawFocusRect имеет следующий прототип:
BOOL DrawFocusRect(HDC hdc, CONST RECT* lprc);
По своему действию она напоминает функцию FrameRect, рисуя периметр пря моугольника шахматной узорной кистью с применением растровой операции «Исключающее ИЛИ». Повторный вызов функции с теми же параметрами вос станавливает первоначальное изображение.
Функция активно используется теми модулями Win32 API, которые отвечают за управление окнами. Например, в диалоговых окнах функция DrawFocusRect ри сует точечный контур прямоугольника на кнопке, получающей фокус ввода с клавиатуры. Когда фокус переходит к другой кнопке, прямоугольник стирается повторным вызовом функции DrawFocusRect.
Функция DrawFocusRect также может использоваться при выводе «эластичных» прямоугольников.
Эллипсы, сегменты, секторы
и закругленные прямоугольники
Win32 GDI содержит несколько функций для рисования эллипса, его частей и даже гибрида прямоугольника с эллипсом, который выглядит как прямоуголь ник с закругленными углами.
Эллипсы
Для рисования эллипсов предназначена функция Ellipse, прототип которой при веден ниже:
BOOL Ellipse(HDC hdc, int xLeft, int yTop, int xRight, int yBottom);
Функция рисует эллипс в ограничивающем прямоугольнике, заданном коор динатами xLeft, yTop, xRight, yBottom.
Все сказанное выше о влиянии атрибутов в контексте устройства на процесс рисования прямоугольников распространяется также и на рисование эллипсов функцией Ellipse.
1 См. замечания по поводу стиля PS_ALTERNATE для косметических перьев.
106 |
Глава 2. GDI — графический интерфейс устройства |
|
|
Сегменты
В разделе «Линии и кривые» уже рассматривалось рисование дуги эллипса с по мощью функции Arc. Сегмент эллипса образуется из дуги, если ее концы соеди нить отрезком, называемым хордой.
Для рисования сегментов используется функция Chord:
BOOL Chord(HDC hdc, int xLeft, int yTop, int xRight, int yBottom, int xStart, int yStart, int xEnd, int yEnd);
Функция принимает такой же набор параметров, что и функция Arc. Началь ный и конечный углы дуги задаются двумя точками с координатами (xStart, yStart) и (xEnd, yEnd). Направление рисования дуги, а следовательно, и вид получаемой фигуры определяются так же, как и для функции Arc. На рис. 2.17 показано при менение функции Chord.
Рис. 2.17. Применение функции Chord
Секторы
Сектор эллипса — это фигура, ограниченная дугой и двумя радиусами, проведен ными к концам дуги.
Секторы рисуются функцией Pie, прототип которой приведен ниже:
BOOL Pie(HDC hdc, int xLeft, int yTop, int xRight, int yBottom, int xStart, int yStart, int xEnd, int yEnd);
Функция принимает такой же набор параметров, что и функция Arc. Направ ление рисования дуги и вид получаемой фигуры определяются так же, как и для функции Arc. На рис. 2.18 показано применение функции Pie.
Закругленные прямоугольники
Прямоугольник с закругленными углами создается при помощи функции RoundRect, имеющей следующий прототип:
BOOL RoundRect(HDC hdc, int xLeft, int yTop, int xRight, int yBottom, int roundWidth, int roundHeight);
Функция позволяет нарисовать прямоугольник, эллипс или любую промежу точную фигуру. Первые пять параметров функции совпадают с параметрами функ ции Rectangle. Последние два параметра определяют ширину и высоту маленьких эллипсов, используемых для закругления углов прямоугольника, как это показа но на рис. 2.19.
Замкнутые фигуры |
107 |
|
|
|
|
Рис. 2.18. Применение функции Pie
Рис. 2.19. Прямоугольник, нарисованный функцией RoundRect
Если параметры roundWidth и roundHeight имеют нулевое значение, то функция RoundRect рисует прямоугольник. Если параметр roundWidth равен xRight – xLeft и одновременно параметр roundHeight равен yBottom – yTop, то функция RoundRect нарисует эллипс.
Многоугольники
Прямоугольник является частным случаем многоугольника. Для рисования про извольного многоугольника предназначена функция Polygon:
BOOL Polygon(HDC hdc, CONST POINT* lpPoints, int nCount);
Работа этой функции напоминает рисование ломаных линий функцией Polyline. Второй параметр функции принимает адрес массива точек, а третий — количе ство точек. В отличие от Polyline, функция Polygon автоматически замыкает фигу ру. В случае использования геометрического пера функция Polygon, так же как и Polyline, оформляет каждую вершину в соответствии с атрибутом соединения.
Для выпуклых многоугольников внутренняя область определяется достаточ но четко. Однако невыпуклый многоугольник может состоять из нескольких частей, как, например, пятиконечная звезда, что затрудняет определение его
108 |
Глава 2. GDI — графический интерфейс устройства |
|
|
внутренней области. Такие же проблемы могут возникнуть при перекрытии од ного многоугольника другим. В связи с этим Win32 GDI предусматривает два ре жима заполнения многоугольников: режим ALTERNATE и режим WINDING. Контекст устройства содержит соответствующий атрибут, который можно изменять, вызы вая функцию SetPolyFillMode. По умолчанию установлен режим заполнения мно гоугольников ALTERNATE. На рис. 2.20 показано рисование пятиконечной звезды при разных режимах заполнения многоугольников.
Рис. 2.20. Фигуры, нарисованные в двух режимах закрашивания многоугольника: слева — ALTERNATE; справа — WINDING
Врежиме ALTERNATE принадлежность некоторой точки внутренней области оп ределяется при помощи довольно простого алгоритма:
1.Проведем мысленно горизонтальную линию сканирования через интересую щую нас точку.
2.Пронумеруем точки пересечения этой линии с встречающимися на ее пути ли ниями многоугольника.
3.Если интересующая нас точка лежит между нечетным и четным пересечения ми, то она принадлежит внутренней области многоугольника.
Это правило иллюстрируется левой фигурой, показанной на рис. 2.21.
Врежиме WINDING принадлежность некоторой точки внутренней области оп ределяется с учетом направления рисования сторон многоугольника по следую щему алгоритму:
1.Проведем мысленно горизонтальную линию сканирования через интересую щую нас точку.
2.Установим нулевое значение счетчика count до первого пересечения этой ли нии с многоугольником.
3.При каждом следующем пересечении линии многоугольника анализируем на правление рисования этой линии по отношению к линии сканирования. Если это направление по часовой стрелке, то значение счетчика count увеличивает ся на единицу, если против часовой стрелки, то уменьшается на единицу.
4.Если текущее значение счетчика count больше нуля, то точка принадлежит внут ренней области, в противном случае точка считается внешней.
Это правило иллюстрируется правой фигурой, показанной на рис. 2.21.
Для рисования серии многоугольников за один вызов предназначена функция
PolyPolygon:
BOOL PolyPolygon(HDC hdc, CONST POINT* lpPoints, CONST int* lpPolyCounts, int nCount);
Второй параметр функции содержит адрес массива точек для всех многоуголь ников. Многоугольники определяются последовательно один за другим. Каждый
Регионы и отсечение |
109 |
|
|
|
|
многоугольник замыкается автоматически проведением линии от последней вер шины к первой.
Рис. 2.21. Определение принадлежности точки многоугольнику при разных режимах закрашивания многоугольника: слева — ALTERNATE; справа — WINDING
Третий параметр функции — адрес массива целых чисел, задающих количе ство вершин в соответствующем многоугольнике. Каждое число должно быть не менее двух. Если количество вершин равно двум, то многоугольник вырождается в прямую линию. Четвертый параметр функции задает количество рисуемых мно гоугольников.
Регионы и отсечение
Регион — это совокупность точек в координатном пространстве. Эта совокупность может быть пустой, а может занимать все координатное пространство. Она может иметь прямоугольную или любую неправильную форму. Регионы так же, как пе рья, кисти, битовые образы и многие другие элементы, являются объектами GDI. После создания объекта региона приложение получает его дескриптор, который относится к типу HRGN. Когда объект региона становится ненужным, его следует удалить функцией DeleteObject. Регионы могут использоваться как для рисова ния, так и для отсечения.
Создание регионов
Простейший тип региона — это прямоугольник. После объявления объекта ре гиона:
HRGN hRgn;
вы можете создать прямоугольный регион одним из двух способов:
hRgn = CreateRectRgn(xLeft, yTop, xRight, yBottom);
или
hRgn = CreateRectRgnIndirect(&rect);
Вы может также создать эллиптический регион, используя следующие вызовы:
hRgn = CreateEllipticRgn(xLeft, yTop, xRight, yBottom);
или
hRgn = CreateEllipticRgnIndirect(&rect);
110 |
Глава 2. GDI — графический интерфейс устройства |
|
|
Прямоугольный регион с закругленными углами тоже формируется довольно просто:
hRgn = CreateRoundRectRgn(xLeft, yTop, xRight, yBottom, roundWidth, roundHeight);
Создание многоугольного региона похоже на использование функции Polygon:
hRgn = CreatePolygonRgn(point, iCount, iPolyFillMode);
Аргумент point содержит адрес массива структур типа POINT. В аргументе iCount задается количество точек, а аргумент iPolyFillMode принимает значение ALTERNATE
или WINDING.
Также можно создать сложный регион, состоящий из нескольких многоуголь ников при помощи функции CreatePolyPolygonRgn:
hRgn = CreatePolyPolygon(point, polyCounts, iCount, iPolyFillMode);
Использование этой функции аналогично использованию функции PolyPolygon.
Операции с объектами регионов
Регион представляет собой множество точек двумерного пространства, поэтому многие операции над регионами выглядят как операции над множествами. В табл. 2.15 приведены функции, реализующие эти операции.
Таблица 2.15. Функции для работы с регионами
Функция |
Назначение |
|
|
BOOL PtInRegion(HRGN hrgn, int X, int Y); |
Проверяет, принадлежит ли точка (X, Y) |
|
региону hrgn |
BOOL RectInRegion(HRGN hrgn, CONST RECT *lprc); |
Проверяет, принадлежит ли хотя бы одна |
|
точка прямоугольника lprc региону hrgn |
BOOL EqualRgn(HRGN hRgn1, HRGN hRgn2); |
Проверяет, содержат ли регионы hRgn1 |
|
и hRgn2 одинаковые множества точек |
int GetRgnBox(HRGN hrgn, LPRECT lprc); |
Возвращает через lprc ограничивающий |
|
прямоугольник региона |
int CombineRgn(HRGN hrgnDest, HRGN hrgnSrc1, |
Комбинирует два региона, hrgnSrc1 |
HRGN hrgnSrc2, int fnCombineMode); |
и hrgnSrc2, в соответствии с операцией |
|
fnCombineMode. Результат помещается |
|
â hrgnDest |
int OffsetRgn(HRGN hrgn, int nXOffset, int nYOffset); |
Осуществляет смещение региона hrgn на |
|
nXOffset единиц по оси X и на nYOffset |
|
единиц по оси Y |
DWORD GetRegionData(HRGN hRgn, |
Заполняет структуру lpRgnData типа |
DWORD dwCount, LPRGNDATA lpRgnData); |
RGNDATA данными, описывающими регион |
|
hRgn |
HRGN ExtCreateRegion(CONST XFORM *lpXform, |
Создает регион по структуре RGNDATA |
DWORD nCount, CONST RGNDATA *lpRgnData); |
с возможным аффинным преобразованием, |
|
заданным структурой XFORM |
|
|
Укажем на некоторые возможные применения этих функций.
Функция PtInRegion может оказаться полезной при реализации некоторых эк зотических разновидностей кнопок или интерактивных областей, изменяющих цвет под курсором мыши. Приложение должно лишь создать объект региона, со ответствующий интерактивной области, и вызвать функцию PtInRegion при обра ботке сообщения WM_MOUSEMOVE для изменения изображения.
