【问题标题】:How to get the correct String width from FontMetrics in JAVA如何从 JAVA 中的 FontMetrics 获取正确的字符串宽度
【发布时间】:2013-11-04 03:19:28
【问题描述】:

我使用FontMetrics 对象上的stringWidth("str") 方法计算字符串的宽度。这种方法只给了我基线上从起点到终点的宽度。不是字符串的总宽度。

关于如何计算整体宽度的任何想法?

大多数文档都说我不能通过添加字符串中每个字符的宽度来依赖结果。 到目前为止,这是我的代码:

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");

【问题讨论】:

  • 祝你好运!我曾经在这方面浪费了 3 天时间,尝试了 14 种技术,并让它在大约 95% 的时间内发挥作用......从那以后我就尽量避开 Swing
  • @iluxa 嗯。谢谢:-).. 95% 对我来说没问题。你能告诉我,你做了什么吗?
  • 你在用宽度做什么?您可以尝试使用其他方法。例如 getStringBounds。您也可以尝试使用 GlyphVector 而不是绘制字符串(我假设您最终会这样做),这是一种 Shape 表示形式,并为您提供了许多其他选项。
  • 我个人建议尝试使用 GlyphVector。它可以做的很多事情是 FontMetrics 和 drawString 无法做到的:docs.oracle.com/javase/7/docs/api/java/awt/font/…
  • 老兄,我希望我记得...试试SwingUtilities.computeStringWidth()。试试这个技巧:stackoverflow.com/questions/258486/…。希望对你有用...

标签: java string


【解决方案1】:

FontMetrics 也有 getStringBounds(),而不仅仅是 stringWidth()。

你应该问问自己你需要什么文本宽度。如果是通过例如输出一个 paintComponent() 覆盖,那么您应该在那里测量文本尺寸,以确保考虑所有因素(例如分数度量、抗锯齿)。此外,您不必考虑处理图形上下文 - 在您的示例中,您肯定必须这样做,它需要 g.dispose()!

以下示例用于paintComponent() 覆盖,例如对于您用作 ContentPane 的 JPanel,以您给定的字体在组件的中心绘制文本,并在其周围绘制一个有一定距离的矩形,文本完全位于其中心。

但是,文本大小,尤其是垂直大小,不精确。更好的解决方案是进一步向下。

这个不精确的解决方案的屏幕截图:http://i.imgur.com/vetRjCK.png

更下方的精确解决方案截图: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);

以下解决方案在结构上与上述类似,但不是使用 FontMetrics 调用来松散地导出文本尺寸,它通过首先将文本转换为 Shape 来导出精确的文本尺寸

// 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);

【讨论】:

  • 感谢您对@Dreamspace 总裁的评论。但自从我一年多前提出这个问题以来,系统现在正在客户处运行。解决方案不是 100% 好,但我们可以接受它..
【解决方案2】:

你需要一个图形对象。

graphics.setFont(font);

int lenghtgraphics.getFontMetrics(graphics.getFont()).stringWidth(value);

【讨论】:

    【解决方案3】:

    几年前我构建了一个xml渲染组件,非常依赖

    SwingUtilities.computeStringWidth(fontMetrics, string);

    我从要为其测量字符串的组件中获取字体指标。

    myComponent.getFontMetrics(myComponent.getFont());

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 2021-12-10
      • 1970-01-01
      • 2013-05-12
      • 1970-01-01
      相关资源
      最近更新 更多