如何从 JAVA 中的 FontMetrics 获取正确的字符串宽度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19582502/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get the correct String width from FontMetrics in JAVA
提问by Jakob Mathiasen
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.
我使用对象stringWidth("str")
上的方法计算字符串的宽度FontMetrics
。这个方法只给我基线上从起点到终点的宽度。不是字符串的总宽度。
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");
回答by Geosearchef
you need a graphics object.
你需要一个图形对象。
graphics.setFont(font);
graphics.setFont(font);
int lenghtgraphics.getFontMetrics(graphics.getFont()).stringWidth(value);
int lenghtgraphics.getFontMetrics(graphics.getFont()).stringWidth(value);
回答by Stinger
I built an xml rendering component a few years back and rely very heavily on
几年前我构建了一个 xml 渲染组件并且非常依赖
SwingUtilities.computeStringWidth(fontMetrics, string);
SwingUtilities.computeStringWidth(fontMetrics, string);
I get the font metrics from the component that I'm measuring the string for.
我从我测量字符串的组件中获取字体度量。
myComponent.getFontMetrics(myComponent.getFont());
myComponent.getFontMetrics(myComponent.getFont());
回答by Dreamspace President
FontMetrics also has getStringBounds(), not just stringWidth().
FontMetrics 也有 getStringBounds(),而不仅仅是 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()!
您应该问问自己需要文本宽度的用途。如果是通过例如paintComponent() 覆盖输出,那么您应该测量那里的文本尺寸,以确保考虑所有因素(例如分数度量、抗锯齿)。此外,您不必考虑处理图形上下文 - 在您的示例中,您绝对必须这样做,它需要 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.
以下示例用于paintComponent() 覆盖,例如,对于您用作ContentPane 的JPanel,在组件中心以您提供的字体绘制文本,并在其周围绘制一个矩形,并保持一定距离,文本完全位于其中心。
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
此不精确解决方案的屏幕截图:http: //i.imgur.com/vetRjCK.png
Screenshot of precise solution further down: http://i.imgur.com/0A0EdCf.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);
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 dimensionsby converting the text into a Shape first.
下面的解决方案在结构上与上面的一样,但它不是使用 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);