I know it\'s a simple concept but I\'m struggling with the font metrics. Centering horizontally isn\'t too hard but vertically seems a bit difficult.
I\'ve tried usi
Note, you do need to consider precisely what you mean by vertical centering.
Fonts are rendered on a baseline, running along the bottom of the text. The vertical space is allocated as follows:
---
^
| leading
|
--
^ Y Y
| Y Y
| Y Y
| ascent Y y y
| Y y y
| Y y y
-- baseline ______Y________y_________
| y
v descent yy
--
The leading is simply the font's recommended space between lines. For the sake of centering vertically between two points, you should ignore leading (it's ledding, BTW, not leeding; in general typography it is/was the lead spacing inserted between lines in a printing plate).
So for centering the text ascenders and descenders, you want the
baseline=(top+((bottom+1-top)/2) - ((ascent + descent)/2) + ascent;
Without the final "+ ascent", you have the position for the top of the font; therefore adding the ascent goes from the top to the baseline.
Also, note that the font height should include leading, but some fonts don't include it, and due to rounding differences, the font height may not exactly equal (leading + ascent + descent).
I found a recipe here.
The crucial methods seem to be getStringBounds()
and getAscent()
// Find the size of string s in font f in the current Graphics context g.
FontMetrics fm = g.getFontMetrics(f);
java.awt.geom.Rectangle2D rect = fm.getStringBounds(s, g);
int textHeight = (int)(rect.getHeight());
int textWidth = (int)(rect.getWidth());
int panelHeight= this.getHeight();
int panelWidth = this.getWidth();
// Center text horizontally and vertically
int x = (panelWidth - textWidth) / 2;
int y = (panelHeight - textHeight) / 2 + fm.getAscent();
g.drawString(s, x, y); // Draw the string.
(note: above code is covered by the MIT License as noted on the page.)
Another option is the getBounds method from the TextLayout class.
Font f;
// code to create f
String TITLE = "Text to center in a panel.";
FontRenderContext context = g2.getFontRenderContext();
TextLayout txt = new TextLayout(TITLE, f, context);
Rectangle2D bounds = txt.getBounds();
int xString = (int) ((getWidth() - bounds.getWidth()) / 2.0 );
int yString = (int) ((getHeight() + bounds.getHeight()) / 2.0);
// g2 is the graphics object
g2.setFont(f);
g2.drawString(TITLE, xString, yString);
Not sure this helps, but drawString(s, x, y)
sets the baseline of the text at y.
I was working with doing some vertical centering and couldn't get the text to look right until I noticed that behavior mentioned in the docs. I was assuming the bottom of the font was at y.
For me, the fix was to subtract fm.getDescent()
from the y-coordinate.