Косметические перья работают значительно
быстрее, чем другие, но это имеет значение
только для сложных рисунков. Геометрическое перо
может иметь любую толщину и любые атрибуты
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
пиксел выдерживает подобное испытание и его
можно использовать для графиков функций. |