Страницы

Поиск по вопросам

вторник, 23 октября 2018 г.

Как сделать двойное(тройное) отрицание на wpf или windows forms?


Например, как на картинке. Чтобы при нажатии на кнопку над выделенным элементом(или группой элементов) появлялся знак отрицания(двойное/тройное). Если нельзя реализовать на данных языках, то может хоть какие-нибудь другие идеи есть..


Ответ

Ну, можно сделать, хотя намного менее удобно, чем в TeX'е. Вам придётся самостоятельно измерять символы и работать со свойствами шрифтов. Вот вам простой вариант: он не учитывает курсив и строчные буквы.
XAML:

Заведём маленький вспомогательный класс:
class LevelDescriptor { public double Y; public List<(double from, double to)> Lines; }
Наш код:
string text = "(X & Y) & (X & Y) & (X & Z)"; // описание линий var lines = new List>() { new List<(int from, int to)>() { (1, 2), (15, 16), (25, 26) }, // уровень 1 new List<(int from, int to)>() { (1, 6), (11, 16), (21, 26) }, // уровень 2 new List<(int from, int to)>() { (0, 27) }, // уровень 3 };
// вертикальное расстояние между линиями const double vgap = 4; // разрешение вашего монитора. (если оно изменяется, например, у вас их несколько, то // надо подписаться на его изменение) var pixelsPerDip = VisualTreeHelper.GetDpi(this).PixelsPerDip; // куда пишем TextBlock tb = Target; tb.Text = text; // отбираем у текстбокса шрифт var font = new Typeface(tb.FontFamily, tb.FontStyle, tb.FontWeight, tb.FontStretch);
// форматируем текст FormattedText formattedText = new FormattedText( text, CultureInfo.GetCultureInfo("en-US"), FlowDirection.LeftToRight, font, tb.FontSize, Brushes.Black, // конкретная кисть нам не важна, мы используем только геометрию pixelsPerDip);
// на какой высоте начинается большая буква? double vstart = formattedText.Baseline - font.CapsHeight * tb.FontSize;
// описатели линий List result = new List(); // текущая высота double height = vstart; foreach (var line in lines) { // получаем окружающие прямоугольники для всех подстрок var boundingBoxes = line.Select(d => formattedText.BuildHighlightGeometry(new Point(), d.from, d.to - d.from).Bounds); height -= vgap; // запомнили высоту, и левую/правую границу для каждого отрезка result.Add(new LevelDescriptor() { Y = height, Lines = boundingBoxes.Select(bb => (from: bb.Left, to: bb.Right)).ToList() }); }
// теперь создаём линии var brush = tb.Foreground; // цвет такой же, как и у строки foreach (var level in result) { foreach (var d in level.Lines) Host.Children.Add( new Line() { X1 = d.from, X2 = d.to, Y1 = level.Y, Y2 = level.Y, StrokeThickness = 1, // толщина Stroke = brush, Fill = brush }); }
Вот и всё. Вам придётся на основе своих данных самостоятельно строить таблицу lines
У меня вышел вот такой результат:

Комментариев нет:

Отправить комментарий