【问题标题】:How can I underline some part of a multi-line text with GDI?如何使用 GDI 在多行文本的某些部分下划线?
【发布时间】:2009-11-03 05:35:41
【问题描述】:

我正在使用Graphics.DrawString 来绘制我的用户控件的文本,如下所示:

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);
    }
}

如果控件的TextDisplayRectangle 宽,DrawString 很好地将Text 在字边界处分成多行。

现在我想在Text 中的一些词下划线,但我无法解决。我尝试在下划线部分开始之前拆分Text,然后MeasureString 字符串,DrawString 正常部分,然后DrawString 下划线部分。但这只有在 Text 是单行时才有效。

我确信使用子控件LinkLabelRichTextBox 来呈现我的控件的文本会解决这个问题,但我不喜欢使用子控件只是为了给几个单词加下划线的想法。还有其他方法吗?

【问题讨论】:

    标签: c# .net graphics gdi+


    【解决方案1】:

    这是一个粗略的示例,它将使用拆分为部分的字符串和两种不同的字体样式,而不是单独绘制下划线(尽管这也可以)。在实际实践中,我建议按单词而不是短语拆分文本,并在循环中单独处理每个单词。否则,就像在这个例子中一样,换行不能正常工作。

    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# 编写的。

    【讨论】:

    • 上面 xPos = 0 的两行。他们不应该是 xPos = xPos + w1 吗?
    • 谢谢,我想这是我能做的最好的了。我还尝试在单词边界上使用 MeasureCharacterRanges,但它似乎不适用于多行文本。
    • 是的,xPos = 0 是错误的。我的剪切和粘贴太着急了。 :)
    猜你喜欢
    • 2014-10-14
    • 1970-01-01
    • 2015-04-19
    • 2011-09-26
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    • 2016-04-20
    • 2017-01-18
    相关资源
    最近更新 更多