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

在java中获取字符串大小(没有可用的图形对象),java,string,bounds,graphics2d,Java,String,Bounds,Graphics2d,我正在尝试编写一个应用程序,它需要使用Java中的Graphics2D类来绘制许多字符串。我需要得到每个字符串对象的大小(以计算每个字符串的确切位置)。 有太多的字符串,在调用paint()方法之前应该执行一次,并且只在程序开始时执行一次(因此我还没有Graphics2D对象)。我知道有一个方法Font.getStringBounds(),但它需要一个FontRenderContext对象作为参数 当我尝试创建自己的对象时: FontRenderContext frc = new FontRen

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

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

FontRenderContext frc = new FontRenderContext(MyFont.getTransform(), true, true)
然后获取字符串边界,我总是使用
Graphics2D.getFontRenderContext()
内的
paint()
方法获取
FontRenderContext
时得到的大小不同。差异不大(大约1E-3),但我想知道为什么会有任何差异

然而,有没有更好更安全的方法来获取字符串的大小

Thnx可提前获得任何帮助

与全班同学一起尝试;该方法返回字符串的大小。 例如:

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

下面是一段代码,它做了类似的事情——编写它是为了将字符串缩写为给定的像素数

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();
  }
}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.GradientPaint;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.image.buffereImage;
导入javax.swing.JOptionPane;
导入javax.swing.JLabel;
导入javax.swing.ImageIcon;
/**从Oracle论坛上的线程获得的示例代码,我无法
在这一刻找到。我的问题与一次意外的渲染有关
杰拉贝尔。由Darryl Burke提供的“添加此”行解决了此问题*/
公共类LabelRenderTest{
String title=“”
+“你喜欢我吗?”
+“这是一条可以缠绕的长字符串。”
+“我们想要的效果是多行标签。”;
LabelRenderTest(){
BuffereImage=新的BuffereImage(
640,
480,
BuffereImage.TYPE_INT_RGB);
Graphics2D imageGraphics=image.createGraphics();
GradientPaint gp=新的GradientPaint(
20f,20f,蓝色,
620f,460f,彩色。白色);
图像图形.setPaint(gp);
imageGraphics.fillRect(0,0,800600);
JLabel textLabel=新的JLabel(标题);

textLabel.setSize(textLabel.getPreferredSize());//您可能还想查看
SwingUtilities.computeStringWidth

出于历史原因,我认为他最初是这样做的(jruby java pseucodoe)


不,啊,刚娜,发生了

原因是您从FRC中寻找的渲染和计算是特定于图形上下文的,即特定的Graphics2D对象。您感兴趣的对象是运行时交给您的对象-它与其他对象不同(您必须假设)

您可以使用其他一些Graphics2D中的FRC计算任意多的值,但是当您尝试在运行时将计算结果与Graphics2D paintComponent一起使用时,无论发生什么情况,您的计算结果都是徒劳的,这就是您将要使用的Graphics2D

所以,是的,这很好,但它完全是理论上的。所有这些好的信息都被有效地锁定在FRC中,因为如果没有确切的图形2d,属性字符串实际上将被绘制,FRC比无用还要糟糕——这是一个你可能会尝试接受的幻觉

这是有道理的,因为一切实际上都取决于运行时得到的图形2D。因此,最好的做法是接受它并编写代码,从paintComponent内部调用任何对象和任何需要进行的专门计算,并围绕这一事实构建设计


<>我是一个很好的问题,也是一件好事,希望你能做,你不能。你看到其他人在网络上的其他地方,在其他论坛上询问这个问题。注意缺少有用的答案和/或震耳欲聋的沉默。

String String不返回有效的字符串大小,因为它不考虑反走样和其他特征。(如字符之间的间距)。此方法并非在所有情况下都有效。如果“JComponent c”您得到的尚未初始化/验证,其字体和fontMetrics将与以后的不一样,并且您的字体度量将关闭。它不会总是这样,但像高DPI模式之类的东西可能会触发这种情况。这不是我需要的-我想在没有Graphics2D对象的情况下获得精确的字符串边界。@coder89嗯..Graph的属性ics2D实例在应用程序的整个生命周期中可能会有所不同。正如您所指出的,需要考虑“抗锯齿和其他功能”,如果没有Graphics2D的特定实例,这是不可能的。它将宽度作为整数返回-我需要更精确的东西
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