Косметическое
перо
Сначала исследуем
косметическое перо. Некоторые его стили, задаваемые символьными константами,
занесем в массив. Введем внутрь тела оконной процедуры (после объявления CustColors)
объявления новых локальных переменных:
//======
х-координаты:
static
int iXCenter; // центра окна,
static
int iXPos; // текущей позиции
static
int iXMax; // допустимой позиции
int
iYPos =0; // Текущая у-координата вывода
int
nLines; // Количество линий
SIZE
szText; // Экранные размеры строки текста
//======
Стили пера Windows
static
DWORD dwPenStyle[] =
{
PS_NULL,
PS_SOLID, PS_DOT, PS_DASH,
PS__DASHDOT,
PS_DASHDOTDOT
};
//======
Строки текста для вывода в окно
static
string style[] =
{
"PS_NULL","PS_SOLID","PS_DOT","PS_DASH",
"PS_DASHDOT","PS_DASHDOTDOT"
};
string
sText; // Дежурная строка текста
//=====
Логическая кисть — как основа для создания пера
LOGBRUSH
lb = { BS_SOLID, color, 0 };
Если
вы хотите, чтобы ваш вывод в окно реагировал на изменения пользователем размеров
окна, то всегда вводите в оконную процедуру ветвь обработки WM_SIZE. Сделайте
это сейчас вместе с изменениями в ветви WM_PAINT:
case
WM_SIZE:
//====
В IParam упрятаны размеры окна.
//====
Нас интересует только ширина окна
iXMax
= LOWORD(IParam) - 50;
iXCenter
= LOWORD(IParam)/2; break;
case
WM_PAINT:
hdc
= BeginPaint(hWnd, &ps);
//=====
Режим выравнивания текста (см. MSDN)
SetTextAlign(hdc,
TA_NOUPDATECP | TA_LEFT | TA_BASELINE) ;
sText
= "Стили линий в Win32 (Cosmetic pen)";
//==
Выясняем размеры строки с текстом заголовка GetTextExtentPoint(hdc,sText.c_str(),
sText.size(),
//==
Сдвигаем точку вывода вниз на одну строку
iYPos
+= szText.cy;
iXPos
= iXCenter - szText.cx/2;
//====
Выводим заголовок
TextOut(hdc,iXPos,
iYPos, sText.c_str(), sText. size ()
}
//====
Перебираем массив стилей пера
nLines
=
sizeof(style)/
sizeof(style[0]);
for
(
int i = 0; i < nLines; i++)
{
//=====
Устанавливаем биты стиля пера
DWORD
dw = PS_COSMETIC | dwPenStyle[i];
//
Создаем перо толщиной в 1 пиксел
HPEN
hp = ExtCreatePen(dw, 1, Sib, 0,NULL);
//=====
Выбираем перо в контекст устройства
HPEN
hOld = (HPEN)SelectObject(hdc,hp); iYPos += szText.cy;
//
Сдвиг позиции
//=====
Помещаем перо в точку (10, iYPos)
MoveToEx(hdc,
10, iYPos, NULL);
//====
Проводим линию до точки (iXMax, iYPos)
LineTo(hdc,
iXMax, iYPos);
//==
Возвращаем старое перо в контекст устройства
SelectObject(hdc,
hold);
//===
Освобождаем ресурс пера DeleteObject(hp);
//===
Выводим поясняющий текст
TextOut(hdc,
10, iYPos, style[i].c_str(), style [i] .size ()
}
;
EndPaint(hWnd,
&ps) ;
break;
Комментарии
в тексте поясняют суть происходящего. Отметьте, что здесь применена стандартная
тактика работы с ресурсами GDI, которая состоит из последовательности следующих
шагов:
- создаем свой инструмент;
- выбираем его в контекст
устройства (SelectObject) и одновременно запоминаем тот инструмент, который
используется в контексте в настоящий момент;
- рисуем с помощью нашего
инструмента;
- возвращаем в контекст
прежний инструмент;
- освобождаем память, занимаемую
нашим инструментом.
Так как система
работает с ресурсами GDI динамически, то нарушение этой тактики может привести
к недостатку памяти и непредсказуемому поведению приложения. Перед тем как запустить
проект, попробуйте ответить на вопросы:
- Будет ли изменяться
цвет линий при пользовании стандартным диалогом, который мы уже реализовали?
- Будет ли изменяться
цвет текста при тех же условиях?
Теперь запустите
приложение и протестируйте его, изменяя размеры окна и пользуясь диалогом. Как
вы узнали из документации, косметическое перо может иметь толщину только в 1
пиксел. Если косметическое перо имеет еще один атрибут PS_ALTERNATE, то каждый
второй пиксел линии пропускается (не выводится) и создается иллюзия, что перо
стало тоньше, чем 1 пиксел. Опробуем эту возможность в нашем примере. Для этого
введите в функцию WndProc еще один локальный массив подсказок.
static
string alt[] =
{"PS_ALTERNATE", "PS_COSMETIC" };
Вставьте следующий
код в ветвь WM_PAINT перед вызовом EndPaint, затем запустите и проверьте результат:
//=======
Косметическое перо (alternate - solid)
Ib.lbStyle
= BS_SOLID;
sText
= "Косметическое перо alternate или solid";
GetTextExtentPoint(hdc,sText.c_str(),
sText.size(),SszText);
iYPos
+= 2 * szText.cy;
iXPos
= iXCenter - szText.cx/2;
TextOut(hdc,
iXPos, iYPos, sText.c_str(), sText.size());
for
(i = 0; i < 2; i+ + ) {
DWORD
dw = i ? PS_COSMETIC : PS_COSMETIC I PS_ALTERNATE;
HPEN
hp = ExtCreatePen(dw, 1, &lb, 0, NULL);
HPEN
hOld = (HPEN)SelectObject(hdc, hp) ;
iYPos
+= szText.cy;
MoveToEx(hdc,
10, iYPos, NULL);
LineTo(hdc,
iXMax,iYPos);
SelectObject(hdc,
hold);
DeleteObject(hp);
TextOut(hdc,
10, iYPos, alt[i].c str(), alt [i] . size ());