Solved

VB.NET Detect if labels text is overflowing and decrease font size to fit contents

Posted on 2009-04-15
7
3,247 Views
Last Modified: 2012-05-06
Hi,

I have a label which has its text changed at run time. I have set AutoEllipsis set to true to stop the text going off the side of the label. But sometimes if the text is too long it goes off the bottom of the label instead. How can I detect if this has happened and adjust the font size so that all of the text fits?

Thanks in advance,

mms_master
0
Comment
Question by:mms_master
  • 4
  • 3
7 Comments
 
LVL 12

Expert Comment

by:omegaomega
ID: 24150227
Hello, mms_master,

You can use the Graphics.MeasureString method for this purpose.  The attached snippet shows an example.

Cheers,
Randy
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

        Dim strText As String = "This is an example of setting the font size to fit the height of the label."

        Dim graLabel As Graphics = Me.Label1.CreateGraphics

        Dim sngFontSize As Single = Me.Label1.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dsfRequired As SizeF

        Do

            fntText = New Font(Me.Label1.Font.FontFamily, sngFontSize)

            dsfRequired = graLabel.MeasureString(strText, fntText)

            sngFontSize = 0.99F * sngFontSize

        Loop Until (dsfRequired.Height <= Me.Label1.ClientSize.Height)
 

        MsgBox("Final font size = " & sngFontSize)

        Me.Label1.Font = fntText

        Me.Label1.Text = strText
 

    End Sub

Open in new window

0
 
LVL 5

Author Comment

by:mms_master
ID: 24159282
Thanks for the reply. I have created a new project with just a label and button to try the code you posted. However its not working for me. The font size is reduced slightly but isn't fitting all of the text in the label. I've atatched a picture of whats happening (the labe has a lime back color so you can see how big it is).  I've also attached my code as I split it up slightly (you'll see what I mean).

Thanks
mms_master
Public Class Form1

    Dim strText As String = "This is example 1 of setting the font size to fit the height of the label." & Chr(13) & _

                            "This is example 2 of setting the font size to fit the height of the label." & Chr(13) & _

                            "This is example 3 of setting the font size to fit the height of the label."
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

        Me.lblQuestion.Text = strText
 

    End Sub
 

    Private Sub lblQuestion_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lblQuestion.TextChanged

        Dim graLabel As Graphics = Me.lblQuestion.CreateGraphics

        Dim sngFontSize As Single = Me.lblQuestion.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dsfRequired As SizeF

        Do

            fntText = New Font(Me.lblQuestion.Font.FontFamily, sngFontSize)

            dsfRequired = graLabel.MeasureString(strText, fntText)

            sngFontSize = 0.99F * sngFontSize

        Loop Until (dsfRequired.Height <= Me.lblQuestion.ClientSize.Height)
 

        MsgBox("Final font size = " & sngFontSize)

        Me.lblQuestion.Font = fntText

    End Sub

End Class

Open in new window

Test.jpg
0
 
LVL 5

Author Comment

by:mms_master
ID: 24162922
I started again keeping all the code in the button click sub. I've made a few changes and it seems to work better. However depending on the size of the label it doesn't always display the full string.

I've added Label1.Width to the MeasureString function. Used vbNewLine (or vbCrLF) instead of Chr(13) as it doesn't seem to measure properly when theres just a carriage return. The last line of the string still wasn't being displayed so I changed:

Loop Until (dsfRequired.Height <= Label1.Height )

To:

Loop Until (dsfRequired.Height <= (Label1.Height - (fntText.Height / 2)))

I also got it to reset the font to the original size each time so I can resize the text box (by anchoring it to the form) and keep pressing the button.

I will keep playing about with it a to see if it does what I need properly. If you have a better solution please let me know.

Many Thanks

mms_master
Public Class Form1
 

    Dim fntOriginal As Font
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

        Label1.Font = fntOriginal 'Reset the font to its original size
 

        Dim strText As String = "This is example 1 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 2 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 3 of setting the font size to fit the height of the label."
 

        Dim graLabel As Graphics = Label1.CreateGraphics

        Dim sngFontSize As Single = Label1.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dsfRequired As SizeF
 

        Do

            fntText = New Font(Me.Label1.Font.FontFamily, sngFontSize, Me.Label1.Font.Style)

            dsfRequired = graLabel.MeasureString(strText.Replace(vbNewLine, vbNewLine & "M"), fntText, Label1.Width)

            sngFontSize = 0.99F * sngFontSize

        Loop Until (dsfRequired.Height <= (Label1.Height - (fntText.Height / 2)))
 

        MsgBox("Final font size = " & sngFontSize)

        Label1.Font = fntText

        Label1.Text = strText
 

    End Sub
 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        fntOriginal = New Font(Label1.Font, Label1.Font.Style)

    End Sub

End Class

Open in new window

0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 12

Expert Comment

by:omegaomega
ID: 24196975
Hello, mms_master,

Sorry for the delay in getting back to you about this.  I've been travelling for a few days and haven't had the opportunity.

I hadn't realized that you were needing to display multiple lines of text.  The example I gave you was intended for the case that the label was to display a single line of text.  

So I revised the example slightly.  (MeasureString has several overloads, some of which cover the case of text wrapping over multiple lines.)  But when I tested my revised sample... it didn't work.  I found I could make it work if I set the Label's UseCompatibleTextRendering flag.  After some research, I discovered that there has been a change between versions 1.1 and 2.0 in the way text is rendered.  In version 2.0, the recommended approach seems to be to use the MeasureText method of the TextRenderer class (instead of the Graphics MeasureString method).

This MeasureText method is new to me, and I can't say that I understand all of the flags and options, but the attached snippet contains a sample that works for me in v2.0.  (If you need an example that works in v1.1 just mention it and I will provide that also.)

Btw... This is intended just to be an example.  For instance, it will shrink the font size to fit the space available, but it won't expand it to utilize excess space.  Also, the method of iteration is pretty primitive and could be improved to give more rapid (or more precise) fitting.

Cheers,
Randy

    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
 

        Dim strText As String = "This is an example of setting the font size to fit the height of the label " & _

                                "for the case that the label is to display multiple lines of wrapped text."

        Dim sngFontSize As Single = Me.Label1.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dszAvailable As New Size(Me.Label1.ClientSize.Width, Integer.MaxValue)

        Dim dszRequired As Size

        Do

            fntText = New Font(Me.Label1.Font.FontFamily, sngFontSize)

            dszRequired = TextRenderer.MeasureText(Me.Label1.CreateGraphics, strText, fntText, dszAvailable, _

                                                   TextFormatFlags.WordBreak Or TextFormatFlags.NoPadding)

            If (dszRequired.Height > Me.Label1.ClientSize.Height) Then

                sngFontSize = 0.99F * sngFontSize

            Else

                Exit Do

            End If

        Loop

        MsgBox("Final font size = " & sngFontSize)

        Me.Label1.Font = fntText

        Me.Label1.Text = strText
 

    End Sub

Open in new window

0
 
LVL 5

Author Comment

by:mms_master
ID: 24207757
No problem, thanks for getting back to me. I've just coppied your code exactly and put it on a new button.

The only thing I've changed is the value of strText to:

Dim strText As String = "This is example 1 of setting the font size to fit the height of the label." & vbNewLine & _
        "This is example 2 of setting the font size to fit the height of the label." & vbNewLine & _
        "This is example 3 of setting the font size to fit the height of the label."

and added this line before your code to set the label back to its default font before resizing it.

Label1.Font = fntOriginal

Full code atatched. Even with the new code the success seems to depend on the width of the label. (See attached pics, both were using the new code). Notice one shows example 3 and the other doesn't.


Also, just wondering why you used Integer.MaxValue instead of Label1.ClientSize.Height in this line:

Dim dszAvailable As New Size(Me.Label1.ClientSize.Width, Integer.MaxValue)

Thanks
mms_master
Public Class Form1
 

    Dim fntOriginal As Font
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

        Label1.Font = fntOriginal 'Reset the font to its original size
 

        Dim strText As String = "This is example 1 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 2 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 3 of setting the font size to fit the height of the label."
 

        Dim graLabel As Graphics = Label1.CreateGraphics

        Dim sngFontSize As Single = Label1.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dsfRequired As SizeF
 

        Do

            fntText = New Font(Me.Label1.Font.FontFamily, sngFontSize, Me.Label1.Font.Style)

            dsfRequired = graLabel.MeasureString(strText.Replace(vbNewLine, vbNewLine & "M"), fntText, Label1.Width)

            sngFontSize = 0.99F * sngFontSize

        Loop Until (dsfRequired.Height <= (Label1.Height - (fntText.Height / 2)))
 

        MsgBox("Final font size = " & sngFontSize)

        Label1.Font = fntText

        Label1.Text = strText
 

    End Sub
 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        fntOriginal = New Font(Label1.Font, Label1.Font.Style)

        Label2.Text = "Label1.ClientSize.Width = " & Label1.ClientSize.Width

    End Sub
 

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
 

        Label1.Font = fntOriginal 'Reset the font to its original size
 

        Dim strText As String = "This is example 1 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 2 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 3 of setting the font size to fit the height of the label."
 

        Dim sngFontSize As Single = Me.Label1.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dszAvailable As New Size(Me.Label1.ClientSize.Width, Integer.MaxValue)

        Dim dszRequired As Size

        Do

            fntText = New Font(Me.Label1.Font.FontFamily, sngFontSize)

            dszRequired = TextRenderer.MeasureText(Me.Label1.CreateGraphics, strText, fntText, dszAvailable, _

                                                   TextFormatFlags.WordBreak Or TextFormatFlags.NoPadding)

            If (dszRequired.Height > Me.Label1.ClientSize.Height) Then

                sngFontSize = 0.99F * sngFontSize

            Else

                Exit Do

            End If

        Loop

        MsgBox("Final font size = " & sngFontSize)

        Me.Label1.Font = fntText

        Me.Label1.Text = strText
 

    End Sub
 

    Private Sub Label1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Label1.Resize

        label2.text = "Label1.ClientSize.Width = " & Label1.ClientSize.Width

    End Sub

End Class

Open in new window

MeasureString.JPG
0
 
LVL 12

Accepted Solution

by:
omegaomega earned 250 total points
ID: 24210386
Hi, Hello, mms_master,

Well, that's "interesting" for sure.  In my original tests I was using a Label of size (153,58) and everything seemed to work normally.  When I changed it to the sizes you are using I saw similar problems and others.  I found that not only changing the width of the Label had an impact, but also changing the height.  In some circumstances, even the vbNewLine characters were not rendered correctly, showing up as rectangles instead.

I added a textbox to the form to record font size and "required height" for each iteration and found that the required height seems to be "quantized".  That is, it remained constant for a range of font sizes, suggesting that perhaps the rendered font size is quantized.  The results for three Labels of different heights are shown in the first attached picture.  As can be seen in the first image (with the shortest Label) there is a very large jump in required height as font size changes from 6.00 to 5.94.  The text rendered with the calculated font size fits in the case of the first two images, but not in the third.

I also tried experimenting with turning on the UseCompatibleTextRendering property.  The second picture shows that this does have an effect, but does not solve the problem.  The Label on the left has the property set to False.  The one on the right has it set to True.

Finally, I tried performing similar tests using the old MeasureString method (with the UseCompatibleTextRendering property set to True).  The results of my tests (which were not exhaustive) are shown in the third picture.  In this case the required height does not display the same quantization effect, but there is still a very large jump in required height as the font size changes from 6.50 to 6.44.  This results in a significant amount of waste space at the bottom of the Label in the first image.  But at least the whole text is included in all three cases, so perhaps this is a better solution.  In case it might be useful to you, I have included the code for this in the attached snippet.

One possible suggestion that you might want to consider is just painting the text yourself using the Graphics DrawText method in the Paint event.  This would allow you to use the Graphics ScaleTransform to adjust the size.  I have done this successfully in the past with my own controls (although not with a Label) and never had a problem with the quantization or inconsistency that you are seeing here.

Beyond that, I'm stumped.  This thread is getting old, so you might want to repost the question in the hope that someone more experienced can offer better help.

Cheers,
Randy

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

        Label1.Font = fntOriginal 'Reset the font to its original size
 

        Dim strText As String = "This is example 1 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 2 of setting the font size to fit the height of the label." & vbNewLine & _

        "This is example 3 of setting the font size to fit the height of the label."
 

        Dim graLabel As Graphics = Me.Label1.CreateGraphics

        Dim sngFontSize As Single = Me.Label1.Font.Size

        MsgBox("Original font size = " & sngFontSize)

        Dim fntText As Font

        Dim dsfAvailable As New SizeF(Me.Label1.ClientSize.Width, Me.Label1.ClientSize.Height)

        Dim dsfRequired As SizeF

        Dim stfFormat As New StringFormat(StringFormatFlags.LineLimit Or StringFormatFlags.FitBlackBox)

        stfFormat.Trimming = StringTrimming.EllipsisCharacter

        stfFormat.Alignment = StringAlignment.Near

        stfFormat.LineAlignment = StringAlignment.Near

        Do

            fntText = New Font(Me.Label1.Font.FontFamily, sngFontSize)

            dsfRequired = graLabel.MeasureString(strText, fntText, Me.Label1.ClientSize.Width, stfFormat)

            Me.TextBox1.Text = Me.TextBox1.Text & vbCrLf & _

                               "Font size = " & sngFontSize & ", Required height = " & dsfRequired.Height

            If (dsfRequired.Height > dsfAvailable.Height) Then

                sngFontSize = 0.99F * sngFontSize

            Else

                Exit Do

            End If

        Loop

        MsgBox("Final font size = " & sngFontSize)

        Me.Label1.Font = fntText

        Me.Label1.Text = strText
 

    End Sub

Open in new window

Results-1.jpg
Results-2.jpg
Results-3.jpg
0
 
LVL 5

Author Closing Comment

by:mms_master
ID: 31570534
Thank you.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Introduction When many people think of the WebBrowser (http://msdn.microsoft.com/en-us/library/2te2y1x6%28v=VS.85%29.aspx) control, they immediately think of a control which allows the viewing and navigation of web pages. While this is true, it's a…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now