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

лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows

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

Перья

91

 

 

 

Третьему параметру функции CreatePen передается цвет пера в виде значения типа COLORREF. Обычно это значение задается либо с помощью макроса RGB, либо с помощью макроса PALETTERGB1. Первый вариант используется, если устройство вывода поддерживает полный диапазон цветов, определяемый 24 битным RGB значением, и следовательно, приложению нет необходимости работать с палит рой. Второй вариант (макрос PALETTERGB) необходимо использовать, если прило жение работает с логической палитрой, например, для моделей дисплеев, которые поддерживают только 256 цветов. В последнем случае система Windows преобра зует запрошенный RGB цвет в наиболее подходящий индекс палитры.

Характеристика пера, названная в таблице «выравниванием», проявляется наиболее существенно, когда линия используется для обводки замкнутых фи гур или для рисования дуг, являющихся частью эллипса. Для всех стилей, кро ме PS_INSIDEFRAME, линия центрируется таким образом, что часть линии оказы вается за пределами ограничивающего контура. Для стиля PS_INSIDEFRAME вся линия рисуется внутри ограничивающего контура. Эту разницу можно заметить, только если параметр nWidth имеет значение большее, чем единица. Например, рисование дуг на рис. 2.5 и 2.6 выполнено пером со стилем PS_INSIDEFRAME. Если же параметр nWidth имеет единичное значение, то стиль PS_INSIDEFRAME совпа дает со стилем PS_SOLID.

Приведем пример использования функции CreatePen. Следующий вызов со здает простое сплошное (однородное) перо красного цвета толщиной 5 логичес ких единиц:

hPen = CreatePen(PS_SOLID, 5, RGB(255, 0, 0));

Следует отметить, что утолщенные линии рисуются всегда с закругленными окончаниями. Это можно заметить для линий, у которых параметр nWidth больше или равен трем единицам.

Второй способ создания простых перьев связан с вызовом функции CreatePenIndirect:

HPEN CreatePenIndirect(CONST LOGPEN* lplgpn);

Этой функции в качестве параметра передается адрес структуры типа LOGPEN:

typedef struct tagLOGPEN {

UINT

style;

// стиль пера

POINT

width;

// толщина в логических единицах

COLORREF

color;

// öâåò

} LOGPEN;

 

 

Член структуры width имеет тип POINT, но Windows использует только величи ну width.x как толщину пера и игнорирует значение width.y.

Таким образом, сначала определяется переменная типа LOGPEN, например:

LOGPEN logpen;

Затем полям этой переменной присваиваются нужные значения, например:

logpen.style = PS_SOLID; logpen.width.x = 10; logpen.color = RGB(255, 0, 0);

И только после этого вызывается функция CreatePenIndirect:

hPen = CreatePenIndirect(&logpen);

1 См. раздел «Управление цветом. Вывод пиксела».

92

Глава 2. GDI — графический интерфейс устройства

 

 

Простые перья, созданные с помощью функции CreatePenIndirect, обладают точ но такими же характеристиками, что и перья, созданные функцией CreatePen.

Обратите внимание на то, что функции CreatePen и CreatePenIndirect не требуют дескриптора контекста устройства. Они создают логические перья, которые никак не связаны с контекстом устройства, пока не будет вызвана функция SelectObject.

Покажем возможный сценарий использования нескольких перьев в программе. Допустим, приложению требуются три нестандартных пера: красное толщиной 2, зеленое толщиной 5 и синее пунктирное. Сначала нужно определить переменные для хранения дескрипторов этих перьев:

static HPEN hPen1, hPen2, hPen3;

Сами перья могут быть созданы в процессе обработки сообщения WM_CREATE:

hPen1 = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));

hPen2 = CreatePen(PS_SOLID, 5, RGB(0, 255, 0)); hPen3 = CreatePen(PS_DASH, 1, RGB(0, 0, 255));

В процессе обработки сообщения WM_PAINT можно выбрать одно из этих перь ев в контекст устройства и рисовать с его помощью:

SelectObject(hDC, hPen1);

//... функции рисования линий SelectObject(hDC, hPen2);

//... функции рисования линий

Впроцессе обработки сообщения WM_DESTROY рекомендуется удалить эти перья:

DeleteObject(hPen1);

DeleteObject(hPen2);

DeleteObject(hPen3);

Это наиболее общий подход. Но возможны и другие сценарии. Например, мож но создать перо в блоке обработки сообщения WM_PAINT и удалить его перед вызо вом функции EndPaint или даже после ее вызова.

Кроме того, можно создавать перья «на лету», объединяя вызовы функций

CreatePen и SelectObject в одну инструкцию:

SelectObject(hDC, CreatePen(PS_DOT, 0, RGB(255, 255, 0)));

Теперь последующее рисование линий будет выполняться желтым пером с то чечным стилем. Закончив рисовать, нужно удалить выбранное перо. Но как это сделать, если его дескриптор не сохранен? В этом случае на выручку приходит функция SelectObject с ее свойством возвращать дескриптор объекта, выбранного в контекст устройства ранее. Таким образом, можно удалить перо при помощи выбора стандартного пера BLACK_PEN в контекст устройства и удаления значения, возвращенного функцией SelectObject:

DeleteObject(SelectObject(hDC, GetStockObject(BLACK_PEN)));

Рассмотрим слегка модифицированную версию последнего примера. Дело в том, что можно сохранить дескриптор пера при первом вызове SelectObject:

hPen = SelectObject(hDC, CreatePen(PS_DOT, 0, RGB(255, 255, 0)));

Если это первый вызов SelectObject после получения дескриптора контекста устройства, то hPen примет значение дескриптора стандартного пера BLACK_PEN. Тогда после окончания рисования выбранным пером его удаление можно совмес тить с возвратом в контекст устройства стандартного пера:

DeleteObject(SelectObject(hDC, hPen));

Перья

93

 

 

 

Расширенные перья

Простые перья, рассмотренные в предыдущем разделе, обладают ограниченными возможностями. Так, стилевые линии можно рисовать только толщиной 1 пик сел, а сплошные линии рисуются любой толщиной, но всегда имеют закруглен ные окончания.

Для преодоления этих ограничений в Win32 API появилась новая функция ExtCreatePen, создающая перья с расширенным набором атрибутов:

HPEN ExtCreatePen(

 

DWORD dwPenStyle,

// тип, стиль и атрибуты пера

DWORD dwWidth,

// толщина

CONST LOGBRUSH* lplb,

// атрибуты кисти

DWORD dwStyleCount,

// длина массива lpStyle

CONST DWORD* lpStyle

// массив, задающий правила чередования пикселов

);

 

Параметр dwPenStyle может принимать значения в виде комбинации флагов, определяющих тип пера, его стиль, тип завершения линий и тип соединения ли ний. Возможные значения этих флагов приведены в табл. 2.6–2.9.

Таблица 2.6. Типы расширенных перьев

Ôëàã òèïà

Описание

 

 

PS_COSMETIC

Косметическое перо. Толщина равна 1 пиксел

PS_GEOMETRIC

Геометрическое перо. Толщина задается в логических единицах

 

 

Из табл. 2.6 видно, что расширенные перья могут быть косметическими и гео метрическими.

Таблица 2.7. Стили расширенных перьев

Флаг стиля

Описание

Ограничения

 

 

 

PS_ALTERNATE

Чередование «пиксел —

Поддерживается только в Windows NT/2000

 

промежуток»

и только для косметических перьев

PS_SOLID

Непрерывная линия

 

PS_DASH

Пунктирная линия

Windows 95: не поддерживается для

 

 

геометрических перьев. Windows 98:

 

 

не поддерживается

PS_DOT

Точечная линия

Windows 95/98: не поддерживается для

 

 

геометрических перьев

PS_DASHDOT

Пунктирно-точечная линия

Windows 95: не поддерживается для

 

 

геометрических перьев. Windows 98:

 

 

не поддерживается

PS_DASHDOTDOT

Отрезок и две точки

Windows 95: не поддерживается для

 

 

геометрических перьев. Windows 98:

 

 

не поддерживается

PS_NULL

Линия не рисуется

 

PS_INSIDEFRAME

Непрерывная линия.

Только для геометрических перьев

 

Выравнивание внутри контура

 

PS_USERSTYLE

Чередование отрезков и про-

Поддерживается только в Windows NT/2000

 

межутков задается параме-

 

 

трами dwStyleCount и lpStyle

 

 

 

 

94

Глава 2. GDI — графический интерфейс устройства

 

 

Все стили, кроме PS_INSIDEFRAME, имеют выравнивание по центру. Интерпре тация этого параметра была приведена при описании простых перьев.

Таблица 2.8. Тип завершения, используемый только для геометрических перьев

Флаг завершения

Описание

 

 

PS_ENDCAP_ROUND

Закругленное завершение, когда к линии добавляется половина круга

PS_ENDCAP_SQUARE

Квадратное завершение, когда к линии добавляется половина квадрата

PS_ENDCAP_FLAT

Плоское завершение

 

 

Таблица 2.9. Тип соединения, используемый только для геометрических перьев

Флаг соединения

Описание

 

 

PS_JOIN_BEVEL

Усеченное соединение

PS_JOIN_MITER

Заостренное соединение

PS_JOIN_ROUND

Закругленное соединение

 

 

Косметические перья

Косметические перья можно использовать только с толщиной 1 пиксел. При по пытке задать большую толщину Windows использует стиль PS_SOLID.

Для стилей PS_DASH, PS_DOT, PS_DASHDOT и PS_DASHDOTDOT косметические пе рья рисуют точно такие же линии, как и простые перья. Однако, в отличие от про стых перьев, они всегда рисуют в прозрачном режиме смешивания фона, даже если в контексте устройства установлен режим OPAQUE.

Для стиля PS_ALTERNATE косметическое перо рисует «настоящую» точечную линию, которую образуют точки размером 1 пиксел и промежутки между точка ми также размером 1 пиксел.

Для использования стиля PS_USERSTYLE необходимы два дополнительных па раметра: dwStyleCount задает количество элементов в массиве с адресом lpStyle. Пер вый элемент массива содержит длину первого отрезка, второй — длину проме жутка, третий — длину второго отрезка и т. д. При этом одна единица длины соответствует трем пикселам вместо одного.

Геометрические перья

Геометрические перья рисуют линии, которые могут различаться толщиной, сти лем, заливкой, типом завершения и типом соединения.

Толщина геометрического пера задается в логических координатах. Если в про стых перьях единица длины, соответствующая изображению точки, равна 3 пик села, то в геометрических перьях единица длины в режиме отображения MM_TEXT равна 1 пиксел. Но с увеличением толщины линии пропорционально увеличива ется и длина точки, равно как и длина других отрезков, составляющих линию. Также эти размеры могут изменяться в соответствии с мировыми преобразовани ями или режимом отображения.

В отличие от простых перьев, утолщенные геометрические перья рисуют ли нии в соответствии со своим стилем, как показано на рис. 2.9.

Из рисунка также видно, что геометрические перья по умолчанию имеют завер шение, определяемое стилем PS_ENDCAP_ROUND. Но тип завершения можно изменить, если при вызове функции ExtCreatePenпередать первый параметр с добавлением флага

Перья

95

 

 

 

из табл. 2.8. На рис. 2.10 показано, как выглядит буква Z, состоящая из трех утолщенных линий с разными завершениями. Линии нарисованы при помощи фун кции LineTo. Для большей четкости картины в местах стыковки вторая линия нарисо вана более светлым пером, чем первая и третья линии. Тонкие белые линии, нанесен ные поверх фигуры, обозначают положение базовых осей каждой линии.

Рис. 2.9. Простые и расширенные геометрические перья толщиной 10 пикселов

Рис. 2.10. Стыковка линий с разными завершениями

Учтите, что если вы будете рисовать при помощи функции LineTo все три ли нии пером одного и того же цвета в режиме рисования R2_XORPEN, то на стыках из за повторной прорисовки образуются «провалы», как показано на рис. 2.11, слева. Та же Z образная фигура, нарисованная функцией Polyline (на рис. 2.11 в центре и справа), таких провалов не имеет. При этом фигура справа демонстрирует воз можность заливки линий с помощью кисти. В данном случае перед созданием гео метрического пера поле lbStyle структуры LOGBRUSH было установлено в значение

BS_HATCHED, а поле lbHatch — в значение HS_DIAGCROSS1.

Рис. 2.11. Рисование геометрическим пером в режиме рисования R2_XORPEN

Функция Polyline относится к группе функций GDI, позволяющих выполнить рисование нескольких линий и кривых за один вызов. Функции этой группы обла дают тем замечательным свойством, что обеспечивают плавную стыковку линий. Именно для них имеет значение тип соединения геометрического пера, устанавли ваемый флагом из табл. 2.9. По умолчанию в контексте устройства используется флаг PS_JOIN_ROUND. На рис. 2.12 показаны различные типы соединений в сочета нии с разными типами завершения геометрического пера. Рисование производи лось при помощи функции Polyline.

1 Работа с объектом логической кисти рассматривается далее в разделе «Кисти».

96

Глава 2. GDI — графический интерфейс устройства

 

 

Рис. 2.12. Рисование с помощью Polyline для разных типов соединений и разных типов завершения геометрического пера

Перейдем теперь к рассмотрению рисования замкнутых фигур.

Любая замкнутая фигура, например прямоугольник или эллипс, рисуется в Windows с использованием двух графических объектов, выбранных в контекст устройства. Первым объектом является текущее перо, которым обводится контур фигуры, а вторым объектом — текущая кисть, используемая для заливки (закра шивания) внутренней области фигуры. Контекст устройства содержит кисть по умолчанию, которой является сплошная кисть белого цвета. Обычно фон окна тоже имеет белый цвет, поэтому, рисуя замкнутые фигуры с кистью по умолча нию, нельзя увидеть эффект заливки. В связи с этим стоит сначала научиться соз давать и использовать различные кисти, а уже потом знакомиться с функциями, рисующими замкнутые фигуры.

Кисти

Кисть — это растр размером 8 × 8 пикселов, который при закрашивании области дублируется в горизонтальном и вертикальном направлении. Когда Windows ис пользует смешивание (dithering) для отображения большего числа цветов, чем до ступно на дисплее, то на самом деле для этого используется кисть. На монохром ном дисплее, например, смешивание черных и белых пикселов позволяет получить 64 разных оттенка серого цвета. На цветных видеосистемах полутона тоже реали зуются при помощи подобных растровых образов, но с гораздо более широким набором доступных цветов.

Win32 GDI предоставляет несколько функций для создания объектов логичес ких кистей. Логическая кисть описывает требования, предъявляемые к заливке со стороны приложения. Эти требования не всегда совпадают с возможностями фи зических устройств. Драйверы устройств поддерживают собственные структуры данных, определяющие реализацию логической кисти. Такие внутренние объекты называются физическими кистями.

Кисти

97

 

 

 

Для дескрипторов логических кистей зарезервирован тип HBRUSH (handle to a brush), поэтому новая кисть объявляется следующим образом:

HBRUSH hBrush;

Значение дескриптора получают вызовом соответствующей функции. Вид вы зываемой функции зависит от типа кисти. Так же как и при работе с перьями, созданные кисти выбираются в контекст устройства с помощью функции SelectObject, после чего заливка всех замкнутых фигур осуществляется выбранной кистью. Ког да кисть перестает быть нужной, рекомендуется вернуть в контекст устройства прежнюю кисть, а ненужную кисть удалить при помощи функции DeleteObject. В разделе «Простые перья» были приведены возможные сценарии использова ния нескольких перьев в одном приложении. Аналогичные сценарии можно ис пользовать и для работы приложения с несколькими кистями.

Стандартные кисти

Стандартные кисти, предоставляемые GDI, приведены в табл. 2.10.

Таблица 2.10. Стандартные кисти

Индекс кисти

Описание

 

 

BLACK_BRUSH

Черная кисть

DKGRAY_BRUSH

Темно-серая кисть

DC_BRUSH

Кисть DC — сплошная цветная кисть; по умолчанию имеет белый цвет; цвет

 

может быть изменен функцией SetDCBrushColor

GRAY_BRUSH

Серая кисть

HOLLOW_BRUSH

Пустая кисть (заливки нет)

LTGRAY_BRUSH

Светло-серая кисть

NULL_BRUSH

Òî æå, ÷òî è HOLLOW_BRUSH

WHITE_BRUSH

Белая кисть, которая используется по умолчанию

 

 

Все кисти, приведенные в таблице, — сплошные, то есть все 8 × 8 пикселов растра имеют один и тот же цвет. Кисть DC, реализованная только в Windows 2000, относится к числу новых средств GDI. Так же как и перо DC, кисть DC позволяет изменять свой цвет после ее выбора в контекст устройства. Для этого предназна чена функция SetDCBrushColor.

Чтобы получить дескриптор стандартной кисти, достаточно вызвать функцию GetStockObject с одной из констант, приведенных в табл. 2.10, например:

hBrush = (HBRUSH) GetStockObject(GRAY_BRUSH);

Пользовательские кисти

Стандартные кисти хороши простотой своего использования, но их возможности явно недостаточны для нужд многих приложений. Поэтому Windows содержит функции, создающие пользовательские кисти следующих типов: сплошные кисти,

штриховые кисти и растровые кисти.

Сплошные кисти

Сплошная кисть создается вызовом функции CreateSolidBrush:

HBRUSH CreateSolidBrush(COLORREF crColor);

98

Глава 2. GDI — графический интерфейс устройства

 

 

Ее единственному параметру crColor передается цвет кисти в виде значения типа COLORREF. Обычно это значение задается при помощи макроса RGB или PALETTERGB1. Первый вариант используется, если устройство вывода поддерживает полный диапазон цветов, определяемый 24 битным RGB значением. В этом случае при ложению нет необходимости работать с палитрой. Второй вариант необходимо использовать, если приложение работает с логической палитрой. В последнем случае Windows преобразует запрошенный в макросе PALETTERGB цвет в наиболее подходящий индекс палитры. Если подходящий индекс не найден, то устройство имитирует нужный цвет, комбинируя доступные цвета при помощи смешения (dithering).

Примеры использования сплошной кисти можно найти в листингах глав 3 и 6.

Штриховые кисти

Штриховая кисть создается вызовом функции CreateHatchBrush:

HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);

Параметр fnStyle, задающий стиль штриховки, может принимать значения

HS_HORIZONTAL, HS_VERTICAL, HS_BDIAGONAL, HS_FDIAGONAL, HS_CROSS и HS_DIAGCROSS. На рис. 2.13 показано, как выглядят эти стили при заливке прямоугольников размером 64 × 64 пиксела (верхний ряд). В нижней части рисунка приведены в увеличенном виде минимальные блоки, соответствующие этим штриховым ки стям. Каждый минимальный блок представляет собой растр размером 8 × 8 пик

селов.

Рис. 2.13. Стили штриховых кистей

В штриховых кистях пикселы делятся на основные и фоновые. На рис. 2.13 ос новные пикселы показаны более темным цветом. Цвет основных пикселов зада ется параметром clrref, а цвет фоновых пикселов определяется атрибутом цвета фона графических элементов в контексте устройства, который можно устанавли вать при помощи функции SetBkColor. Фоновые пикселы выводятся только в том случае, если установлен режим смешивания фона OPAQUE.

GDI позволяет также устанавливать базовую точку штриховой кисти с помо щью функции SetBrushOrgEx:

BOOL SetBrushOrgEx(HDC hdc, int nXOrg, int nYOrg, LPPOINT lppt);

Базовая точка (nXOrg, nYOrg), задаваемая в системе координат устройства, оп ределяет привязку левого верхнего пиксела штрихового узора. Остальные блоки пикселов выстраиваются соответствующим образом. Параметр lppt содержит ад рес структуры типа POINT, в которой запоминается прежняя базовая точка. По умолчанию координаты базовой точки кисти равны (0, 0).

1 См. раздел «Управление цветом. Вывод пиксела».

Кисти

99

 

 

 

Предположим, что вы рисуете прямоугольник, имея перо толщиной 1 пик сел, и используете штриховую кисть для заливки. Если вы хотите, чтобы левый верхний угол первого пиксельного блока штриховой кисти в точности совпадал с левым верхним углом заливаемой области, то этого можно достичь вызовом функции

SetBrushOrgEx(hDC, xLeft + 1, yTop + 1, NULL);

где xLeft и yTop — координаты левого верхнего угла прямоугольника. Обратите внимание на то, что смещение на единицу обусловлено единичной толщиной ис пользуемого пера.

Растровые кисти

Растровая (или узорная) кисть создается при помощи функции CreatePatternBrush:

HBRUSH CreatePatternBrush(HBITMAP hbmp);

Параметр hbmp содержит дескриптор растрового объекта GDI.

Поскольку растровый объект GDI (bitmap), называемый также аппаратно зависимым растром (DDB)1, может содержать произвольное изображение, то про граммист получает неограниченные возможности создания рисунков для залив ки замкнутых областей.

Давайте проведем следующий эксперимент с растровой кистью. При помощи графического редактора MS Paint создайте рисунок размером 32 × 32 пиксела, содержащий изображение пятиконечной звезды, как показано на рис. 2.14. Это изображение следует сохранить в файле Star.bmp.

Рис. 2.14. Изображение звезды, созданное в редакторе MS Paint

Затем вставьте в код программы Hello2, как мы это делали раньше, следующий фрагмент:

{

HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "Star.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

HBRUSH hBrush = CreatePatternBrush(hBmp);

HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); Rectangle(hDC, 32, 32, 288, 160); DeleteObject(SelectObject(hDC, hOldBrush));

}

Функция LoadImage в этом фрагменте загружает аппаратно независимый растр (DIB)2 из файла Star.bmp, затем преобразует его к формату растрового объекта GDI и возвращает дескриптор этого объекта hBmp. Полученный дескриптор пе редается функции CreatePatternBrush, создающей растровую кисть. Кисть hBrush

1 Вопросы использования растров рассматриваются в главе 3.

2 Аппаратно зависимые и аппаратно независимые растры рассматриваются в главе 3.

100

Глава 2. GDI — графический интерфейс устройства

 

 

выбирается в контекст устройства и после этого используется для заливки внут ренней области прямоугольника, рисуемого функцией Rectangle1.

Чтобы программа смогла загрузить файл Star.bmp, нужно поместить его в пап ку с проектом Hello2. После компиляции и запуска на выполнение программа долж на нарисовать прямоугольник, показанный на рис. 2.15.

Рис. 2.15. Заливка прямоугольника растровой кистью

В системах Windows 95/98 накладывается ограничение на применение рас тровых кистей. Битовые образы кистей не могут превышать размер 8 × 8 пиксе лов. В случае превышения размера используется квадрат 8 × 8 из левого верхнего угла изображения.

Пример использования растровой кисти приведен в главе 11.

Структура LOGBRUSH и функция CreateBrushIndirect

Win32 GDI предоставляет еще одну функцию — CreateBrushIndirect, позволяющую создать логическую кисть любого из трех рассмотренных выше типов:

HBRUSH CreateBrushIndirect(CONST LOGBRUSH* lplb);

Параметр lplb — это адрес структуры типа LOGBRUSH, в которой задаются пара метры кисти:

typedef struct tagLOGBRUSH { UINT lbStyle; COLORREF lbColor;

LONG lbHatch; } LOGBRUSH;

Поле lbStyle задает стиль кисти и может иметь одно из значений, приведенных в табл. 2.11.

Таблица 2.11. Возможные значения поля lbStyle

Значение

Описание

 

 

BS_SOLID

Сплошная кисть

BS_HATCHED

Штриховая кисть

BS_HOLLOW

Пустая кисть (заливки нет)

BS_NULL

Òî æå, ÷òî è BS_HOLLOW

BS_PATTERN

Растровая кисть, рисунок которой определен растровым изображением

 

в памяти

BS_PATTERN8X8

Òî æå, ÷òî è BS_PATTERN

BS_DIBPATTERN

Растровая кисть, рисунок которой задается аппаратно-независимым

 

растровым изображением (DIB — device-independent bitmap), дескриптор

 

которого содержится в поле lbHatch

 

 

1 Функции, рисующие замкнутые фигуры, рассматриваются в следующем разделе.