Геометрическое
перо
Косметические
перья работают значительно быстрее, чем другие, но это имеет значение только
для сложных рисунков. Геометрическое перо может иметь любую толщину и любые
атрибуты Windows-кисти (dither и pattern). Введем дополнения,
которые позволят исследовать свойства геометрического пера. В число локальных
переменных функции WndProc введите новые сущности:
//======
Узоры штрихов (hatch) кисти, на основе
//======
которых будет основано перо
static
UINT uHatch[] =
{
HS_BDIAGONAL,
HS_CROSS, HS_DIAGCROSS,
HS_FDIAGONAL,
HS_HORIZONTAL, HS_VERTICAL
};
//=====
Строки текста для пояснений
static
string brush[] =
{
"HS_BDIAGONAL",
"HS_CROSS", "HS_DIAGCROSS",
"HS_FDIAGONAL",
"HS_HORIZONTAL", "HS_VERTICAL"
};
Вставьте следующий
код в ветвь WM_PAINT перед вызовом EndPaint. Этот фрагмент по структуре такой
же, как и предыдущий, но здесь мы создаем перо, используя штриховую (hatched)
кисть. Запустите и проверьте, что получилось. Попробуйте объяснить, почему линия
со штрихом типа HS_HORIZONTAL невидима. Замените строку
LineTo(hdc,
iXMax, iYPos);
на
LineTo(hdc,
iXMax, iYPos + 3);
и запустите
вновь. Теперь линия должна быть видна. Найдите объяснение и попробуйте обойтись
без последнего изменения кода, то есть уберите +3:
//========
геометричесое
перо
Ib.lbStyle
= BS_HATCHED; // Узорная кисть
sText
= "Стили на основе кисти (Geometric pen)";
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 ());
nLines
=
sizeof(brush)/sizeof(brush[0]);
for
(i = 0; i < nLines; i ++ )
{
//=======
Выбираем узор штриха кисти
Ib.lbHatch
= uHatch[i];
//==
Создаем на его основе перо тощиной 5 пиксел
HPEN
hp = ExtCreatePen(PS_GEOMETRIC, 5, Sib,0,0);
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, brush[i].c_str(), brush[i].size());
}
Геометрическое
перо может быть создано на основе заданного пользователем или программистом
узора (PS_USERSTYLE). Узор задается с помощью массива переменных типа DWORD.
Элементы массива определяют циклический алгоритм закраски линии по схеме «играем
— не играем». Например, массив DWORD а [ ] = { 2,3,4 } определяет линию, у которой
2 пиксела закрашены, 3 — не закрашены, 4 — закрашены. Затем цикл (2,3,4) повторяется.
Для моделирования этой возможности введите в WndProc еще один двухмерный массив
(так как линия будет не одна):
//=======
три узора геометрического
пера
static
DWORD dwUser[3][4] =
{
{
8, 3, 3, 3),
{
3, 3, 3, 3),
(15,
4, 3, 4}
};
Затем добавьте
вслед за фрагментом, моделирующим штриховую линию, следующий код:
//=======
Геометричесое перо (user-defined)
Ib.lbStyle
- BS_SOLID;
sText
= "Стили на основе узора (Geometric pen)";
GetTextExtentPoint(hdc,sText.c_str(),
sText.size(),SszText);
iYPos
+= 2 * szText.cy;
iXPos
= iXCenter - szText.cx/2;
TextOutfhdc,
iXPos, iYPos,
sText.c_str(),
sText .size () } ,
nLines
=
sizeof(dwUser)/sizeof(dwUser[0]) ;
//======
Перебираем узоры пользователя
//======
(строки массива dwUser)
for
(i = 0; i < nLines; i++)
{
DWORD
dw = PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT;
HPEN
hp = ExtCreatePen(dw, i+2, Sib, 4, dwUser[i]);
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, user[i].c_str(), user[i].size());
}
Запустите и
проверьте результат. Здесь следует отметить, что узор имеет возможность развиться
(разогнаться) только на достаточно большом промежутке между точками. Для вывода
графиков функциональных зависимостей он, к сожалению, не пригоден, так как графики
имеют большое количество точек. Точки расположены тесно, а узор начинается заново
после каждой пары точек. Как ни странно, косметическое перо толщиной в 1 пиксел
выдерживает подобное испытание и его можно использовать для графиков функций.