Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine the height of my text that will be drawn in a rectangle?

Tags:

c#

winforms

gdi+

I'm trying to draw some text in a rectangle w/ GDI+ like described in this Microsoft article: https://msdn.microsoft.com/en-us/library/baw6k39s(v=vs.110).aspx.

After specfying the width I want, the text automatically wraps to the next line like intended. The issue is, I need to set the height of the rectangle so that the text fits perfectly within the box, none cut off but no extra whitespace. Trial and error testing with values will simply not work in this case because the text will be changing.

I implemented a solution that mimics the breaking of the text that will occur at rendering by adding newline chars to it then measuring the height. But this does not appear to be working and the height of the box often has a tremendous amount of trailing white space (which seems follow a positive linear relationship to the amount of text).

The problem:

enter image description here

My code is as follows:

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

However, this just seems like overkill, there must be a better way. As such, I suppose this is actually a two part question.

  1. How can I make my current solution work?
  2. Is there a better way to do this?

NOTE: Using the debugger, I've determined that the breaklen variable is correct. It reads 11 and there are 11 characters on each line.

I've also checked other chars with the fixed width font (Consolas family) , they all produce identical break lengths. Is this is an issue with how StringBuilder handles newline chars? I usually work with Java not C# so I'm not familiar with the streams and such.

EDIT: Drawing code is as follows:

g2d.DrawString(m.text, m.font, Brushes.Blue, m.box);
g2d.DrawRectangle(Pens.Black, Rectangle.Round(m.box));

EDIT 2: I've tried implemnting this secondary solution with the overload Size parameter of MeasureText function. This just returns 19 every time despite the length of the string, it seems to be returning the correct height for a SINGLE line.

    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);
like image 969
Ashwin Gupta Avatar asked Oct 26 '25 05:10

Ashwin Gupta


1 Answers

Try below code. I just clubbed the code in one function to get it run. You can see the change. You have to use MeasureString rather than MeasureText. See the output i got 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();
    }
}
like image 177
Mukul Varshney Avatar answered Oct 28 '25 18:10

Mukul Varshney



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!