Martin Marconcini
Martin Marconcini

Reputation: 27226

Determine Label Size based upon amount of text and font size in Winforms/C#

I'd like to know if there's a better approach to this problem. I want to resize a label (vertically) to accomodate certain amount of text. My label has a fixed width (about 60 chars wide before it must wrap), about 495 pixels. The font is also a fixed size (12points afaik), but the text is not.

What I want to do is increase the Label Height when there's a "NewLine" or the text must wrap; the idea is that the text is fully visible in the label. The AutoSize doesn't work because it will grow in width, not in height.

Of course I could count the number of NewLines and add: Newlines * LineHeight, and then -given that I manage to put 60 chars per line, just divide the number of chars and add as many LineHeight pixels as needed.

I was wondering if there was a more professional way to do it. Is my approach too "lame" ?

Thanks in advance.

Upvotes: 48

Views: 59338

Answers (12)

Stelios Adamantidis
Stelios Adamantidis

Reputation: 2031

I would like to propose an alternative since it's a label we are talking about and not just text rendering: GetPreferredSize. I tried Mark's answer and the problem is that it almost works: the label has some "padding" around the text and this needs to be taken into account in the width value of MeasureString. I couldn't find any apparent way to get this padding. While digging, I found this answer where the poster suggests to set the FlatStyle to System. That works, but unfortunately breaks the TextAlign which I wanted it to be MiddleLeft.

I poked into the Label code and I found out the GetPreferredSize which takes into account all the weird settings (FlatStyle, UseCompatibleTextRendering etc) and can give you the correct result for each case. So instead of g.MeasureString(text, lbl.Font, 495); you can do instead

lbl.GetPreferredSize(new Size(495, 0));

or even like this since the label size is already known:

lbl.GetPreferredSize(new Size(lbl.Width, 0));

In case you are wondering, 0 and 1 will be treated as int.MaxValue.

I don't know when GetPreferredSize was introduced, so back in 2008 when Mark wrote his answer, the above might not have been relevant. But if you still need something similar in 2021, GetPreferredSize might be a tiny bit handier -which returns a Size and not a SizeF.

Upvotes: 2

Sujeet Shrestha
Sujeet Shrestha

Reputation: 21

Although, its an old thread, thought it might help new visitors.

In C#, you could use control.width

Upvotes: 0

Doğa Gençer
Doğa Gençer

Reputation: 124

In some cases where you must use compact framework, which does not have any override methods for MeasureString(), you might consider calculating the height by yourself.

private int YukseklikAyarla(string p, Font font, int maxWidth)
    {
        int iHeight = 0;
        using (Graphics g = CreateGraphics())
        {
            var sizes = g.MeasureString(p, font); // THE ONLY METHOD WE ARE ALLOWED TO USE
            iHeight = (int)Math.Round(sizes.Height);
            var multiplier = (int)Math.Round((double)sizes.Width) / maxWidth; // DIVIDING THE TEXT WIDTH TO SEE HOW MANY LINES IT CAN HAS
            if (multiplier > 0)
            {
                iHeight = (int)(iHeight * (multiplier + 1)); // WE ADD 1 HERE BECAUSE THE TEXT ALREADY HAS A LINE
            }
        }
        return iHeight;
    }

Upvotes: 0

Barry Keller
Barry Keller

Reputation: 41

According to this article you should use TextRenderer if you are going to use a Windows Form control for the final output. TextRenderer and Graphics.MeasureString will give different results, so use the one that matches your final mode of output.

Upvotes: 0

Hacko
Hacko

Reputation: 1761

Size maxSize = new Size(495, int.MaxValue);
_label.Height = TextRenderer.MeasureText(_label.Text , _label.Font, maxSize).Height;

Upvotes: 8

blak3r
blak3r

Reputation: 16516

I posted a user control which solves this problem in the accepted answer here: Autoscale Font in a TextBox Control so that its as big as possible and still fits in text area bounds

The control extends RichTextBox. It has a method: ScaleFontToFit that will automatically resize the font to make all the text fit.

Neat thing is it respects the multiline property. If it's true it allows words to wrap, Otherwise it doesn't.

Upvotes: 1

user166390
user166390

Reputation:

This "answer" is for future reference and to combat the initial assumption that AutoSize = true implies that it (a WinForms label) will never grow in height.

The following link shows the various effects of AutoSize = true with other properties such as MaximumSize. Depending upon the expected use of the question it may be appropriate to follow one of these approaches.

http://blogs.msdn.com/jfoscoding/articles/478299.aspx

Upvotes: 2

jean
jean

Reputation: 1037

Is there any downside to using the TextRenderer class to measure the string (like in Marc's response) instead of going through the work to create a Graphics object, etc?

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062550

How about Graphics.MeasureString, with the overload that accepts a string, the font, and the max width? This returns a SizeF, so you can round round-off the Height.

        using(Graphics g = CreateGraphics()) {
            SizeF size = g.MeasureString(text, lbl.Font, 495);
            lbl.Height = (int) Math.Ceiling(size.Height);
            lbl.Text = text;
        }

Upvotes: 103

Yuliy
Yuliy

Reputation: 17718

Well the 60 chars might be valid for your test text, but not all characters have the same width. For instance, compare
llllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
and
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww

They both have 60 characters, and yet have vastly differing widths.

Upvotes: 0

MusiGenesis
MusiGenesis

Reputation: 75296

System.Drawing.Graphics has a MeasureString method that you can use for this purpose. Use the overload that takes a string, a font, and an int "width" parameter; this last parameter specifies the maximum width allowed for the string - use the set width of your label for this parameter.

MeasureString returns a SizeF object. Use the Height property of this returned object to set the height of your label.

Note: to get a Graphics object for this purpose, you can call this.CreateGraphics.

Upvotes: 33

Quibblesome
Quibblesome

Reputation: 25409

Graphics.MeasureString() will probably help you.

This is also one of the only usecases for using the Control.CreateGraphics() call!

Upvotes: 9

Related Questions