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

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

最好不要使用 Swing。

编辑: 我想在 Java2D 中使用 drastring()绘制字符串 并使用长度的文字包装。

159552 次浏览

If you just want to use AWT, then use Graphics.getFontMetrics (optionally specifying the font, for a non-default one) to get a FontMetrics and then FontMetrics.stringWidth to find the width for the specified string.

For example, if you have a Graphics variable called g, you'd use:

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

For other toolkits, you'll need to give us more information - it's always going to be toolkit-dependent.

It doesn't always need to be toolkit-dependent or one doesn't always need use the FontMetrics approach since it requires one to first obtain a graphics object which is absent in a web container or in a headless enviroment.

I have tested this in a web servlet and it does calculate the text width.

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

Add the necessary values to these dimensions to create any required margin.

Use the getWidth method in the following class:

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


}

I personally was searching for something to let me compute the multiline string area, so I could determine if given area is big enough to print the string - with preserving specific font.

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

And now for something completely different. The following assumes arial font, and makes a wild guess based on a linear interpolation of character vs width.

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

Interesting, but perhaps not very practical.