When using Graphics.DrawString is there any way to determine, before the render, the actual dimensional size that the text will take up when using WrapWidth and/or Condense?

Mainly this would be used for centering text in a button, if that text go too long then it would auto condense or wrap depending on user settings. If it wraps when I need to get the precise measurement so I can center is vertically.

I see there is StringWidth, but this doesnt cope with multiline, and there’s obviously StringHeight.

Do I need to throw out Graphics.DrawString and write my own or am I missing something?

Hmm, when you use wrapwith (even with condense), you know it would not be more than the configured value. So it can only be smaler.

if stringwidth < wrapwidth then width = stringwidth else width = wrapwidth

If that is not precise enough, you should not use wrapwidth and condense. You could do that on your own.

Yeah, thats the problem, some space at the end of a cut line where the proportional font doesnt quite finish right.

Also some space at the end of a condensed line because of the same issue.

Use of StringHeight and StringWidth are most appropriate for this… as long as you understand the restrictions.

  • on OSX/macOS these return a DOUBLE, so you need to ROUND UP to the next integer to make sure they fit
  • on WIndows, these return an INTEGER, (which is rounded DOWN already), so you need to add 1 to make sure they fit

These functions are used extensively in my gPDF class, and as long as the above modifications are applied, they work just fine

Oh… and it is because of the above that most people indicate [quote]If that is not precise enough.[/quote]

There is a way around the lack of precision in Windows : measure stringwidth and stringheight for a font size 10 or even 100 times bigger, and divide by 10 or 100.

Found something in my code:

Private Function CalculateTextLines() as String

[code] dim theText as string = ReplaceAll(pText, “:”, ": ")
theText = ReplaceAll(theText, “: :”, “::”)
theText = ReplaceAll(theText, “/”, "/ ")
dim TextArray(-1) as string = Split(theText, " ")

dim FinalText(-1) as String
dim currentLine as String
for currentWord as Integer = 0 to UBound(TextArray)
if currentLine = “” and getStringWidth(TextArray(currentWord)) < me.Width - 20 then
'first word
currentLine = TextArray(currentWord)
elseif currentLine <> “” and getStringWidth(currentLine + " " + TextArray(currentWord)) < me.Width then
'need one more word
currentLine = currentLine + " " + TextArray(currentWord)
currentLine = ReplaceAll(currentLine, ": ", “:”)
'length reached
currentLine = ReplaceAll(currentLine, ": ", “:”)
FinalText.Append currentLine
currentLine = TextArray(currentWord)
end if


FinalText.Append currentLine
Return Join(FinalText, " ")
End Function[/code]


[code]Private Function getStringWidth(theString as String) as Integer

dim thePicture as new Picture(500, 100, 32)
thePicture.Graphics.TextFont = me.TextFont
thePicture.Graphics.TextSize = me.TextSize

Return thePicture.Graphics.StringWidth(theString)

End Function[/code]

As far as I can see the intent of my code is a different one. I have text with “bla:something:bla:else” that needs to be changed to “bla:something: bla:else” with a space in the middle so that the text breaks.


problem is, it still comes up short for DrawString

since it only accepts INTEGERS, so you still need to ROUND UP

OSX might return 100.7 for a stringwidth, while Windows will return 100 for the same string
in order to insure it fits in both places you need 101

What do you mean ? That solves the integer rounding.

no it doesn’t… because Windows reports an INTEGER value to begin with… so you are starting with a value that is potentially less than it should be

for OSX x=(CEIL(100.7)*100)/100 is 101, but for windows is still comes out 100 (short)

		Dim s As String="Now is the time for all good men to come to the aid of their country"
		Dim p As picture
		Dim g As graphics
		Dim whole As Double
		Dim sum As Double
		Dim i As Integer
		Dim c As String
		p=New picture(10,10)
		g.TextFont="Arial" // to insure the same font on both OSX and windows
		For i=1 To Len(s)
		Next i
		MsgBox "Whole="+Str(whole)+" Sum="+Str(sum)
		// Xojo 2016 r4.1
		// OSX 10.11.6 returns 1411.359 for both values
		// Win 10 returns 

Unfortunatly my remote connection to my Win10 machine is not working, but I’ll bet dollars to doughnuts that the above code run on Win 10 will return something closer to 1400 (or less)

EDIT : Windows 10 return 1405.000 as opposed to OSX with 1411.359

Whole=1411.359 Sum=1411.359

You don’t get it.

Sure Windows uses integer values. Let us say Mac would report 10.7 using a double.

I measure stringwidth for fontsize*10. The result is 107 (Integer). Divided by 10 gives 10.7 (double). Do you want me to write the method for you that returns a double ?

not on windows it didnt

Michel… YOU dont get it… Windows does not return the right value to begin with… so no amount of “math” can fix that

On OSX you might get 10.7, but on Windows you get 10.0

Try the code I posted above… it proves it quite nicely

and read the LR (which I quoted above. OSX uses doubles, Win uses Integers)

Its ok guys, StringWidth isnt the issue I have, as I said in my OP but thanks anyway :slight_smile:

Its to do with the varying space at the end of a wrapped/shortened line.

Thanks for all the source code etc. I can write it without a problem :slight_smile: I just really needed to know if there was something obvious that I had overlooked, before I wrote my own.

[quote=310818:@Dave S]@anon20074439 Whole=1411.359 Sum=1411.359
not on windows it didnt[/quote]

Right-O I’ll take your word for it, but I could have sworn I was using WIndows 10 :smiley:

I might be using a Mac, I’m not sure tbh:

Whatever. Your project simply demonstrates that an integer creates a rounding error. Be happy in your certitudes.

Now I have to fire up vmware and test the code on Win 7 and 8.1 just for “funsies”

2016r4.1 reports DOUBLE values for stringwidth on Windows - same as OS X

Hug for big Norm and the Xojo team :slight_smile: