在java中获取字符串大小(没有可用的Graphics对象)

我正在尝试编写需要使用Java中的Graphics2D类绘制许多字符串的应用程序。 我需要获取每个String对象的大小(以计算每个字符串的确切位置)。 在调用paint()方法之前应该完成很多字符串,在程序开始时只执行一次(所以我还没有Graphics2D对象)。 我知道有一个方法Font.getStringBounds()但它需要一个FontRenderContext对象作为参数。

当我试图创建自己的对象时:

FontRenderContext frc = new FontRenderContext(MyFont.getTransform(), true, true) 

然后获取字符串边界我总是得到不同的大小比我在paint()方法中使用Graphics2D.getFontRenderContext()方法获取FontRenderContext时的大小。 差异不大(约1E-3),但我想知道为什么会有什么不同?

但是,有没有更好更安全的方法来获取字符串的大小?

Thnx提前提供任何帮助!

尝试使用FontMetrics类; stringWidth方法返回字符串的大小。 一个例子:

 JComponent c = getSomeKindOfJComponent(); FontMetrics fm = c.getFontMetrics(c.getFont()); // or another font int strw = fm.stringWidth("My text"); 

您可能还想查看SwingUtilities.computeStringWidth

内华达州啊。 坤呐。 发生。

原因是您从FRC寻找的渲染和计算特定于Graphics上下文,即特定的Graphics2D对象。 你感兴趣的是你在运行时交给的人 – 就像没有其他人一样(你必须假设)。

您可以使用来自其他 Graphics2D的FRC尽可能多地计算,但是当您尝试在运行时使用Graphics2D paintComponent时,您的计算全部都是徒劳的,这是您将要使用的Graphics2D,没有有什么关系。

所以,是的,这将是不错的,但它完全是理论上的。 所有这些不错的信息都被有效地锁定在FRC中,因为如果没有确切的Graphics2D,实际上将会吸引AttributedString,那就是FRC比无用更糟糕 – 这可能是你实际上想要拥抱的错觉。

这是有道理的,因为一切都真的依赖于你在运行时交给的Graphics2D。 因此,最好的办法就是接受它并编写代码,从paintComponent中调出任何对象以及你必须做的任何专业计算,并围绕事实的方式构建你的设计。

我是一个很好的问题,也是一件好事,希望你能做到,只是,你做不到。 您可以在其他论坛中看到其他人在网络上的其他地方要求这样做。 注意缺乏有用的答案和/或震耳欲聋的沉默。

这是一段代码,它做了类似的事情 – 编写它来将字符串缩写为给定数量的像素。

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

除了使用FontMetrics之外,还可以使用JLabel来确定未格式化和(基本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 = "" + "

Do UC Me?

" + "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(); } }

编辑1:关于你的“许多字符串”评论。 将字符串绘制为BufferedImage,仅在需要时重新生成。 每次调用paintComponent()时都使用BufferedImage。

从历史的角度来看,这就是我认为他最初是这样做的(jruby java pseucodoe)

 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 
Interesting Posts