Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows

.pdf
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
13.15 Mб
Скачать

Замкнутые фигуры

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 для изменения изображения.