Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you draw a string centered vertically in Java?

Tags:

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 using the FontMetrics getAscent, getLeading, getXXXX methods in various combinations but no matter what I've tried the text is always off by a few pixels. Is there a way to measure the exact height of the text so that it is exactly centered.

like image 426
Paul Alexander Avatar asked Jun 28 '09 21:06

Paul Alexander


People also ask

How do you vertically align text in Java?

exactCentre() = (top + bottom) / 2f . These would only yield the same result when top is 0 . This may be the case for some fonts at all sizes, or other fonts at some sizes, but not for all fonts at all sizes. Show activity on this post.

What is vertically centered?

Vertical alignment can be applied to two or more objects to center them vertically in relation to each other, so that the center of each object is found in the same plane extending between the two sides of the page.

What are font metrics?

Font metrics are measurements of text rendered by a Font object such as the height of a line of text in the font. The most common way to measure text is to use a FontMetrics instance which encapsulates this metrics information.


2 Answers

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).

like image 151
Lawrence Dol Avatar answered Oct 06 '22 23:10

Lawrence Dol


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.)

like image 26
Otto Allmendinger Avatar answered Oct 07 '22 01:10

Otto Allmendinger