我正在尝试编写需要使用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 method返回字符串的大小。
一个例子:
JComponent c = getSomeKindOfJComponent();
FontMetrics fm = c.getFontMetrics(c.getFont()); // or another font
int strw = fm.stringWidth("My text");
试试吧 FontMetrics对象 类;该 stringWidth method返回字符串的大小。
一个例子:
JComponent c = getSomeKindOfJComponent();
FontMetrics fm = c.getFontMetrics(c.getFont()); // or another font
int strw = fm.stringWidth("My text");
您可能还想看看 SwingUtilities.computeStringWidth
。
内华达州啊。坤呐。发生。
原因是您正在寻找FRC的渲染和计算特定于Graphics上下文,即特定的Graphics2D对象。你感兴趣的是你在运行时交给的人 - 就像没有其他人一样(你必须假设)。
你可以使用一些FRC来计算你想要的数量 其他 Graphics2D,但是当你尝试在运行时使用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 = "<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();
}
}
编辑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