StringWidth Vs. TextWidth

Today I noticed that the Xojo docs state that StringWidth was deprecated in v2019r2 and it suggests that you use TextWidth as a replacement.

But, StringWidth returns a measurement in Pixels whereas TextWidth returns a measurement in Points. So how can you replace StringWidth with TextWidth if they don’t return the same values?

StringWidth also uses points, so both StringWidth and TextWidth work exactly the same. Looks like the docs for StringWidth were never updated when things went from pixels to points a few years ago.

Ah Ok. I’m trying to figure out a way to determine if a string in a particular font will fit inside of a label. If the string is too long to fit I want to truncate the rightmost part enough to fit into the label with a trailing ellipsis.

Any suggestions?

Create a static picture, using new Picture(1,1,32) and use the graphics from that to set the font name, size and call textWidth to find the size. Then if too long remove last char and test with “…” on the edit repeating until it fits or the last char is removed.

Also note there is padding on the label so might need to add some margins to your check

An extension method like this is a start:

Public Sub TruncatedText(Extends lbl As Label, Assigns value As String)
  Var p As Picture = lbl.TrueWindow.BitmapForCaching(1, 1)
  
  Var g As Graphics = p.Graphics
  g.FontName = lbl.FontName
  g.FontSize = lbl.FontSize
  
  Var w As Integer = g.TextWidth(value)
  
  // Text fits in the Label
  If w <= lbl.Width Then
    lbl.Text = value
    Return
  End If
  
  // Find the maximum length of text that will
  // fit in the label (with an ellipses) and
  // use that.
  Var ellipsesWidth As Integer = g.TextWidth("…")
  
  For i As Integer = value.Length DownTo 1
    w = g.TextWidth(value.Left(i)) 
    
    If w <= lbl.Width - ellipsesWidth Then
      lbl.Text = value.Left(i) + "…"
      Exit For
    End If
  Next
End Sub

Usage:

MyLabel.TruncatedText = "Some really long text that should get cut off"
1 Like

Thanks Paul, I found a similar bit of code in the forum and modified it.

This is what I came up with. This code prevents the ellipsis from being tacked-on after a trailing space. And prevents the ellipsis from being displayed without at least one character preceding it.

Public Sub TextWithEllipsis(Extends This_lbl As Label, Assigns This_str As String)
  
  ' Creat a picture object that we can use for its
  ' Graphics properties.
  '
  Dim Pic As New Picture(1,1)
  
  ' Set the picture object to the same font characteristics
  ' as the label we are trying to populate.
  '
  Pic.Graphics.FontUnit = This_lbl.FontUnit
  Pic.Graphics.FontSize = This_lbl.FontSize
  Pic.Graphics.FontName = This_lbl.FontName
  Pic.Graphics.Italic = This_lbl.Italic
  Pic.Graphics.Bold = This_lbl.Bold
  
  ' If the specified string (after trimming) fits within this
  ' label we update the label and exit.
  '
  This_str = This_str.Trim
  If Pic.Graphics.TextWidth(This_str) <= This_lbl.Width Then
    This_lbl.Text = This_str
    Exit Sub
  End
  
  ' If the specified string doesn't fit within this label we 
  ' start shortening the string one character at a time.
  '
  Var Temp_str As String
  For i As Integer = This_str.Length DownTo 1
    
    ' Build new shorter string (right trimmed) with a
    ' trailing ellipsis.
    '
    Temp_str = This_str.Left(i).TrimRight + "..."
    
    ' Does the new shorter string (with ellipsis) fit
    ' into the label?
    '
    If Pic.Graphics.TextWidth(Temp_str) <= This_lbl.Width Then

      '  Update the label and exit.
      '
      This_lbl.Text = Temp_str
      Exit Sub

    End
    
  Next
  
  ' If we made it this far we have a label that is too
  ' small to display one character (with an ellipsis 
  ' tacked-on), so update label with an empty string.
  '
  This_lbl.Text = ""
  
End Sub
2 Likes