Как я могу подчеркнуть некоторую часть многострочного текста с помощью GDI? - PullRequest
3 голосов
/ 30 октября 2009

Я использую Graphics.DrawString, чтобы нарисовать текст моего usercontrol следующим образом:

protected override void OnPaint(PaintEventArgs e)
{
    RectangleF bounds = DisplayRectangle;
    bounds.Inflate(-4, -4); // Padding
    StringFormat format = new StringFormat();
    format.Alignment = StringAlignment.Near;
    format.LineAlignment = StringAlignment.Near;
    format.Trimming = StringTrimming.None;
    using (Brush bFore = new SolidBrush(ForeColor))
    {
        g.DrawString(Text, Font, bFore, bounds, format);
    }
}

Если Text элемента управления шире, чем DisplayRectangle, DrawString приятно разбивает Text на несколько строк на границах слов.

Теперь я хочу подчеркнуть некоторые слова из Text, но я не смог разобраться. Я попытался разбить Text, затем MeasureString строку непосредственно перед началом подчеркнутой части, DrawString нормальную часть, затем DrawString подчеркнутую часть. Но это работает, только если Text однострочный.

Я уверен, что использование дочернего элемента LinkLabel или RichTextBox для визуализации текста моего элемента управления решит эту проблему, но мне не нравится идея использовать дочерний элемент управления только для того, чтобы подчеркнуть несколько слов. Есть ли другой способ?

1 Ответ

3 голосов
/ 03 ноября 2009

Это грубый пример, который будет работать с использованием строки, разделенной на части и двух разных стилей шрифта, вместо отрисовки подчеркивания по отдельности (хотя это тоже будет работать). На практике я бы рекомендовал разбивать текст по словам, а не по фразам, и разбираться с каждым словом по отдельности в цикле. В противном случае, как в этом примере, разрыв строки не будет работать правильно.

Dim fntNormal As New Font(myFontFamily, myFontSize, FontStyle.Regular, GraphicsUnit.Pixel)
  Dim fntUnderline As New Font(myFontFamily, myFontSize, FontStyle.Underline, GraphicsUnit.Pixel)

  g.DrawString("This is ", fntNormal, Brushes.Black, rctTextArea)
  w1 = g.MeasureString("This is ", fntNormal).Width
  w2 = g.MeasureString("underlined", fntUnderline).Width
  If w1 + w2 > rctTextArea.Width Then
     yPos = rctTextArea.Y + g.MeasureString("This is ", fntNormal).Height + 5
     xPos = rctTextArea.X
  Else
     yPos = rctTextArea.Y
     xPos = 0
  End If

  g.DrawString("underlined", fntUnderline, Brushes.Black, xPos, yPos)

  w1 = g.MeasureString("underlined", fntUnderline).Width
  w2 = g.MeasureString(", and this is not.", fntNormal).Width

  If w1 + w2 > rctTextArea.Width Then
     yPos += g.MeasureString("underlined", fntUnderline).Height + 5
     xPos = rctTextArea.X
  Else
     xPos = 0
  End If


  g.DrawString(", and this is not.", fntNormal, Brushes.Black, xPos, yPos)

Этот код действительно можно почистить и сделать более эффективным, чтобы позволить вам перебирать каждое слово в вашей текстовой строке.

В этом примере также отсутствует код для проверки превышения вертикального предела прямоугольника границ.

Извините за код VB, я только что заметил, что ваш вопрос был на C #.

...