我正在使用FontMetrics.getHeight()
来获取字符串的高度,但是它给了我一个错误的值,切断了字符串字符的下降。我可以使用更好的功能吗?
答案 0 :(得分:19)
以下getStringBounds()
方法基于当前GlyphVector
字体的Graphics2D
,该字体适用于一行文字字符串:
public class StringBoundsPanel extends JPanel
{
public StringBoundsPanel()
{
setBackground(Color.white);
setPreferredSize(new Dimension(400, 247));
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// must be called before getStringBounds()
g2.setFont(getDesiredFont());
String str = "My Text";
float x = 140, y = 128;
Rectangle bounds = getStringBounds(g2, str, x, y);
g2.setColor(Color.red);
g2.drawString(str, x, y);
g2.setColor(Color.blue);
g2.draw(bounds);
g2.dispose();
}
private Rectangle getStringBounds(Graphics2D g2, String str,
float x, float y)
{
FontRenderContext frc = g2.getFontRenderContext();
GlyphVector gv = g2.getFont().createGlyphVector(frc, str);
return gv.getPixelBounds(null, x, y);
}
private Font getDesiredFont()
{
return new Font(Font.SANS_SERIF, Font.BOLD, 28);
}
private void startUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) throws Exception
{
final StringBoundsPanel tb = new StringBoundsPanel();
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
tb.startUI();
}
});
}
}
请注意,为清晰起见,我省略了导入。
结果:
答案 1 :(得分:12)
是什么让你认为它返回了错误的值?你对它返回的预期与规范不符的可能性要大得多。请注意,如果Font中的某些字形超过或低于这些值,则完全没问题。
getMaxDescent()
和getMaxAscent()
应该告诉您字体中任何字形的那些字段的绝对最大值。
如果您想知道特定字符串的指标,那么您肯定想要致电getLineMetrics()
。
答案 2 :(得分:7)
答案 3 :(得分:3)
我最近编写了下面的代码,因为我需要对字体的特定范围进行像素完美高度测量(例如:所有较低字符或所有数字)。
如果你需要更快的代码(我的代码是循环),我建议在启动时运行一次以获取数组中的所有值(例如1到100),然后使用数组。
代码基本上从输入字符串中的所有字符绘制在250x250位图重叠的相同位置(如果需要增加或减少),它开始从顶部查找像素,然后从底部查找像素,然后返回找到的最大高度。它适用于普通字符串,即使它是为字符范围设计的。这意味着在评估常规字符串时存在一种冗余,因为某些字符会重复出现。因此,如果您的输入字符串超过字母数(26),请使用'tRange'inmput:“abcd ... z”和其他可能使用的字符。它更快。
希望有所帮助。
public int getFontPixelHeight(float inSize, Paint sourcePaint, String tRange)
{
// It is assumed that the font is already set in the sourcePaint
int bW = 250, bH = 250; // bitmap's width and height
int firstContact = -1, lastContact = -2; // Used when scanning the pixel rows. Initial values are set so that if no pixels found, the returned result is zero.
int tX = (int)(bW - inSize)/2, tY = (int)(bH - inSize)/2; // Used for a rough centering of the displayed characters
int tSum = 0;
// Preserve the original paint attributes
float oldSize = sourcePaint.getTextSize();
int oldColor = sourcePaint.getColor();
// Set the size/color
sourcePaint.setTextSize(inSize); sourcePaint.setColor(Color.WHITE);
// Create the temporary bitmap/canvas
Bitmap.Config bConf = Bitmap.Config.ARGB_8888;
Bitmap hld = Bitmap.createBitmap(250, 250, bConf);
Canvas canv = new Canvas(hld);
for (int i = 0; i < bH; i++)
{
for (int j = 0; j < bW; j++)
{
hld.setPixel(j, i, 0); // Zero all pixel values. This might seem redundant, but I am not quite sure that creating a blank bitmap means the pixel color value is indeed zero, and I need them to be zero so the addition performed below is correct.
}
}
// Display all characters overlapping at the same position
for (int i = 0; i < tRange.length(); i++)
{
canv.drawText("" + tRange.charAt(i), tX, tY, sourcePaint);
}
for (int i = 0; i < bH; i++)
{
for (int j = 0; j < bW; j++)
{
tSum = tSum + hld.getPixel(j, i);
}
if (tSum > 0) // If we found at least a pixel, save row index and exit loop
{
firstContact = i;
tSum = 0; // Reset
break;
}
}
for (int i = bH - 1; i > 0 ; i--)
{
for (int j = 0; j < bW; j++)
{
tSum = tSum + hld.getPixel(j, i);
}
if (tSum > 0) // If we found at least a pixel, save row index and exit loop
{
lastContact = i;
break;
}
}
// Restore the initial attributes, just in case the paint was passed byRef somehow
sourcePaint.setTextSize(oldSize);
sourcePaint.setColor(oldColor);
return lastContact - firstContact + 1;
}
答案 4 :(得分:2)
getHeight()
无法切断字符串的下延,只能绘制字符串就可以做到。您正在使用从getHeight
返回的高度以某种方式绘制字符串,并且您可能误用了高度。例如,如果将字符串的起点定位在getHeight()为高的框的底部,则文本的基线将位于框的下边缘,并且很可能会剪切下延器。
文本几何是一个复杂的主题,注入了奇异的历史文物。正如其他人所建议的那样,使用getAscent
和getDescent
尝试将基线正确放置在您的框内。