none
Как часть текста в ячейке dataGridView сделать жирным шрифтом? RRS feed

  • Вопрос

  • Добрый день.

    Нужно в ячейке dataGridView часть текста как-то выделить.

    Например:

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

    Например, 1010 чтобы было жирным шрифтом, а 1110 обычным шрифтом.

    Другие способы выделения тоже подойдут. Как их реализовать?

    P.S. Пишу в WinForms на C#
    • Изменено sg6336 21 декабря 2013 г. 13:16
    21 декабря 2013 г. 13:15

Ответы

  • private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
    {
        // меняем выделение в колонке 2; заголовок не трогаем
        if (e.ColumnIndex == 2 && e.RowIndex >= 0)
        {
            e.PaintBackground(e.ClipBounds, true); // фон отрисовывается стандартный
    
            Font font = e.CellStyle.Font; // стандартный шрифт ячейки, используется для первой половины текста
    
            using (var sf = new StringFormat())
            using (var firstBrush = new SolidBrush(e.CellStyle.ForeColor)) // кисть для первой половины текста
            using (var lastBrush = new SolidBrush(Color.Red)) // кисть для последней половины текста
            using (var boldFont = new Font(font, FontStyle.Bold)) // жирный шрифт, используется для последней половины текста
            {
                sf.LineAlignment = StringAlignment.Center; // выравнивание по центру, как в других ячейках (стандартно)
                sf.FormatFlags = StringFormatFlags.NoWrap; // чтобы при сжатии колонки текст не переносился на вторую строку
                sf.Trimming = StringTrimming.EllipsisWord; // будет отрисовываться многоточие, если текст не влезает в колонку
    
                string text = (string)e.FormattedValue; // полное (форматированное) значение ячейки
                string firstHalf = text.Substring(0, 4); // первая часть текста
                string lastHalf = text.Substring(4); // оставшаяся часть текста
    
                e.Graphics.DrawString(firstHalf, font, firstBrush, e.CellBounds, sf); // первую половину текста рисуем стандартным шрифтом и цветом
    
                SizeF size = e.Graphics.MeasureString(firstHalf, font, e.CellBounds.Location, StringFormat.GenericTypographic); // размер первой половины текста
                var rect = new RectangleF(e.CellBounds.X + size.Width, e.CellBounds.Y, e.CellBounds.Width - size.Width, e.CellBounds.Height); // ограничивающий прямоугольник для оставшейся части текста
    
                e.Graphics.DrawString(lastHalf, boldFont, lastBrush, rect, sf); // выводим вторую часть текста жирным шрифтом и другим цветом
            }
            e.Handled = true; // сигнализируем, что закончили обработку
        }
    }

    Произвольное выделение отрисовываем в событии CellPainting.

    Для примера первые четыре символа текста выводятся шрифтом и цветом по умолчанию. Оставшаяся часть текста выделяется как жирным шрифтом, так и красным цветом (по желанию можно взять что-то одно). Аналогично можно и фон под текстом изменить.

    Создание кистей и шрифтов - затратное дело. Поэтому, если они не меняются по ходу дела, то лучше их сделать полями класса (формы) и создать при старте проги, задиспозив лишь при закрытии.

    Вместо Graphics.DrawString и Graphics.MeasureString (функции GDI+) можно использовать TextRenderer.DrawText и TextRenderer.MeasureText (функции GDI) - считается, что они обеспечивают лучшее качество.

    • Помечено в качестве ответа sg6336 26 декабря 2013 г. 12:26
    24 декабря 2013 г. 20:26
  • Добавляем в класс формы поля для значений, которые нужно будет передавать. В функции, которая проводит расчёты, устанавливаем эти поля, и делаем обновление датагрида.

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();        
        }
    
        bool needCustomPainting = false;
        int index = 0;
    
        private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (!needCustomPainting)
                return;
    
            ...
    
                    string firstHalf = text.Substring(0, index); // первая часть текста
                    string lastHalf = text.Substring(index); // оставшаяся часть текста
    
            ...
    
            }
        }
    
        private void someFunction()
        {
            index = 4;
            needCustomPainting = true;
            dataGridView1.Refresh();
        }
    }


    • Помечено в качестве ответа sg6336 26 декабря 2013 г. 12:26
    25 декабря 2013 г. 16:56

Все ответы

  • Элементы управления WinForms, как правило, используют единый стиль отображения текста, включая размер и начертание шрифта. Исключение составляет лишь RichTextBox. Хотите реализовать отличное поведение - создайте свой элемент управления.
    21 декабря 2013 г. 19:25
  • можно сделать так чтобы в dataGridView ячейки были из RichTextBox?
    21 декабря 2013 г. 20:54
  • все можно. копайте в сторону DataGridView + Наследование + Graphics
    21 декабря 2013 г. 20:56
  • можно сделать так чтобы в dataGridView ячейки были из RichTextBox?
    Нет.
    22 декабря 2013 г. 8:29
  • Пример можете дать?
    23 декабря 2013 г. 9:48
  • А хоть какие-то варианты выделения части ячейки существуют?
    23 декабря 2013 г. 9:49
  • Посмотрите вот этот раздел документации. Там утверждается, что для ячейки можно изменить стиль и форматирование. Может быть это Вам поможет.
    23 декабря 2013 г. 10:11
  • Я рекомендовал бы вам посмотреть в сторону WPF. Там со стилизацией проблем возникнуть не должно.
    24 декабря 2013 г. 2:59
  • можно сделать в wpf и поместить хостом в winforms
    24 декабря 2013 г. 13:53
  • private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
    {
        // меняем выделение в колонке 2; заголовок не трогаем
        if (e.ColumnIndex == 2 && e.RowIndex >= 0)
        {
            e.PaintBackground(e.ClipBounds, true); // фон отрисовывается стандартный
    
            Font font = e.CellStyle.Font; // стандартный шрифт ячейки, используется для первой половины текста
    
            using (var sf = new StringFormat())
            using (var firstBrush = new SolidBrush(e.CellStyle.ForeColor)) // кисть для первой половины текста
            using (var lastBrush = new SolidBrush(Color.Red)) // кисть для последней половины текста
            using (var boldFont = new Font(font, FontStyle.Bold)) // жирный шрифт, используется для последней половины текста
            {
                sf.LineAlignment = StringAlignment.Center; // выравнивание по центру, как в других ячейках (стандартно)
                sf.FormatFlags = StringFormatFlags.NoWrap; // чтобы при сжатии колонки текст не переносился на вторую строку
                sf.Trimming = StringTrimming.EllipsisWord; // будет отрисовываться многоточие, если текст не влезает в колонку
    
                string text = (string)e.FormattedValue; // полное (форматированное) значение ячейки
                string firstHalf = text.Substring(0, 4); // первая часть текста
                string lastHalf = text.Substring(4); // оставшаяся часть текста
    
                e.Graphics.DrawString(firstHalf, font, firstBrush, e.CellBounds, sf); // первую половину текста рисуем стандартным шрифтом и цветом
    
                SizeF size = e.Graphics.MeasureString(firstHalf, font, e.CellBounds.Location, StringFormat.GenericTypographic); // размер первой половины текста
                var rect = new RectangleF(e.CellBounds.X + size.Width, e.CellBounds.Y, e.CellBounds.Width - size.Width, e.CellBounds.Height); // ограничивающий прямоугольник для оставшейся части текста
    
                e.Graphics.DrawString(lastHalf, boldFont, lastBrush, rect, sf); // выводим вторую часть текста жирным шрифтом и другим цветом
            }
            e.Handled = true; // сигнализируем, что закончили обработку
        }
    }

    Произвольное выделение отрисовываем в событии CellPainting.

    Для примера первые четыре символа текста выводятся шрифтом и цветом по умолчанию. Оставшаяся часть текста выделяется как жирным шрифтом, так и красным цветом (по желанию можно взять что-то одно). Аналогично можно и фон под текстом изменить.

    Создание кистей и шрифтов - затратное дело. Поэтому, если они не меняются по ходу дела, то лучше их сделать полями класса (формы) и создать при старте проги, задиспозив лишь при закрытии.

    Вместо Graphics.DrawString и Graphics.MeasureString (функции GDI+) можно использовать TextRenderer.DrawText и TextRenderer.MeasureText (функции GDI) - считается, что они обеспечивают лучшее качество.

    • Помечено в качестве ответа sg6336 26 декабря 2013 г. 12:26
    24 декабря 2013 г. 20:26
  • Спасибо!!! завтра на свежую голову вдумаюсь в Ваш пример.
    24 декабря 2013 г. 21:54
  • Добавлю ещё, что метод string.Substring может выбрасывать исключение ArgumentOutOfRangeException, если длина строки меньше переданного параметра. Компонент DataGridView проглатывает это исключение, в результате дальнейшая отрисовка нарушается. Поэтому нужно либо ловить и обрабатывать это исключение, либо проверять длину строки до вызовов Substring.
    25 декабря 2013 г. 8:32
  • Спасибо!!! Это то что нужно!

    Можете подсказать, пожалуйста, как мне в это событие предавать значения того, что мне нужно выделить? Т.е. чтобы моя функция провела расчеты, а потом выделила то, что изменилось в таблице. Как сделать выделение (обращение к этому событию с нужными параметрами) из функции? Функция написана рядом с этим кодом.

    // меняем выделение в колонке 2; заголовок не трогаем
        if (e.ColumnIndex == 2 && e.RowIndex >= 0)
        {
    

    Сейчас столбец 2 и все рядки задействованы.

    Можно как-то передавать в это событие значения номера столбца, строки и количества выделенных знаков в ячейке (0, 4 или значения firstHalf и lastHalf)?

    25 декабря 2013 г. 12:52
  • Добавляем в класс формы поля для значений, которые нужно будет передавать. В функции, которая проводит расчёты, устанавливаем эти поля, и делаем обновление датагрида.

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();        
        }
    
        bool needCustomPainting = false;
        int index = 0;
    
        private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (!needCustomPainting)
                return;
    
            ...
    
                    string firstHalf = text.Substring(0, index); // первая часть текста
                    string lastHalf = text.Substring(index); // оставшаяся часть текста
    
            ...
    
            }
        }
    
        private void someFunction()
        {
            index = 4;
            needCustomPainting = true;
            dataGridView1.Refresh();
        }
    }


    • Помечено в качестве ответа sg6336 26 декабря 2013 г. 12:26
    25 декабря 2013 г. 16:56
  • Спасибо! Уже работает.


    • Изменено sg6336 26 декабря 2013 г. 12:26
    26 декабря 2013 г. 8:36
  • хороший вариант с событием CellPainting, но как поступить, если выделять цветом нужно после создания грида по условию дочерний/родительский.

    грид выглядит вот так:датагрид формируется динамически, количество/содержимое колонок заранее неизвестно.

    15 декабря 2015 г. 13:47