Text height calculation with wrapped text

lebb
05-26-2006, 04:46 PM
I've been trying to develop a reasonably accurate auto-sizing label control. The idea is that the control will have a fixed width, and will adjust its own height based on its contents. However, so far all my attempts are slightly off with some input strings (especially long ones) and widths. Can anyone spot the flaw in my approach or suggest a better method?

Public Class SmartSizeLabel
Inherits System.Windows.Forms.Label

Private _noReentry As Boolean = False

Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)

If Not _noReentry Then _SetBestHeight()
End Sub

Protected Overrides Sub OnStyleChanged(ByVal e As System.EventArgs)
MyBase.OnStyleChanged(e)

_SetBestHeight()
End Sub

Public Overrides Property Text() As String
Get
Return MyBase.Text
End Get
Set(ByVal value As String)
MyBase.Text = value

_SetBestHeight()
End Set
End Property

Private Sub _SetBestHeight()
Dim gfx As Graphics = Me.CreateGraphics()

_SetBestHeight(gfx)
gfx.Dispose()
End Sub

Private Sub _SetBestHeight(ByVal gfx As Graphics)
Dim diff As Integer = Me.Height - Me.ClientSize.Height

_noReentry = True
Me.Height = Convert.ToInt32(_BestHeight(gfx)) + diff + Me.Margin.Top + Me.Margin.Bottom
_noReentry = False
End Sub

Private Function _BestHeight(ByVal gfx As Graphics) As Single
Dim srcSize As New SizeF(Me.ClientRectangle.Width, Single.MaxValue)
Dim bestSize As SizeF = gfx.MeasureString(Me.Text, Me.Font, srcSize, _
Drawing.StringFormat.GenericTypographic)

Return bestSize.Height
End Function
End Class


Note: For testing, I am setting the control's AutoSize property to False and BorderStyle to FixedSingle (just to be able to more clearly see the problems).

jo0ls
05-27-2006, 08:45 PM
Try stringformat.default. If you use measurestring with the typographic version then it is probably wrapping/clipping the text in a different way to the control itself when it paints the text.

lebb
05-27-2006, 08:48 PM
Thanks jo0ls. I have tried with both methods, and can't tell much difference (it's possible that they're "off" in slightly different ways, but in any case neither is correct).

Any other thoughts?

jo0ls
05-27-2006, 08:57 PM
Ah, I had a small label.
If you override OnPaint too, then you can definately get them matching.
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), Me.Bounds, StringFormat.GenericTypographic)
End Sub

lebb
05-27-2006, 09:34 PM
*scratches head*

If I use Me.Bounds, then the calculations don't seem to work at all -- why would I use that instead of Me.ClientRectangle?

I've tried this with just adding your suggestion as-is, with changing your Me.Bounds to Me.ClientRectangle, and with changing my Me.ClientRectangle to Me.Bounds. With both as ClientRectangle, I get the same results as previously. With either of the other two combinations, they are even more wrong than they were before.

Am I misunderstanding something in your suggestion?

jo0ls
05-28-2006, 04:57 AM
Argh, I was convinced it was working, it was very late though. I was doing something similar a while ago. I'll have another look.

jo0ls
05-28-2006, 06:42 AM
The height needs rounding up, and then paint the text with a matching stringformat.

Private Function _BestHeight(ByVal gfx As Graphics) As Single
Dim srcSize As New SizeF(Me.ClientRectangle.Width, Single.MaxValue)
Dim bestSize As SizeF = gfx.MeasureString(Me.Text, Me.Font, _
srcSize, StringFormat.GenericTypographic)
Return Math.Ceiling(bestSize.Height)
End Function

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), _
New RectangleF(0, 0, Me.ClientSize.Width, Me.ClientSize.Height), _
StringFormat.GenericTypographic)
End Sub

lebb
05-28-2006, 06:36 PM
You've done it! Thanks so much, jo0ls -- I hadn't even considered the rounding issue. With a little tweaking to account for margins, this is perfect. :)

lebb
05-29-2006, 12:01 AM
In case it's of interest to anyone else, here is the final solution (http://www.verbalclay.com/blog/2006/05/28/resizing-label-control-for-vbnet/) I ended up with. As best I can tell, this works fine for any border style or margin combination.

Thanks again for all your help.

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum