Пользовательский стиль пера. Часть I: GDI

В прошлой статье я наотрез отказался рассматривать два последних параметра в функции ExtCreatePen, отвечающих за пользовательский стиль пера. Хотя упоминал про ГОСТы и прочую формальность. Давайте теперь рассмотрим их.

Что такое пользовательский стиль пера

Стиль пера — это последовательность отрезков заданной длины и интервалов между ними. Тире, точка, тире-точка-точка. Есть возможность выбрать предопределённые стили. Но также есть возможность задать и свою последовательность отрезков. Вот такая своя последовательность и называется пользовательским стилем.

Где это может понадобиться

Если заглянем в ГОСТ 2.303-68, то можем увидеть, что параметры разнообразных штрих-пунктирных линий весьма формализованы. Люди, которые будут использовать наш софт, могут хотеть придерживаться этих формальностей. Поэтому, желательно, чтобы наши пунктиры позволяли соответствовать стандартам.

Например:

4. Штриховая
5. Штрихпунктирная тонкая
9. Штрихпунктирная с двумя точками тонкая

Не обязательно строго придерживаться стандартов. Надо дать возможность пользователю их придерживаться. Стандарты могут меняться, а мы народ ленивый, чтобы подпрыгивать на каждый чих. Поэтому давайте назовём это заботой о пользователе. И дадим пользователю самому формировать виды линий, которые его устроят. И которые устроят комиссию, принимающую эти чертежи.

Помимо всего вышесказанного, есть ещё и просто задумка программиста, креативный подход, томный художественный взгляд. В статье будут рассмотрены примеры эффекта бегущей линий и эффект «бегущих муравьев». Если первый эффект — это попса, то второй просто незаменим при выделении областей на картинке, чертеже и т.д.

Пользовательский стиль пера в GDI

Как уже говорилось ранее, за пользовательский стиль отвечают два параметра в функции ExtCreatePen.

StyleCountДлина массива настроек стиля
StyleМассив пользовательского стиля

Берём исходник из предыдущей статьи и немного модифицируем.

Во-первых, теперь будем создавать как геометрическое, так и косметическое перо. Пользовательский стиль можно создать для обоих типов.

Во-вторых, учтём, что для косметического пера стиль применим только для толщины, равной единице. Другие ошибочные ситуации обрабатывать не будем, но ниже описаны ситуации, когда перо не будет создано.

В-третьих, по прежнему доступна заливка битмапом. Правда, только для геометрического пера. Она тут не особо нужна, оставил просто как доступную опцию.

Пользовательский стиль содержится в массиве AUserStyle: TArray<Cardinal> (ребят, не могу я уже в Delphi 7 писать, нет её). Давайте воспринимать его просто, как некий массив. В два последних параметры функции передаётся длина массива и сам массив.

Если бы массив стиля был объявлен, как:

То вызов функции выглядел бы так:

В массиве содержатся длины штрихов и пробелов. Например, если посмотреть на DashDotArray чуть выше, то в нём содержится следующая информация: Штрих-2px, Пробел-4px, Штрих-8px, Пробел-4px.

Если размер массива чётный, то тут всё понятно, последовательность штрихов и пробелов неизменна. Что будет, если размер нечётный? Тогда при следующем заходе на начало стиля, GDI будет воспринимать его, как размер не штриха, а пробела.

Рис.1. Чётный и нечётный размеры пользовательского стиля

Чтобы лучше понимать, как себя поведёт нечётный массив, просто допишите мысленно тот же массив в конец. Например: (2 4 8) = (2 4 8 2 4 8). Теперь массив чётный и поведение становится предсказуемым. Что, собственно, рисунок 1 и демонстрирует.

И да! Всё это работает только для стиля PS_USERSTYLE!

Когда создать перо не получится

Для косметического пера

Если при любом стандартном стиле, даже сплошном, попытаться установить толщину пера, не равную единице, нас ждёт фиаско.

Если в массиве стиля какой-нибудь из элементов равен 0, косметическое перо воспримет это как оскорбление. Для геометрического пера указывать ноль можно где угодно, и мы этим воспользуемся чуть ниже.

Для всех перьев

Если параметры функции ExtCreatePen StyleCount и Style не равны 0 и nil, то при попытке создать перо со стилем, отличным от PS_USERSTYLE, не создаст ничего.

И наоборот, если создаёте со стилем PS_USERSTYLE, но в StyleCount и Style ничего нет — то пиши пропало.

Документация по ExtCreatePen прямо говорит, что размер массива стиля не может быть больше 16. Если попытаетесь передать бОльший размер, перо не будет создано. Тут часто делают ошибку, в надежде, что если DWORD, то можно всё. Не, максимум 16, не больше.

[in] cStyle

Длина массива lpStyle в единицах DWORD. Это значение должно быть равным нулю, если dwPenStyle не PS_USERSTYLE.

Число стилей ограничено 16.

Совет

Для пользовательского, да и любого другого стиля, отличного от сплошного, лучше использовать стиль наконечника PS_ENDCAP_FLAT. Если толщина линии будет больше единицы, а наконечник — полукруг, либо квадрат, то чем больше ширина линии, тем ближе будут располагаться концы отрезков друг к другу. В итоге они просто сольются в одну линию. Хотя, на этом тоже можно построить интересный визуальный эффект.

Однако, если мы хотим строгих размеров для штрихов, то наконечник — только PS_ENDCAP_FLAT.

Что касается соединения линий, то тут уж по обстоятельствам. Я предпочитаю PS_JOIN_MITER.

Использование

Изначально планировал показать, как, используя пользовательский стиль пера, можно соблюсти стандарты, миллиметры и расстояния. Но эта затея оказалась аж на целую статью. Да не особо и интересно, если честно. Бросил, допишу потом, если будет интерес у публики.

Намного интересней что-то из области «живых» картинок. Штрих-точка, это здорово, конечно. Но если воспринимать пользовательский стиль не как статичную линию из ГОСТа, а как элемент анимации?

Первая часть будет рассказывать про принцип использования. В реальности, для таких штук надо использовать не GDI (что угодно, только не GDI). А вот почему не надо использовать GDI, и что надо использовать, расскажет вторая часть.

Для анимации и живости в приложении появляется таймер, который увеличивает счётчик FTimerTick на единицу в каждом своём срабатывании.

Бегущая линия

Идея состоит в том, что мы рисуем один и тот же массив координат, но всякий раз с разным стилем, где первый элемент, отвечающий за штрих — всегда ноль, второй — уменьшающийся пробел, третий — бесконечно длинный штрих.

Рис.2. Бегущая линия
Построитель спирали

[свернуть]

Формируем пользовательский стиль таким образом:

Рисуем точно также (ну почти), как и в предыдущей статье:

То есть мы рисуем один и тот же массив. Анимация осуществляется исключительно за счёт пользовательского стиля.

«Однако, я же могу ту же саму спираль нарисовать просто выводя не весь массив, а просто смещать по таймеру указатель на начало в рисуемом массиве» — скажет искушённый программист. И будет прав. Но я показываю модель применения пользовательского стиля, который служит не только для скучных штрих-пунктирных линий.

И потом, как быть с бегущим контуром текста? Неужели заворачиваться, брать массив из пути, считать длину, считать указатель? Когда можно всё сделать быстро, просто и изящно.

Бегущий контур текста

Рис.3. Бегущий контур текста

Использую паттерн для заливки. С кэшем битмапа работа абсолютна такая же, как в предыдущей статье (голимый копипаст, зря что ли публикую). Сама отрисовка (под спойлером):

Отрисовка бегущего контура текста

[свернуть]

В данном случае используем стиль из двух элементов. Первый — это равномерно увеличивающийся (или уменьшающийся) штрих, второй — бесконечный пробел.

Понятно, что на этом принципе можно построить конфетку. Например, затухание при исчезновении. Можно сделать иллюзию пока не проявившихся «новых» нарощенных линий. Эдакий серый след, который приобретает цветность с каждой новой отрисовкой.

Но пока только принцип.

Бегущие муравьи

Незаменимая штука, когда надо выделить какой-то участок изображения. PhotoShop, GIMP, Paint.net и куча других аналогичных продуктов имеют в арсенале этот инструмент. В стандартном API конечно этой прелести нет. Поэтому давайте его реализуем.

Понятно, что мы будем рисовать по-прежнему какой-то статичный массив, но с разным стилем. Предлагается 4 вида таких стилей, которые будут циклично менять друг друга. У нас есть переменная v, которая последовательно принимает значения от 0 до 3.

Мы создаём анимацию с постепенно исчезающим штрихом и появляющимся с другой стороны массива.

Рис.4. Бегущие муравьи

Здесь мы рисуем всё ту же спираль, но бегающими насекомыми.

Листинг отрисовки точно такой же.

Как выглядят муравьи при выделении участка изображения:

Рис.5. Свирепые бегущие муравьи

Вот как их такими сделать, расскажу во второй части. Подписывайтесь на телегу, все новости там.

Продолжение. Пользовательский стиль пера. Часть II: Бегущие муравьи


Скачать

Друзья, спасибо за внимание!

Бегущие линии и бегущие муравьи

Исходник (zip) 282 Кб. Delphi XE 7, XE 10, XE 11

Исполняемый файл (zip) 1.07 Мб.

Бегущий контур текста

Исходник (zip) 79 Кб. Delphi XE 7, XE 10, XE 11

Исполняемый файл (zip) 940 Кб.

Друзья! Буду чрезвычайно признателен за комментарии, регистрацию на сайте, подписку в телеге. Это очень большая моральная поддержка для меня.


5 5 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Не нашли ответ на свой вопрос? Задайте его здесь!...x