Назначение сегментного дисплея
Каждый наверняка уже встречался в жизни и быту с сегментными дисплеями отображения информации. Подобные решения используются в различных электронных устройствах: табло терминалов, бытовая техника, кассовые аппараты. Такие индикаторы состоят из множества сегментов, некоторые подсвечиваются, формируя текст. 7-сегментные дисплеи используются, в основном, для отображения цифр. Чтобы показать буквы и символы применяются 14 или 16 сегментов.
В интернете можно повстречать шрифты или уже готовые библиотеки и компоненты для эмуляции таких дисплеев. Иногда, такой стандартной реализации может быть недостаточно – в особенности при изменении таких настроек как, например, размер самих сегментов или заливка сегментов. Поэтому самостоятельная разработка может помочь внедрить решение под свои собственные нужды и со многими опциями.
В данной статье разбирается, как осуществить пользовательский многосегментный WPF компонент. Кроме того, это может содействовать в изучении внутреннего устройства C#, .NET и самой платформы WPF.
Этот полностью переработанный материал основан на моей ранней публикации 2019 года для CodeProject.
Идея реализации
Вся логика отображения сегментов осуществляется классом Geometry из библиотеки Windows Presentation Foundation (WPF) для описания фигур. Из множества методов этого класса в проекте могут понадобиться: LineSegment и PolyLineSegment для создания замкнутой фигуры, различные кривые Безье PolyBezierSegment, PathGeometry для создания набора созданных фигур. DrawGeometry из класса DrawingContext отображает созданные элементы.
Программирование отрисовки фигур Geometry происходит в абстрактном generic классе SegmentBase<TSegment>. От него могут наследоваться классы для создания многосегментных компонентов. В качестве универсального generic параметра передается битовая маска, для описания сегментов в виде битов. Например, для 7 сегментов:
[Flags]public enum SevenSegmentsFlags{ None = 0, Top = 1 << 0, RightTop = 1 << 1, RightBottom = 1 << 2,//...}
То есть, для примера 1 << 2 происходит сдвиг числа один — 0000001 в двоичной системе влево на 2 разряда – 0000100.
Для формирования символов создается комбинация битов через дизъюнкцию и заносится в словарь Dictionary <char, SevenSegmentsFlags> . Пример:
public static readonly Dictionary<char, SevenSegmentsFlags> Map = new Dictionary<char, SevenSegmentsFlags> { ['1'] = SevenSegmentsFlags.RightTop | SevenSegmentsFlags.RightBottom, };
Для символа ‘1’ получается маска 0000011.
В классе SegmentBase<TSegment> используется метод ApplyMask для включения необходимых сегментов, то есть последовательно применяется конъюнкция сегментов фигуры с маской:
protected void ApplyMask(uint mask){ foreach (var figure in GeometryFigures) { uint figureMask = Convert.ToUInt32( figure.SegmentNumber); figure.IsSelected = (mask & figureMask) != 0; }}
Например, маска символа – 0000011, проверяемый сегмент – 0000010 (RightBottom). После применения логического И , результат не равен нулю (0000010), значит сегмент выделяется.
Битовая маска для 7 сегментов приведена ниже:

Маска для 16 сегментов:

Полученный результат реализации отрисовки одиночного символа располагается в классах SevenSegments и SixteenSegments, содержащих необходимые свойства зависимостей для внешнего использования (значение, цвет заливки сегментов, угол наклона и т. д.).
Для создания сегментных компонентов, содержащих множество символов применяются классы SevenSegmentsStack и SixteenSegmentsStack с xaml разметкой. В них располагаются стандартный Grid, в который добавлены компоненты SevenSegments и SixteenSegments в виде элементов ItemsControl.
Свойства многосегментных компонентов
Пользователю для использования доступно 4 разных пользовательских компонента: SevenSegments и SixteenSegments отображают один символ, SevenSegmentsStack и SixteenSegmentsStack отображают группу символов. Они имеют общие свойства зависимостей:
-
цвет и кисть заливки сегментов , активных и неактивных (FillBrush, SelectedFillBrush).
-
перо сегментов, активных и не активных.
-
возможность скрыть/показать точку или двоеточие и их активация/деактивация (ShowDot, ShowColon, OnDot, OnColon).
-
угол наклона сегментов в градусах (TiltAngle).
-
возможность скрыть/показать округлость углов (RoundedCorners).
-
ширина зазора в пикселах между сегментами (GapWidth).
-
пропорциональная ширина и высота сегментов.
SevenSegmentsStack и SixteenSegmentsStack имеют дополнительное свойство ElementsCount— количество символов.
Пользователь компонентов может устанавливать цвет и кисть заливки отдельных сегментов (свойство SegmentsBrush с типом IList), а также активировать отдельные сегменты (свойство SelectedSegments с типом IList).
К примеру, для компонента в коде xaml привязываются два свойства списков:
<SegmentsControls:SevenSegmentsSelectedSegments="{Binding SelectedSevenSegments}"SegmentsBrush="{Binding SevenSegmentsBrushes}"/>
В модели можно заполнить свойство SelectedSevenSegments типа ObservableCollection для активации требуемых сегментов и свойство SevenSegmentsBrushes типа ObservableCollection для того, чтобы закрасить разной заливкой разные сегменты:
SelectedSevenSegments.Add(SevenSegmentsFlags.Top);SelectedSevenSegments.Add(SevenSegmentsFlags.Middle);var redBrush = new LinearGradientBrush( Colors.Orange, Colors.Red, 90); SevenSegmentsBrushes = new ObservableCollection<SegmentBrush<SevenSegmentsFlags>> { new SegmentBrush<SevenSegmentsFlags> { Segment = SevenSegmentsFlags.Top, FillBrush = redBrush, PenColor = Colors.Black },};
Результат
В итоге, без использования сторонних решений и библиотек удалось разработать универсальный многосегментный WPF-компонент с поддержкой 7 и 16 сегментов, по сути аналог шрифта. По необходимости проект можно расширить до архитектуры любого количества сегментов.
В отличие от других разработок контролл дает множество гибких настроек, использовать латинские символы, цифры, кириллицу и работать через MVVM для привязки свойств зависимостей. Использование битовых символов позволило сделать код более понятным и производительным. Реализованное решение можно использовать для визуализации электронных табло, счетчиков, калькуляторов, цифровых часов c сегментной информацией.
Исходный код
Посмотреть проект с примерами настройки и использованием через MVVM можно на GitHub через ссылку.
ссылка на оригинал статьи https://habr.com/ru/articles/1045774/