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