Java 2D - 垂直居中文本
Java 2D - Vertically centering text
我面临的问题是,我从字体指标对象获得的下降似乎不正确。这仅在非常大的字体上才明显。我已经尝试使用 FontMetrics#getDescent
-方法和 FontMetrics#getStringBounds
-方法,然后我使用 height
和 y
手动确定下降。虽然两者给出的结果略有不同,但都是不正确的。为预定义字符集获取正确基线的最正确方法是什么?在我的例子中,它是字符 0-9
。这些都应该有相同的基线,因此很容易居中。所以至少我的假设。
这是一个展示问题的例子:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.UIManager;
public class Draw
{
public static void main( String[] args )
{
JFrame frame = new JFrame();
frame.add( new X() );
frame.pack();
frame.setSize( 150, 300 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
private static class X extends JComponent
{
private final Font xFont;
public X()
{
xFont = UIManager.getFont( "Label.font" ).deriveFont( 40.0f );
}
@Override
public void paint( Graphics g )
{
g.setColor( Color.YELLOW );
g.fillRect( 0, 0, getWidth(), getHeight() );
g.setColor( Color.BLACK );
g.drawLine( 0, getHeight() / 2, getWidth() - 1, getHeight() / 2 );
g.setFont( xFont );
g.drawString( "X", getWidth() / 2, getHeight() / 2 + g.getFontMetrics().getDescent() );
}
}
}
黑线代表组件的中间。 X
的垂直中心应与直线对齐。
我相信你想要:
FontMetrics fm = g.getFontMetrics();
g.drawString( "X", getWidth() / 2, (getHeight() + fm.getAscent() - fm.getDescent())/2 );
给出:
即使使用大字体,以下内容似乎也能正常工作。调整是从 ascent
中减去 leading
和 descent
,然后除以二。看起来如果你不包括前导,大字体的文本会漂移。在此示例中,字体大小为 300
。对于较小的字体,这可能不是问题。
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(0, getHeight() / 2, getWidth(),
getHeight() / 2);
g.setFont(xFont);
String s = "X";
FontMetrics fm = g.getFontMetrics();
int swidth = fm.stringWidth(s);
int ctrx = getWidth() / 2;
int ctry = getHeight() / 2;
int mheight = fm.getAscent() - fm.getDescent() - fm.getLeading();
g.drawString(s, ctrx - swidth/2, ctry + mheight/2);
}
我面临的问题是,我从字体指标对象获得的下降似乎不正确。这仅在非常大的字体上才明显。我已经尝试使用 FontMetrics#getDescent
-方法和 FontMetrics#getStringBounds
-方法,然后我使用 height
和 y
手动确定下降。虽然两者给出的结果略有不同,但都是不正确的。为预定义字符集获取正确基线的最正确方法是什么?在我的例子中,它是字符 0-9
。这些都应该有相同的基线,因此很容易居中。所以至少我的假设。
这是一个展示问题的例子:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.UIManager;
public class Draw
{
public static void main( String[] args )
{
JFrame frame = new JFrame();
frame.add( new X() );
frame.pack();
frame.setSize( 150, 300 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
private static class X extends JComponent
{
private final Font xFont;
public X()
{
xFont = UIManager.getFont( "Label.font" ).deriveFont( 40.0f );
}
@Override
public void paint( Graphics g )
{
g.setColor( Color.YELLOW );
g.fillRect( 0, 0, getWidth(), getHeight() );
g.setColor( Color.BLACK );
g.drawLine( 0, getHeight() / 2, getWidth() - 1, getHeight() / 2 );
g.setFont( xFont );
g.drawString( "X", getWidth() / 2, getHeight() / 2 + g.getFontMetrics().getDescent() );
}
}
}
黑线代表组件的中间。 X
的垂直中心应与直线对齐。
我相信你想要:
FontMetrics fm = g.getFontMetrics();
g.drawString( "X", getWidth() / 2, (getHeight() + fm.getAscent() - fm.getDescent())/2 );
给出:
即使使用大字体,以下内容似乎也能正常工作。调整是从 ascent
中减去 leading
和 descent
,然后除以二。看起来如果你不包括前导,大字体的文本会漂移。在此示例中,字体大小为 300
。对于较小的字体,这可能不是问题。
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(0, getHeight() / 2, getWidth(),
getHeight() / 2);
g.setFont(xFont);
String s = "X";
FontMetrics fm = g.getFontMetrics();
int swidth = fm.stringWidth(s);
int ctrx = getWidth() / 2;
int ctry = getHeight() / 2;
int mheight = fm.getAscent() - fm.getDescent() - fm.getLeading();
g.drawString(s, ctrx - swidth/2, ctry + mheight/2);
}