fontmetrics java,如何从JAVA中的FontMetrics获取正确的String宽度

I calculate the width of a string by using the stringWidth("str") method on the FontMetrics object. This method only gives me the width from the starting point to the ending point on the baseline. Not the overall width of the string.

Any ideas on how to calculate the overall width?

Most documentation says that I can't rely on the result by adding the width of each char in the string.

Here is my code until now:

BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);

Graphics2D g = image.createGraphics();

FontMetrics fm = g.getFontMetrics(new Font("Arial", Font.PLAIN, 6));

int width = fm.stringWidth("Product name");

解决方案

FontMetrics also has getStringBounds(), not just stringWidth().

You should ask yourself what you need the text width for. If it's for output via e.g. a paintComponent() override, then you should measure the text dimensions there, which makes sure that all factors (e.g. fractionalmetrics, antialiasing) are taken into consideration. Also, you don't have to think about disposing the graphics context - which in your example, you definitely have to, it needs g.dispose()!

The following example for use in a paintComponent() override, e.g. for the JPanel you're using as your ContentPane, draws a text at the center of the component in a font given by you and draws a rectangle around it with some distance, the text being perfectly in its center.

The text size, especially vertically, is not precise, however. A better solution is further down.

Screenshot of this imprecise solution: http://i.imgur.com/vetRjCK.png

Screenshot of precise solution further down: http://i.imgur.com/0A0EdCf.png

final int w = getWidth();

final int h = getHeight();

// CLEAR BACKGROUND

g.setColor(Color.DARK_GRAY);

g.fillRect(0, 0, w, h);

// ACTIVATE ANTIALIASING AND FRACTIONAL METRICS

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

// PREPARE TEXT, COLOR, FONT

final String text = "The Higgs Boson is ...";

g.setColor(Color.ORANGE);

g.setFont(yourFont);

// PREPARE COORDINATES, AND DRAW TEXT

final FontMetrics fm = g.getFontMetrics();

final Rectangle2D stringBounds = fm.getStringBounds(text, g);

final double x = (w - stringBounds.getWidth()) / 2d;

final double y = (h - stringBounds.getHeight()) / 2d;

g.drawString(text, (int) x, (int) (y + fm.getAscent()));

// TURN OFF ANTIALIASING FOR HIGHER VISUAL PRECISION OF THE LINES

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);

// DRAW RECTANGLE BORDER

final double borderDistance = 10d;

final Shape borderRect = new Rectangle2D.Double(x - borderDistance * 2, y - borderDistance, stringBounds.getWidth() + borderDistance * 4, stringBounds.getHeight() + borderDistance * 2);

g.setStroke(new BasicStroke(3f));

g.draw(borderRect);

// DRAW THIN TIGHT RECTANGLE BORDER

final Shape borderRectTight = new Rectangle2D.Double(x, y , stringBounds.getWidth(), stringBounds.getHeight());

g.setStroke(new BasicStroke(1f));

g.setColor(Color.GRAY);

g.draw(borderRectTight);

The following solution is structurally just like the above, but instead of using FontMetrics-calls to loosely derive the text dimensions, it derives the precise text dimensions by converting the text into a Shape first.

// CLEAR BACKGROUND

g.setColor(Color.DARK_GRAY);

g.fillRect(0, 0, w, h);

// ACTIVATE ANTIALIASING AND FRACTIONAL METRICS

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

// PREPARE TEXT, COLOR

final String text = "The Higgs Boson is ...";

g.setColor(Color.ORANGE);

// CREATE GLYPHVECTOR FROM TEXT, CREATE PRELIMINARY SHAPE FOR COORDINATE CALCULATION, CALC COORDINATES

final GlyphVector gv = yourFont.createGlyphVector(g.getFontRenderContext(), text);

final Rectangle2D stringBoundsForPosition = gv.getOutline().getBounds2D();

final double xForShapeCreation = (w - stringBoundsForPosition.getWidth()) / 2d;

final double yForShapeCreation = (h - stringBoundsForPosition.getHeight()) / 2d;

// DERIVE SHAPE AGAIN, THIS TIME IN THE RIGHT PLACE (IT'S NOT THE ONLY POSSIBLE METHOD.)

final Shape textShape = gv.getOutline((float) xForShapeCreation, (float) yForShapeCreation + g.getFontMetrics(yourFont).getAscent());

g.fill(textShape);

// GET PRECISE SHAPE BOUNDS, TURN OFF ANTIALIASING FOR HIGHER VISUAL PRECISION OF THE LINES

final Rectangle2D stringBoundsForEverything = textShape.getBounds2D();// JavaDocs: "Returns a high precision [...] bounding box of the Shape [...] guarantee [...] that the Shape lies entirely within the indicated Rectangle2D."

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);

// DRAW RECTANGLE BORDER

final double borderDistance = 10d;

final Shape borderRect = new Rectangle2D.Double(stringBoundsForEverything.getX() - borderDistance * 2, stringBoundsForEverything.getY() - borderDistance, stringBoundsForEverything.getWidth() + borderDistance * 4, stringBoundsForEverything.getHeight() + borderDistance * 2);

g.setStroke(new BasicStroke(3f));

g.draw(borderRect);

// DRAW THIN TIGHT RECTANGLE BORDER

final Shape borderRectTight = new Rectangle2D.Double(stringBoundsForEverything.getX(), stringBoundsForEverything.getY(), stringBoundsForEverything.getWidth(), stringBoundsForEverything.getHeight());

g.setStroke(new BasicStroke(1f));

g.setColor(Color.GRAY);

g.draw(borderRectTight);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值