计算Java中字符串的显示宽度


91

如何在Java中计算字符串的长度(以像素为单位)?

最好不使用Swing。

编辑:我想使用Java2D中的drawString()绘制字符串,并使用长度进行自动换行。


4
没有摇摆?您正在使用什么设备?什么字体 什么尺寸?什么风格 所有这些都会改变显示宽度。
S.Lott,

3
你打算如何画线?用AWT?还是使用其他工具包?字符串的大小(以像素为单位)取决于稍后将在其上绘制像素的绘图API(当然还包括您使用的字体,字体大小以及字体是否为粗体/斜体等)。不知道绘图API和字体属性,字符串没有大小。
麦基

1
@S。洛特 您将它合而为一。我很想以无疑问的方式结束这个问题。
David Arno,

1
@David Arno:我是n00bz上的傻瓜。我将添加[beginner]标签。
S.Lott,

对于.NET相当于有TextRenderer类,见stackoverflow.com/questions/604298/...
Spoike

Answers:


137

如果只想使用AWT,则使用Graphics.getFontMetrics(可选地指定字体,对于非默认字体)获取a FontMetrics,然后FontMetrics.stringWidth查找指定字符串的宽度。

例如,如果您有一个Graphics名为的变量g,则可以使用:

int width = g.getFontMetrics().stringWidth(text);

对于其他工具箱,您需要向我们提供更多信息-它始终取决于工具箱。


8
如果您提供了一个示例用法,可能会更清楚一些,起初,我尝试将其用作静态方法,因为您是用这种方式编写的。
Aequitas 2015年

不推荐使用!但仍然是最好的方法!,为什么在没有更好的方法的情况下为什么不赞成使用该方法呢!!!我就是不明白!
伊曼

2
@Zich:我不确定您说的是哪种方法已被弃用-据我所知,在Java 8文档中,这两种方法均未标记为已弃用...
Jon Skeet

2
@Zich:这是的方法Graphics,不是FontMetrics。但是您正在调用Toolkit.getFontMetrics,它的确已被弃用,而这并不是此方法所要讨论的……您需要特别注意这种事情,尤其是在开始谈论报告错误之前……
Jon Skeet

1
@Zich:好吧,我不会猜到-我会使用不推荐使用的方法,或者Toolkit.getFontMetrics建议使用不推荐使用的方法。
乔恩·斯基特

55

它并不总是需要依赖于工具箱,也不需要总是使用FontMetrics方法,因为它需要首先获取Web容器或无头环境中缺少的图形对象。

我已经在Web Servlet中对此进行了测试,它确实可以计算文本宽度。

import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;

...

String text = "Hello World";
AffineTransform affinetransform = new AffineTransform();     
FontRenderContext frc = new FontRenderContext(affinetransform,true,true);     
Font font = new Font("Tahoma", Font.PLAIN, 12);
int textwidth = (int)(font.getStringBounds(text, frc).getWidth());
int textheight = (int)(font.getStringBounds(text, frc).getHeight());

将必要的值添加到这些尺寸以创建任何所需的边距。


1
我不认为以这种方式创建affineTransform和fontRenderContext会导致良好的行为。我猜font.getTransfrom()会更合逻辑。
Lyth 2013年

1
您的示例仍在使用AWT功能。以SWT字体为例,它将无法正常工作,这就是为什么“它将始终依赖于工具包”的原因
serg.nechaev 2013年

1
@Olofu标记-getStringBounds仅给出逻辑界限。为了使它更好,应该使用getBounds()和LineMetrics对象来检索实际的高度,包括ascent + descent。
琼斯

8

在以下类中使用getWidth方法:

import java.awt.*;
import java.awt.geom.*;
import java.awt.font.*;

class StringMetrics {

  Font font;
  FontRenderContext context;

  public StringMetrics(Graphics2D g2) {

    font = g2.getFont();
    context = g2.getFontRenderContext();
  }

  Rectangle2D getBounds(String message) {

    return font.getStringBounds(message, context);
  }

  double getWidth(String message) {

    Rectangle2D bounds = getBounds(message);
    return bounds.getWidth();
  }

  double getHeight(String message) {

    Rectangle2D bounds = getBounds(message);
    return bounds.getHeight();
  }

}

1

现在换个完全不同的东西。下面假定字体为arial,并根据字符与宽度的线性插值进行大胆猜测。

// Returns the size in PICA of the string, given space is 200 and 'W' is 1000.
// see https://p2p.wrox.com/access/32197-calculate-character-widths.html

static int picaSize(String s)
{
    // the following characters are sorted by width in Arial font
    String lookup = " .:,;'^`!|jl/\\i-()JfIt[]?{}sr*a\"ce_gFzLxkP+0123456789<=>~qvy$SbduEphonTBCXY#VRKZN%GUAHD@OQ&wmMW";
    int result = 0;
    for (int i = 0; i < s.length(); ++i)
    {
        int c = lookup.indexOf(s.charAt(i));
        result += (c < 0 ? 60 : c) * 7 + 200;
    }
    return result;
}

有趣,但也许不是很实用。


1

我个人一直在寻找可以让我计算多行字符串区域的东西,因此我可以确定给定区域是否足够大以打印字符串-并保留特定的字体。

private static Hashtable hash = new Hashtable();
private Font font;
private LineBreakMeasurer lineBreakMeasurer;
private int start, end;

public PixelLengthCheck(Font font) {
    this.font = font;
}

public boolean tryIfStringFits(String textToMeasure, Dimension areaToFit) {
    AttributedString attributedString = new AttributedString(textToMeasure, hash);
    attributedString.addAttribute(TextAttribute.FONT, font);
    AttributedCharacterIterator attributedCharacterIterator =
            attributedString.getIterator();
    start = attributedCharacterIterator.getBeginIndex();
    end = attributedCharacterIterator.getEndIndex();

    lineBreakMeasurer = new LineBreakMeasurer(attributedCharacterIterator,
            new FontRenderContext(null, false, false));

    float width = (float) areaToFit.width;
    float height = 0;
    lineBreakMeasurer.setPosition(start);

    while (lineBreakMeasurer.getPosition() < end) {
        TextLayout textLayout = lineBreakMeasurer.nextLayout(width);
        height += textLayout.getAscent();
        height += textLayout.getDescent() + textLayout.getLeading();
    }

    boolean res = height <= areaToFit.getHeight();

    return res;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.