【发布时间】:2015-09-01 03:22:12
【问题描述】:
我知道这是一个简单的概念,但我在字体指标方面遇到了困难。水平居中并不太难,但垂直居中似乎有点困难。
我尝试过以各种组合方式使用 FontMetrics getAscent、getLeading、getXXXX 方法,但无论我尝试什么,文本总是偏离几个像素。有没有办法测量文本的确切高度,使其完全居中。
【问题讨论】:
我知道这是一个简单的概念,但我在字体指标方面遇到了困难。水平居中并不太难,但垂直居中似乎有点困难。
我尝试过以各种组合方式使用 FontMetrics getAscent、getLeading、getXXXX 方法,但无论我尝试什么,文本总是偏离几个像素。有没有办法测量文本的确切高度,使其完全居中。
【问题讨论】:
注意,您确实需要准确考虑垂直居中的含义。
字体在基线上呈现,沿着文本底部延伸。垂直空间分配如下:
---
^
| leading
|
--
^ Y Y
| Y Y
| Y Y
| ascent Y y y
| Y y y
| Y y y
-- baseline ______Y________y_________
| y
v descent yy
--
前导只是字体推荐的行间距。为了在两点之间垂直居中,您应该忽略前导(它是 ledding,顺便说一句,不是 leeding;在一般排版中,它是/曾经是印版中的行之间插入的引线间距)。
因此,为了使文本上升和下降居中,您需要
baseline=(top+((bottom+1-top)/2) - ((ascent + descent)/2) + ascent;
没有最后的“+ ascent”,你就有了字体顶部的位置;因此添加上升是从顶部到基线。
另外,请注意字体高度应该包括前导,但有些字体不包括它,并且由于舍入差异,字体高度可能不完全相等(前导 + 上升 + 下降)。
【讨论】:
我找到了一个食谱here。
关键方法似乎是getStringBounds() 和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.
(注意:上面的代码被页面上的MIT License 覆盖。)
【讨论】:
不确定这是否有帮助,但drawString(s, x, y) 将文本的基线设置为 y。
我正在做一些垂直居中的工作,直到我注意到文档中提到的行为之前,我无法让文本看起来正确。我假设字体的底部在 y 处。
对我来说,解决方法是从 y 坐标中减去 fm.getDescent()。
【讨论】:
另一个选项是来自TextLayout class 的getBounds 方法。
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);
【讨论】: