在 java 中获取字符串大小(没有可用的 Graphics 对象)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4914145/
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
Getting string size in java (without having a Graphics object available)
提问by Lukasz Spas
I'm trying to write application which need to draw many strings using Graphics2D
class in Java. I need to get sizes of each String object (to calculate exact position of each string).
There are so many strings that it should be done before the paint()
method is called and only once at the beginning of my program (so then I don't have Graphics2D
object yet). I know that there is a method Font.getStringBounds()
but it needs a FontRenderContext
object as a parameter.
我正在尝试编写需要使用Graphics2D
Java 类绘制许多字符串的应用程序。我需要获取每个 String 对象的大小(以计算每个字符串的确切位置)。有太多的字符串应该在paint()
调用方法之前完成,并且只在我的程序开始时完成一次(所以我还没有Graphics2D
对象)。我知道有一个方法,Font.getStringBounds()
但它需要一个FontRenderContext
对象作为参数。
When i tried to create my own object:
当我尝试创建自己的对象时:
FontRenderContext frc = new FontRenderContext(MyFont.getTransform(), true, true)
and then obtain the strings bounds I've always get different sizes than when I obtain FontRenderContext
using Graphics2D.getFontRenderContext()
method inside paint()
. The differences are not big (about 1E-3) but I wonder why there is any difference at all?
然后获取字符串边界我总是得到与FontRenderContext
使用Graphics2D.getFontRenderContext()
里面的方法获取时不同的大小paint()
。差异不大(大约 1E-3),但我想知道为什么会有任何差异?
However, is there any better and secure way to obtain sizes of a string?
但是,有没有更好更安全的方法来获取字符串的大小?
Thnx for any help in advance!
感谢您的帮助!
回答by Alberto
Try with the FontMetricsclass; the stringWidthmethod returns the size of a string. An example:
尝试使用FontMetrics类;该stringWidth方法返回一个字符串的大小。一个例子:
JComponent c = getSomeKindOfJComponent();
FontMetrics fm = c.getFontMetrics(c.getFont()); // or another font
int strw = fm.stringWidth("My text");
回答by Jochen Bedersdorfer
You might also want to check out SwingUtilities.computeStringWidth
.
您可能还想查看SwingUtilities.computeStringWidth
.
回答by Swing God
Nev-ah. Gon-na. Happen.
涅瓦-啊。呐呐 发生。
The reason is the rendering and computation you're looking for from FRC is specific to a Graphics context, i.e. a specific Graphics2D object. The one you're interested in is one you're handed at runtime- it's like no other (you have to assume).
原因是您从 FRC 寻找的渲染和计算特定于 Graphics 上下文,即特定的 Graphics2D 对象。您感兴趣的那个是您在运行时处理的那个——它与众不同(您必须假设)。
You can compute as much as you want using an FRC from some otherGraphics2D, but your computations all all for naught when you try to use them at runtime with the Graphics2D paintComponent is handed, which is the Graphics2D you're going to use, no matter what.
您可以使用来自其他一些Graphics2D的 FRC 进行尽可能多的计算,但是当您尝试在运行时使用 Graphics2D 绘制组件(即您将要使用的 Graphics2D)在运行时使用它们时,您的计算全都白费了有什么关系。
So, yes, this would be nice but it's entirely theoretical. All that nice information is effectively locked away inside that FRC because without the exact Graphics2D the AttributedString is actually going to be drawn to, that FRC is worse than useless- it's an illusion you might actually try to embrace.
所以,是的,这很好,但它完全是理论上的。所有这些好的信息都被有效地锁定在 FRC 中,因为如果没有确切的 Graphics2D,AttributedString 实际上将被吸引到,那么 FRC 比无用更糟糕 - 这是您可能实际上试图接受的错觉。
It makes sense, since everything really IS dependent on the Graphics2D you get handed at runtime. So the best thing to do is just accept it and write your code to call out from within paintComponent out to whatever objects and whatever specialized computation you have to do and build your design around the fact that THIS is the way things are.
这是有道理的,因为一切都真正依赖于您在运行时获得的 Graphics2D。因此,最好的办法就是接受它并编写您的代码以从paintComponent 内部调用您必须执行的任何对象和任何专门计算,并围绕事情就是这样的事实来构建您的设计。
I's a good question and a good thing to wish you could do, just, you can't. You see other people asking for this elsewhere on the web, in other forums. Notice the lack of useful answers and / or deafening silence.
我是一个很好的问题,也是一件好事,希望你能做到,只是,你不能。你会看到其他人在网络的其他地方、其他论坛上提出这个要求。请注意缺乏有用的答案和/或震耳欲聋的沉默。
回答by Andrew Thompson
Besides using FontMetrics
, a JLabel
can be used to determine the size of both unformatted and (basic HTML) rendered text. Here is an example.
除了使用 之外FontMetrics
,aJLabel
还可用于确定未格式化和(基本 HTML)呈现的文本的大小。这是一个例子。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JOptionPane;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
/** Sample code obtained from a thread on the Oracle forums that I cannot
locate at this instant. My question was related to an unexpected rendering of
JLabel. It was resolved by the 'added this' line courtesy of Darryl Burke. */
public class LabelRenderTest {
String title = "<html><body style='width: 160px; padding: 8px'>"
+ "<h1>Do U C Me?</h1>"
+ "Here is a long string that will wrap. "
+ "The effect we want is a multi-line label.";
LabelRenderTest() {
BufferedImage image = new BufferedImage(
640,
480,
BufferedImage.TYPE_INT_RGB);
Graphics2D imageGraphics = image.createGraphics();
GradientPaint gp = new GradientPaint(
20f, 20f, Color.blue,
620f, 460f, Color.white);
imageGraphics.setPaint(gp);
imageGraphics.fillRect(0, 0, 800, 600);
JLabel textLabel = new JLabel(title);
textLabel.setSize(textLabel.getPreferredSize()); // <==== added this
Dimension d = textLabel.getPreferredSize();
BufferedImage bi = new BufferedImage(
d.width,
d.height,
BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.setColor(new Color(255, 255, 255, 128));
g.fillRoundRect(
0,
0,
bi.getWidth(null),
bi.getHeight(null),
15,
10);
g.setColor(Color.black);
textLabel.paint(g);
Graphics g2 = image.getGraphics();
g2.drawImage(bi, 20, 20, null);
ImageIcon ii = new ImageIcon(image);
JLabel imageLabel = new JLabel(ii);
JOptionPane.showMessageDialog(null, imageLabel);
}
public static void main(String[] args) {
LabelRenderTest ist = new LabelRenderTest();
}
}
Edit 1:
As to your "many strings" comment. Paint the strings to a BufferedImage
that is only regenerated if needed. Use the buffered image each time paintComponent()
is called.
编辑 1:至于您的“许多字符串”评论。将字符串绘制BufferedImage
为仅在需要时重新生成的字符串。每次paintComponent()
调用时都使用缓冲图像。
回答by rogerdpack
for historical sake,here's how I think he did it originally (jruby java pseucodoe)
为了历史,这是我认为他最初是如何做的(jruby java pseudoe)
font = UIManager.getFont("Label.font")
frc = java.awt.font.FontRenderContext.new(font.transform, true, true)
textLayout = java.awt.font.TextLayout.new(text, font, frc)
textLayout.bounds.width
回答by 01es
Here is a snippet of code that does something similar -- wrote it for abbreviating the string to a given number of pixels.
这是一段执行类似操作的代码片段 - 编写它是为了将字符串缩写为给定数量的像素。
public static String abbreviate(final Graphics2D g2, final String text, final int fitToWidth) {
// define how many characters in the caption can be drawn
final FontMetrics fm = g2.getFontMetrics();
Rectangle2D textBounds = fm.getStringBounds(text, g2);
int count = text.length();
while ((textBounds.getWidth() > fitToWidth) && (count > 4)) {
textBounds = fm.getStringBounds(text.substring(0, count--), g2);
}
return count == text.length() ? text : StringUtils.abbreviate(text, count);
}