如何确定将绘制在矩形中的文本高度?

4
我想用GDI+在矩形中绘制一些文本,就像这篇微软文章中描述的那样:https://msdn.microsoft.com/en-us/library/baw6k39s(v=vs.110).aspx
在指定所需宽度后,文本会自动换行到下一行,这正是我的意图。问题是,我需要设置矩形的高度,以使文本完美地适配框内,没有被裁剪,也没有额外的空白。在这种情况下,试错性测试值将根本行不通,因为文本将发生变化。
我实现了一个解决方案,模拟呈现时将发生的文本换行并添加换行符来测量其高度。但是,这似乎并未起作用,矩形的高度通常具有大量的末尾空白(似乎与文本数量呈正线性关系)。 问题: enter image description here 我的代码如下:
public void setBreakLen() { //determines how many chars fit on each line (note: using a FIXED WIDTH FONT) 
  double cwidth = TextRenderer.MeasureText("h", font).Width;
  breakLen = (int)((double)box.Width / (double)cwidth);
}



public void updateHeight() { //should tell me what the height of the box should be to fit perfectly
  StringBuilder sb = new StringBuilder(text);
  int numAppended = 0;
  for (int i = 0; i < text.Length; i++) {
      if ((i + 1) % breakLen == 0) {
          sb.Insert((i + 1 + numAppended), "\n");
          numAppended += 1;
       }
   }

   Size s = TextRenderer.MeasureText(sb.ToString(), font);
   height = s.Height;
   box = new Rectangle(x, y, width, height);
}

然而,这似乎有些过度,必须有更好的方法。因此,我想这实际上是一个包含两个问题的问题。
1. 如何使我的当前解决方案工作? 2. 有没有更好的方法来完成这个任务?
注意:使用调试器,我已确定breaklen变量是正确的。它读取11个字符,每行有11个字符。
我还使用固定宽度字体(Consolas系列)检查了其他字符,它们都产生相同的断点长度。这是StringBuilder处理换行符的问题吗?我通常使用Java而不是C#,所以我对流等不熟悉。
编辑后的绘图代码如下:
g2d.DrawString(m.text, m.font, Brushes.Blue, m.box);
g2d.DrawRectangle(Pens.Black, Rectangle.Round(m.box));

编辑2: 我尝试使用MeasureText函数的重载Size参数来实现这个辅助解决方案。 无论字符串的长度如何,它都只返回19,似乎仅返回单行的正确高度。

    Size s = TextRenderer.MeasureText(text, font, new Size(width, 0));//i also tried MaxInt
    height = s.Height;
    Console.WriteLine(height);
    box = new Rectangle(x, y, width, height);

请问下/关闭投票者,能否解释一下?这个问题怎么会是离题的????你看到的代码是一个MCVE,这完全是在讨论主题范围内的。 - Ashwin Gupta
你想做的是指定一个限制宽度,然后计算需要显示文本的高度吗?如果是这样,请使用 TextRenderer.MeasureText 方法,并传入一个建议大小。对于这个建议大小,将高度设置为零,返回的大小将是所需的高度。 - TnTinMn
使用重载的MeasureText方法,该方法接受一个Size参数,并传入一个HeightInt32.MaxValue的值。返回的Size对象的Height属性将被设置为呈现文本所需的最小高度。 - Bradley Uffner
@TnTinMn,这似乎没有起作用,我会编辑一下我的代码。现在无论字符串的长度(跨越多少行)是多少,它都只返回19。 - Ashwin Gupta
@TnTinMn 好的,谢谢你,我很感激。 - Ashwin Gupta
显示剩余4条评论
1个回答

3
尝试以下代码。我将代码合并到一个函数中以使其运行。您可以看到变化。您必须使用MeasureString而不是MeasureText。看看我得到的输出 enter image description here
Font font = new Font(FontFamily.GenericSansSerif, 12.0F, FontStyle.Bold);

int x = 10, y = 10, width = 120, height = 30, breakLen = 0;
Rectangle box;
string text = "THIS BOX IS TOO TALL!!!";

private void DrawRectangle()
{
    box = new Rectangle(x, y, width, height);

    using (Graphics g = this.CreateGraphics())
    {
        double cwidth = g.MeasureString("h", SystemFonts.DefaultFont).Width;
        breakLen = (int)((double)box.Width / (double)cwidth);

        StringBuilder sb = new StringBuilder(text);
        int numAppended = 0;

        for (int i = 0; i < text.Length; i++)
        {
            if ((i + 1) % breakLen == 0)
            {
                sb.Insert((i + 1 + numAppended), "\n");
                numAppended += 1;
            }
        }

        Size s = TextRenderer.MeasureText(sb.ToString(), font);
        height = s.Height;
        box = new Rectangle(x, y, width, height);

        Pen pen = new Pen(Color.Black, 2);
        g.DrawString(sb.ToString(), font, Brushes.Blue, box);
        g.DrawRectangle(pen, box);
        pen.Dispose();
    }
}

啊,我明白了,我没有意识到GDI+有一种不同的文本测量方法。谢谢你指出来,我想接受。然而,我仍然有一些困惑。首先,你使用g.MeasureString,但你没有提供我要使用的实际字体,而是使用了默认字体。此外,你后来仍然使用了MeasureText。 - Ashwin Gupta
啊,JK,它确实有效。但是,我仍然不明白为什么你使用 SystemFonts.DefaultFont 而不是我指定的字体实例。这是如何工作的? - Ashwin Gupta
我尝试了一下,然后它就运行了。为什么这个技巧有效,我无法回答。 - Mukul Varshney
2
你代码中唯一正确的地方是使用MeasureString而不是MeasureText。其他所有东西都是垃圾!所以为了得到框,你需要这样做: SizeF s = g.MeasureString(text, font, width); box = new Rectangle(x, y, (int)s.width, (int)s.height); - γηράσκω δ' αεί πολλά διδασκόμε

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接