Настройка атрибутов контекста отображения для рисования линий
Как это нетрудно заметить, функции, предназначенные для рисования линий, не имеют никаких параметров, определяющих толщину, цвет и стиль линии. Эти, а также другие характеристики (например, режим прозрачности), выбираются при установке соответствующих атрибутов контекста отображения.
Выбор пера
Для рисования линий приложения Windows могут выбрать одно из трех встроенных перьев, либо создать собственное перо.
Для выбора встроенного пера лучше всего воспользоваться макрокомандами GetStockPen и SelectPen , определенными в файле windowsx.h:
#define GetStockPen(i) ((HPEN)GetStockObject(i))#define SelectPen(hdc, hpen) \ ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))Макрокоманда GetStockPen возвращает идентификатор встроенного пера, заданного параметром i. Вы можете выбрать для этого параметра одно из следующих значений:
Значение | Описание |
BLACK_PEN | Перо, рисующее черную линию толщиной в один пиксел (для любого режима отображения). Это перо выбрано в контекст отображения по умолчанию |
WHITE_PEN | Перо белого цвета. Толщина пера также равна одному пикселу и не зависит от режима отображения |
NULL_PEN | Невидимое перо толщиной в один пиксел. Используется для рисования замкнутых закрашенных фигур (таких, как прямоугольник или эллипс) в тех случаях, когда контур фигуры должен быть невидимым |
После получения идентификатора пера его необходимо выбрать в контекст отображения при помощи макрокоманды SelectPen. Первый параметр этой макрокоманды используется для указания идентификатора контекста отображения, в который нужно выбрать перо, второй - для передачи идентификатора пера.
Макрокоманда SelectPen возвращает идентификатор пера, который был выбран в контекст отображения раньше. Вы можете сохранить этот идентификатор и использовать его для восстановления старого пера.
Однако при помощи встроенных перьев вы не можете нарисовать цветные, широкие, штриховые и штрих-пунктирные линии.
Если вас не устраивают встроенные перья, вы можете легко создать собственные. Для этого нужно воспользоваться функциями CreatePen или CreatePenIndirect.
Функция CreatePen позволяет определить стиль, ширину и цвет пера:
HPEN WINAPI CreatePen( int fnPenStyle, // стиль пера int nWidth, // ширина пера COLORREF clrref); // цвет пераПараметр fnPenStyle определяет стиль линии и может принимать одно из следующих значений, определенных в файле windows.h:
Стиль линии | Внешний вид | Описание |
PS_SOLID | Сплошная | |
PS_DASH | Штриховая | |
PS_DOT | Пунктирная | |
PS_DASHDOT | Штрих-пунктирная, одна точка на одну линию | |
PS_DASHDOTDOT | Штрих-пунктирная, две точки на одну линию | |
PS_NULL | Невидимая | |
PS_INSIDEFRAME | Линия, предназначенная для обводки замкнутых фигур |
Параметр nWidth определяет ширину пера. Используемая при этом единица длины зависит от режима отображения, поэтому вы можете задавать ширину пера не только в пикселах, но и в долях миллиметра или дюйма. Учтите, что для линий PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT можно использовать только единичную или нулевую ширину, в обоих случаях ширина линии будет равна одному пикселу. Поэтому вы не можете создать перо для рисования, например, пунктирной линии шириной 5 миллиметров.
Параметр clrref задает цвет пера.
На первый взгляд линии PS_SOLID и PS_INSIDEFRAME похожи, однако между ними имеются различия, особенно заметные для широких линий. Широкая линия, имеющая стиль PS_SOLID, располагается по обе стороны оси, заданной координатами линии. Линии, имеющие стиль PS_INSIDEFRAME, располагаются внутри контура, определяющего размеры замкнутой фигуры (рис. 2.14).
Рис. 2.14. Использование стилей PS_SOLID и PS_INSIDEFRAME
Еще одно отличие связано с использованием смешанных цветов (dithered color). Когда Windows не может в точности подобрать цвет, указанный для толстой линии стиля PS_INSIDEFRAME, он раскрашивает эту линию с использованием смешанного цвета, полученного из других цветов. В этом случае изображение линии формируется из отдельных точек разных цветов. Техника смешанных цветов может применяться и при закрашивании замкнутых фигур, о чем мы еще будем говорить.
При рисовании тонких линий, а также линий, имеющих другой стиль, используются только чистые цвета.
Небольшое замечание относительно концов толстых линий. Концы толстых линий закруглены (рис. 2.15).
Рис. 2.15. Закругленные концы толстой линии
Для изображения толстой линии с прямыми концами следует задать прямоугольную область ограничения (см. ниже раздел, посвященный области ограничения). Можно также нарисовать толстую линию как закрашенный прямоугольник с использованием тонкого пера.
Другая возможность создать перо - вызвать функцию CreatePenIndirect :
HPEN WINAPI CreatePenIndirect(LOGPEN FAR* lplgpn);Эта функция работает аналогично функции CreatePen, однако в качестве параметра ей необходимо передать указатель на структуру типа LOGPEN, в которой должны находиться характеристики создаваемого пера.
Структура LOGPEN и различные указатели на нее определены в файле windows.h:
typedef struct tagLOGPEN{ UINT lopnStyle; // стиль пера POINT lopnWidth; // ширина пера COLORREF lopnColor; // цвет пера} LOGPEN;typedef LOGPEN* PLOGPEN;typedef LOGPEN NEAR* NPLOGPEN;typedef LOGPEN FAR* LPLOGPEN;Заметим, что ширина пера в данном случае находится в поле x структуры POINT. Поле y не используется.
Если вы создали перо, его можно выбрать в контекст отображения при помощи макрокоманды SelectPen. После этого можно рисовать линии обычным образом, вызывая функции MoveToEx и LineTo.
Созданные вашим приложением перья принадлежат GDI, соответствующие структуры данных располагаются в его сегменте данных. Поэтому если перо больше не нужно, его нужно удалить для освобождения памяти.
Прежде чем удалять созданное вами перо, следует выбрать в контекст отображения одно из встроенных перьев (например то, которое использовалось раньше). После этого для удаления вашего пера нужно вызвать макрокоманду DeleletePen , определенную в файле windowsx.h:
#define DeletePen(hpen) DeleteObject((HGDIOBJ)(HPEN)(hpen))В качестве параметра этой макрокоманде необходимо передать идентификатор удаляемого пера.
Нельзя удалять перо, если оно выбрано в контекст отображения. Нет никакого смысла в удалении встроенных перьев.
Выбор режима фона
Режим фона влияет на заполнение промежутков между штрихами и точками в штрих-пунктирных, штриховых и пунктирных линиях.
Напомним, что по умолчанию в контексте отображения установлен непрозрачный режим фона OPAQUE . В этом режиме промежутки закрашиваются цветом фона, определенным как атрибут контекста отображения. Приложение может установить прозрачный режим фона TRANSPARENT , в этом случае промежутки в линиях не будут закрашиваться (рис. 2.16).
Рис. 2.16. Режимы фона OPAQUE и TRANSPARENT
Для установки режима фона предназначена функция SetBkMode :
int WINAPI SetBkMode(HDC hdc, int fnBkMode);Эта функция устанавливает новый режим фона fnBkMode для контекста отображения hdc, возвращая в случае успеха код старого режима фона.
Для параметра fnBkMode вы можете использовать значения OPAQUE или TRANSPARENT, определенные в файле windows.h.
Приложение может определить текущий режим фона, вызвав функцию GetBkMode :
int WINAPI GetBkMode(HDC hdc);С помощью функций SetBkColor и GetBkColor вы можете, соответственно, установить и определить текущий цвет фона, который используется для закраски промежутков между штрихами и точками линий:
COLORREF WINAPI SetBkColor(HDC hdc, COLORREF clrref);COLORREF WINAPI GetBkColor(HDC hdc);Выбор режима рисования
Возвращаясь к обычной бумаге и карандашу, отметим, что в процессе рисования графит (или иной материал) переносится с острия карандаша на поверхность бумаги. Цвет полученной линии полностью соответствует цвету карандаша и не зависит от цвета бумаги. По умолчанию в контексте отображения выбран именно такой режим рисования , т. е. цвет рисуемой линии не зависит от цвета изображения, поверх которого рисуется линия.
Однако это не единственная возможность. При выборе соответствующего режима рисования цвет линии (на растровых устройствах вывода, таких, как экран монитора) может зависеть от цвета подложки, причем зависимость может быть достаточно сложная.
Для выбора режима рисования предназначена функция SetROP2 :
int WINAPI SetROP2(HDC hdc, int fnDrawMode);Параметр hdc предназначен для указания контекста отображения, в котором необходимо установить новый режим рисования, определяемый параметром fnDrawMode.
Функция SetROP2 возвращает код предыдущего режима рисования.
Процесс рисования на экране монитора заключается в выполнении логической операции над цветами точек экрана и цветами изображения. Ниже в таблице мы привели возможные значения для параметра fnDrawMode. Для каждого режима рисования в этой таблице есть формула, с использованием которой вычисляется результат, и краткое описание режима рисования. В формулах цвет пера обозначается буквой P, цвет подложки - D.
Режим рисования | Формула | Цвет пиксела |
R2_COPYPEN | P | Соответствует (равен) цвету пера |
R2_BLACK | Черный | |
R2_WHITE | Белый | |
R2_NOP | D | Не меняется, т. е. перо ничего не рисует |
R2_NOT | ~D | Получается инвертированием цвета подложки, т. е. цвета пиксела до рисования |
R2_NOTCOPYPEN | ~P | Получается инвертированием цвета пера |
R2_MASKPEN | P&D | Комбинация компонент цветов, имеющихся как в цвете подложки, так и в цвете пера |
R2_NOTMASKPEN | ~(P&D) | Инверсия предыдущего значения |
R2_MERGEPEN | P|D | Комбинация компонент цветов подложки и пера |
R2_NOTMERGEPEN | ~(P|D) | Инверсия предыдущего значения |
R2_XORPEN | P^D | При определении цвета пиксела выполняется операция "ИСКЛЮЧАЮЩЕЕ ИЛИ" между компонентами цвета подложки и пера |
R2_NOTXORPEN | ~(P^D) | Инверсия предыдущего значения |
R2_MASKNOTPEN | ~P & D | Комбинация цвета подложки и инверсии цвета пера |
R2_MASKPENNOT | P & ~D | Комбинация двух цветов: инверсии цвета подложки и цвета пера |
R2_MERGENOTPEN | ~P | D | Комбинация компонент цветов подложки и инверсии цвета пера |
R2_MERGEPENNOT | P | ~D | Комбинация инверсии цвета подложки и цвета пера |
Если изображение и перо черно-белые, результат выполнения описанных выше операций (которые, кстати, называются растровыми операциями ) можно легко предсказать.
В режиме R2_COPYPEN, который установлен в контексте отображения по умолчанию, цвет нарисованной линии будет такой же, как и цвет пера. Для режимов R2_BLACK и R2_WHITE цвет линии будет, соответственно, черный и белый. В режиме R2_NOP вы не увидите нарисованную линию, так как цвет вдоль нее вообще не изменится. Более интересен режим R2_NOT, при использовании которого на черном фоне будет нарисована белая линия, а на белом фоне - черная.
Для цветных изображений перечисленные выше формулы применяются по отдельности к каждой компоненте цвета (всего в Windows используется три компоненты цвета - красная, зеленая и голубая), поэтому для некоторых режимов рисования цвет линии предсказать достаточно трудно. Использование цветовых палитр, которые мы рассмотрим в третьей главе нашей книги, дополнительно усложняет эту задачу.
С помощью функции GetROP2 приложение может определить режим рисования, установленный для контекста отображения hdc:
int WINAPI GetROP2(HDC hdc);