如何在Java中获得真正的字符串高度?

我正在使用FontMetrics.getHeight()来获取字符串的高度,但它给了我一个错误的值,切断了字符串字符的下降。 我可以使用更好的function吗?

下面的getStringBounds()方法基于当前Graphics2D字体的GlyphVector ,它适用于一行文本字符串:

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

请注意,为了清楚起见,我省略了导入。

结果:

结果截图。

是什么让你认为它返回错误的价值? 你对它返回的东西的期望与规格不符的可能性要大得多。 请注意,如果Font中的某些字形超过或低于这些值,则完全没问题。

getMaxDescent()getMaxAscent()应该告诉你Font中任何字形的那些字段的绝对最大值。

如果您想知道特定String的指标,那么您肯定想要调用getLineMetrics()

FontMetrics.getAscent()和FontMetrics.getDescent()可能会成功。

我最近编写了下面的代码,因为我需要对字体的特定范围进行像素完美高度测量(例如:所有较低字符或所有数字)。

如果你需要更快的代码(我的代码是循环),我建议在启动时运行一次以获取数组中的所有值(例如从1到100),然后使用数组。

代码基本上从输入字符串中的所有字符绘制在250×250位图重叠的相同位置(如果需要增加或减少),它开始从顶部查找像素,然后从底部查找像素,然后返回找到的最大高度。 它适用于普通字符串,即使它是为字符范围设计的。 这意味着在评估常规字符串时会出现一种冗余,因为某些字符会重复出现。 因此,如果您的输入字符串超过字母数(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; } 

getHeight()不能切断字符串的下延,只绘制字符串就可以做到。 您正在使用getHeight返回的高度以某种方式绘制字符串,并且可能是您滥用高度。 例如,如果将字符串的起点定位在getHeight()高的框的底部,则文本的基线将位于框的底部边缘,并且很可能会剪切下伸部分。

文本几何是一个复杂的主题,注入了奇异的历史文物。 正如其他人所建议的那样,使用getAscentgetDescent尝试在您的框中正确定位基线。