Canvas1.DrawString vertically centered

Centering text HORIZONTALLY is super easy.


x = (PrintArea.Width - String.Width) / 2

But doing so vertically is a totally different beast. I tried ad nauseam different code and failed.

My target Canvas have a user setting background color, so I can see if the text is centered… (h and v)

I can change the string Size and the Font Name…

At this stage, I am exhausted. Usually, I only have to do other things for a day or two, then when I came back I know how to do, but this time, the only color I get is black (or blue ?).

You need to account for the baseline of the string using g.FontAscent. Try this in a Canvas’ Paint event:

g.DrawingColor = &cff0000
g.DrawRectangle( 0, 0, g.Width, g.Height )

var textToDraw as String = "This is a test string."
var textWidth as Double = g.TextWidth( textToDraw )
var textX as Double = (g.Width - textWidth) / 2
var textY as Double = ((g.height - g.TextHeight) / 2) + g.FontAscent

g.DrawText( textToDraw, textX, textY, textWidth )

image

2 Likes

and even more difficult if text is styled !

Thank you Anthony, Jean-Yves.

No style.

2 Likes

the “new” TextShape is also good for alignment.

At last, I get some troubles with the shared example.

I used it as is, and it worked fine, but I went ahead and add a way to increase the font size. Because I put the testing Canvas above an existing window, I changed the colors.

Here’s my current code (MouseDown and Paint are Canvas1 Events, the gSize Property is in Window1):
Function MouseDown(X As Integer, Y As Integer) As Boolean

gSize = gSize + 16

Me.Invalidate

Return True
End Function

Sub Paint(g As Graphics, areas() As REALbasic.Rect)
// Fills the Canvas background
g.ForeColor = &cffff00
g.DrawRect(0, 0, g.Width, g.Height)
g.FillRect(0, 0, g.Width, g.Height)

// Set a Default Size
g.TextSize = gSize

// Text Color
g.ForeColor = &c000000

// Compute the draw location
Dim textToDraw As String = “tout petit” // String with ascent and descent
Dim textWidth As Double = g.StringWidth( textToDraw )
Dim textX As Double = (g.Width - textWidth) / 2
Dim textY As Double = ((g.height - g.StringHeight(textToDraw,g.Width)) / 2) + g.TextAscent

// Draw the String
g.DrawString(textToDraw, textX, textY, textWidth)

End Sub

gSize Property:
gSize As Integer = 64

My conclusion: maybe my idea to make the print centered by code was a bad idea.
Also, the String Draw Size depends on its length (a max size around 140 pixels can be defined for a long string).

The base line change each time I enlarge the Font Size. Due to the bad idea to use “Top” as a test text, it tooks me time to realize some sizes will probably never be used; a meaningful string is far more than 3 characters (Using “Top” was a good idea because it holds a character with Ascent and another with Descent; it is also draw at the… top of the Canvas… a second one is drawn at its bottom…)…

Change the textY calculation line to:

var textY as Double = ((g.height - g.TextHeight) / 2) + g.FontAscent - ((g.TextHeight - g.FontAscent) / 2)

This actually gets you a better fit than using a TextShape’s VerticalAlignment set to Center.

var t as new TextShape
t.FillColor = &cff0000
t.Value = "String."
t.FontSize = FontSize
t.VerticalAlignment = TextShape.Alignment.Center
t.HorizontalAlignment = TextShape.Alignment.Center
g.DrawObject( t, g.Width / 2, g.Height / 2 )

4 Likes