FontMetrics.getStringBounds for AttributedString gives wrong result?

只愿长相守 提交于 2019-12-01 11:49:10

FontMetrics fontMetrics = graphics.getFontMetrics() returns a FontMetrics object based on the single font currently set on the graphics object. You are not changing the font used by graphics explicitly so it uses the default font designated for JPanel by the current L&F.

FontMetrics methods related to bounds calculation accept a "simple" CharacterIterator (which does not provide font information) instead of AttributedCharacterIterator (which does). Hence fontMetrics.getStringBounds() simply calculates the text bounds based on the single font of the same size.

You need to use java.awt.font.TextLayout to determine the proper bounds when using AttributedCharacterIterator with different fonts and font sizes:

TextLayout textLayout = new TextLayout( 
        text.getIterator(), 
        g.getFontRenderContext() 
);
Rectangle2D.Float textBounds = ( Rectangle2D.Float ) textLayout.getBounds();

g.drawString( text.getIterator(), 50, 50 );
// lets draw a bounding rect exactly around our text
// to be sure we calculated it properly
g.draw( new Rectangle2D.Float(
        50 + textBounds.x, 50 + textBounds.y,
        textBounds.width, textBounds.height
) );

The FontMetrics only receives a CharacterIterator, and does not take into account that it is actually an AttributedCharacterIterator. You can use a TextMeasurer to compute the actual bounds of your string. For comparison, add this after you called the drawString method:

    // Compensate for the 50,50 of the drawString position
    g.translate(50, 50);

    g.setColor(Color.RED);
    Rectangle2D wrongBounds = fm.getStringBounds(
            text.getIterator(), 0, text.getIterator().getEndIndex(), g);
    g.draw(wrongBounds);
    System.out.println("wrong: "+wrongBounds);

    g.setColor(Color.BLUE);
    AttributedCharacterIterator iterator = text.getIterator();
    TextMeasurer tm = new TextMeasurer(iterator, g.getFontRenderContext());
    Rectangle2D rightBounds = tm.getLayout(0, iterator.getEndIndex()).getBounds();
    g.draw(rightBounds);
    System.out.println("right: "+rightBounds);

(And BTW: Don't call g.dispose() on the Graphics that was handed to you in the paintComponent method)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!