2009-06-28 17 views
20

Sé que es un concepto simple, pero estoy luchando con las métricas de fuentes. Centrar horizontalmente no es demasiado difícil, pero verticalmente parece un poco difícil.¿Cómo se dibuja una cadena centrada verticalmente en Java?

He intentado utilizar los métodos FontMetrics getAscent, getLeading, getXXXX en varias combinaciones, pero no importa lo que he intentado, el texto siempre está apagado por unos pocos píxeles. ¿Hay alguna manera de medir la altura exacta del texto para que esté exactamente centrado?

Respuesta

48

Nota, que hace deben considerar Precisamente lo que quiere decir con centrado vertical.

Las fuentes se representan en una línea de base, ejecutándose a lo largo de la parte inferior del texto. El espacio vertical se asigna de la siguiente manera:

--- 
^ 
| leading 
| 
-- 
^    Y  Y 
|    Y Y 
|    Y Y 
| ascent   Y  y  y 
|     Y  y y 
|     Y  y y 
-- baseline ______Y________y_________ 
|       y     
v descent    yy 
-- 

El encabezado es simplemente el espacio recomendado entre las líneas de la fuente. Con el objetivo de centrar verticalmente entre dos puntos, debe ignorar el encabezado (es el encabezado, por cierto, no leeding, en general tipografía es/fue el espacio de plomo insertado entre las líneas en una placa de impresión).

Así que para el centrado de los ascendentes y descendentes de texto, desea que el

baseline=(top+((bottom+1-top)/2) - ((ascent + descent)/2) + ascent; 

Sin el final "+ ascenso", que tiene la posición de la parte superior de la fuente; por lo tanto, agregar el ascenso va desde la parte superior a la línea de base.

Además, tenga en cuenta que la altura de la fuente debe incluir inicial, pero algunas fuentes no la incluyen, y debido a las diferencias de redondeo, la altura de la fuente puede no ser igual (avance + ascenso + descenso).

+0

Oh wow, Esa es una explicación perfecta. ¡Muchas gracias! (también para la explicación de liderar, no lo sabía) – brimborium

+1

¿Por qué estás agregando 1? – Max

+1

@Alex: Porque (abajo + 1-arriba) es la altura; si la parte inferior y la superior son iguales, la altura es uno, no cero.El efecto neto es redondear hacia abajo en el caso de que el punto medio sea n.5 píxeles. –

11

Encontré una receta here.

Los métodos cruciales parecen ser getStringBounds() y 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. 

(nota:. Por encima de código está cubierto por el MIT License como se señala en la página)

+2

Sí ... estoy familiarizado con este concepto ... pero está mal. El método fm.getAscent() es el problema. No informa el ascenso real de píxeles de la fuente y los resultados en texto que está más cerca de la parte inferior que la parte superior. –

2

No estoy seguro de que esto ayude, pero drawString(s, x, y) establece de referencia del texto en y.

Estaba trabajando con hacer un centrado vertical y no pude hacer que el texto se viera bien hasta que noté ese comportamiento mencionado en los documentos. Asumía que la parte inferior de la fuente estaba en y.

Para mí, la solución era restar fm.getDescent() de la coordenada y.

1

Otra opción es el método getBounds del 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); 
Cuestiones relacionadas