Java 2D - 垂直居中文本

Java 2D - Vertically centering text

我面临的问题是,我从字体指标对象获得的下降似乎不正确。这仅在非常大的字体上才明显。我已经尝试使用 FontMetrics#getDescent-方法和 FontMetrics#getStringBounds-方法,然后我使用 heighty 手动确定下降。虽然两者给出的结果略有不同,但都是不正确的。为预定义字符集获取正确基线的最正确方法是什么?在我的例子中,它是字符 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 中减去 leadingdescent,然后除以二。看起来如果你不包括前导,大字体的文本会漂移。在此示例中,字体大小为 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);
}