C#, Симпатичное окошко "О программе"
Можно сказать, по многочисленным просьбам зрителей. Итак, спрашивали, как устроено в наших программах окошко "О программе" с "эффектом титров". Т.е. список разработчиков и прочее медленно выплывает снизу, проползает по форме и исчезает наверху, часть всплывающих строк останавливается в центре формы, в конце выплывает слоган, так же останавливающийся на некоторое время в центре.
На самом деле, форма была устроена ужасно, написана совсем другими людьми для другого проекта, а у нас кочевала из программы в программу без особых изменений, строки добавлялись в 3
ArrayList
в коде формы, в функции рисования были какие-то непонятные жестко заданные поправочные коэффициенты, подобранные на глаз, и т.д. Решили немного поправить и все переделать. Не знаю, насколько получилось лучше, но понятнее и универсальней точно. Далее будет не столько код с пояснениями, сколько попытка показать, как мы рассуждали, переделывая форму.
Сначала надо определить с какими данными мы будем работать. В первую очередь, мы выводим набор строк, т.е. первая сущность это строка, у строки может быть задан шрифт и цвет текста, и, собственно, содержимое строки - это будут явные параметры сущности. В процессе добавился еще один, неявный параметр - номер сцены
Шрифт целесообразно выделить в отдельную сущность. Во-первых, все используемые шрифты желательно загрузить и сформировать до вывода строк, во-вторых, у шрифта куча своих параметров, и задавать их для каждой отдельной строки неудобно.
Параметры шрифта это FontFamily (Arial, Times New Roman и т.д.), размер и начертание или стиль (жирный, курсив, подчеркнутый,
Последняя сущность это группа строк, или сцена, поскольку строки выводятся группами (см. анимацию). К сцене мы приписали следующие параметры: цвет фона, скорость прокрутки строк (технически задается как таймаут таймера прорисовки) и время паузы (для эффекта остановки группы строк посередине формы, см. анимацию). Неявным параметром будет номер, его зададим позже автоматически, а также высота всех строк сцены и их количество.
Негоже задавать эту кучу параметров непосредственно в коде, поэтому пришлось подумать над форматом данных. Решено было хранить описание строк, шрифтов и сцен в виде простого текстового файла следующего формата:
...
команда;параметр1;параметр2;параметр3 [...]
команда;параметр1;параметр2;параметр3 [...]
команда;параметр1;параметр2;параметр3 [...]
...
Формат команд следующий (в квадратных скобках необязательные параметры):
Шрифт:
addfont; FontFamily; Размер (pt, float); [Стиль]; Внутреннее_имя
Например:
addfont; Arial;9;Bold;Group;
addfont; Microsoft Sans Serif;8;;Names;
addfont; Arial;14;Bold italic;Slogan;
Строка:
addstring; Строка; [Имя_шрифта]; [цвет_текста];
Например:
addstring;Make code, not war! C# like you.;Slogan;FF FF 00;
Сцена:
scene; [цвет_фона];[скорость_таймера_прорисовки ms];[пауза ms]
Например:
scene;20;3000;
Цвет текста задается в шестнадцатеричном формате через пробел(ы): R G B [Alpha]
Например:
FF FF 00
- желтыйFF 00 00 80
- красный с прозрачностьюНачертания (стили) шрифта перечисляются через пробел(ы), от регистра не зависят.
Шрифты:
Генерируются при анализе "скрипта", и помещаются в приватный
Dictionary<string, Font>
, где строковый ключ - заданное "внутреннее имя" шрифта.Строка:
Текст и параметры хранятся в специальной структуре:
private struct AboutString
{
public string Text;
public string FontName;
public Color TextColor;
public int SceneNumber;
}
А все строки в
private List<AboutString> Strings
Сцена:
Для описания сцены так же создана структура:
private struct AboutScene
{
public int PauseTimeout;
public int StringsHeight;
public int StringsCount;
public Color BackColor;
public int DrawTimeout;
}
И описания сцен так же хранятся в private
List<AboutScene> Scenes
- последняя точка с запятой является необязательной
- пустые строки, или строки, содержащие только пробельные символы, пропускаются
- команды приводятся к нижнему регистру (т.е. они регистронезависимы)
- есть возможность оставить однострочный комментарий, начинающейся с ~ (тильды). Все, что после знака ~ считается комментарием и пропускается при анализе "скрипта".
- если первая (нулевая) сцена явно не определена, то создается сцена с параметрами по умолчанию
Команды, благо их немного, последовательно анализируются с помощью конструкции
switch/case
и передаются в функции добавления шрифта, строк, или сцены, где анализируются далее.Параметры и команда разбираются с помощью
string.split(';');
Размер шрифта должен быть
float
, поэтому надо сделать функцию-обертку над Convert, так, как я писал об этом ранее:private float ConvertToFloat(string Number)
{
NumberFormatInfo format = new NumberFormatInfo();
format.NumberDecimalSeparator = ".";
return (float)Convert.ToDouble(Number, format);
}
Некоторые параметры передаются через пробел (значения RGBA цвета, или стили шрифта). Нужна функция, которая будет избавляться от дублирующих пробелов, поскольку лишний пробел поставить легко, а вот вылавливать его потом неприятно:
private string RemoveDupSpaces(string s)
{
while (s.Contains(" "))
{
s = s.Replace(" ", "");
}
return s;
}
Естественно, весь функционал не стоит реализовывать прямо на форме, потому вся работа вынесена в отдельный класс
AboutDrawer
, который парсит переданный скрипт и занимается отрисовкой строк на форме.На форме строки отображаются в компоненте
PictureBox
, который передается в конструктор класса. Конструктор также устанавливает некоторые параметры по умолчанию. Поскольку, класс все равно работает с компонентами формы, то спокойно подключаем пространство имен
System.Windows.Forms
, и пользуемся всеми его возможностями. Например, в классе создаются два таймера (Timer
). Внутри обработчика события Tick
одного из них, происходит отрисовка, а другой используется для эффекта паузы.В классе созданы открытые свойства для установки цвета фона, цвета текста по умолчанию, и размера расстояния между строк.
Подробнее ознакомиться с кодом примера можно на Github:
Код на GitHub
Это репост с сайта http://tolik-punkoff.com
Оригинал: http://tolik-punkoff.com/2018/06/11/c-si