【问题标题】:Java font size from widthJava字体大小从宽度
【发布时间】:2013-01-01 01:09:46
【问题描述】:

我正在寻找一种从宽度推断 Java AWT 字体大小的方法。例如,我知道我想在 100 像素内写“hello world”。我知道我正在使用字体“Times”,样式为Font.PLAIN,并且我想获得最适合我给定宽度的 100 像素的字体大小。

我知道我可以循环计算它(类似于while(font.getSize() < panel.getWidth()),但说实话我觉得它不是很优雅。

【问题讨论】:

  • 什么是“最适合面板宽度的字体大小”?
  • 理想的大小取决于你要写的文字,除非你有一个固定宽度的字体。
  • 是的,对不起,我忘了提到我也知道我想使用的字符串!我编辑我的帖子...
  • "..我觉得它不是很优雅。" 有时使用有效的东西是值得的,不管优雅。话虽如此,您可以简单地使用AffineTransform 来缩小和拉伸文本,如this answer
  • 感谢您的评论。当我说“不是很优雅”时,我实际上的意思是“对于它来说太膨胀了”(因为我必须在每次迭代时创建一个新的 Font 对象......)但是是的,我会看看 AffineTransform 对象似乎可以满足我的需求:)

标签: java fonts awt


【解决方案1】:

您可以使用 FontMetrics 类获取字符串的渲染宽度和高度(确保在 Graphics2D 实例中启用小数字体度量以避免舍入错误):

Graphics2D g = ...;
g.setRenderingHint(
    RenderingHints.KEY_FRACTIONALMETRICS, 
    RenderingHints.VALUE_FRACTIONALMETRICS_ON);

Font font = Font.decode("Times New Roman");

String text = "Foo";

Rectangle2D r2d = g.getFontMetrics(font).getStringBounds(text, g);

现在,当您使用具有默认(或实际上任何)大小的字体获得文本宽度时,您可以缩放字体,以便文本适合指定宽度,例如100 像素:

font = font.deriveFont((float)(font.getSize2D() * 100/r2d.getWidth()));

同样,您可能必须限制字体大小,以免超出可用的面板高度。

为了改善渲染文本的外观,您还应该考虑为文本渲染启用抗锯齿和/或字体中的字距支持:

g.setRenderingHint(
    RenderingHints.KEY_TEXT_ANTIALIASING, 
    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

Map<TextAttribute, Object> atts = new HashMap<TextAttribute, Object>();
atts.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
font = font.deriveFont(atts);

【讨论】:

  • 感谢您的回复。实际上,我对这种方法进行了一些测试,我发现字体大小与文本宽度不是线性的!例如,给定一个字体和一个文本,如果字体大小为 1 对应于文本宽度为 10 像素,那么字体大小为 100 不一定会给出文本宽度为 1000 像素...
  • 您是对的,使用相对较小的字体(例如 12pt)来计算目标大小存在一些舍入误差。您可以通过在图形实例中启用“分数”字体度量来解决此问题。我已经更新了我的答案。
  • 谢谢,这回答了我的问题!
【解决方案2】:

看看我正在使用的这两种方法。它不像你说的那样优雅,但它确实有效。

private static int pickOptimalFontSize (Graphics2D g, String title, int width, int height) {
    Rectangle2D rect = null;

    int fontSize = 30; //initial value
    do {
        fontSize--;
        Font font = Font("Arial", Font.PLAIN, fontSize);
        rect = getStringBoundsRectangle2D(g, title, font);
    } while (rect.getWidth() >= width || rect.getHeight() >= height);

    return fontSize;
}

public static Rectangle2D getStringBoundsRectangle2D (Graphics g, String title, Font font) {
    g.setFont(font);
    FontMetrics fm = g.getFontMetrics();
    Rectangle2D rect = fm.getStringBounds(title, g);
    return rect;
}

【讨论】:

  • 是的,这就是我一开始想的那种方法。我将尝试看看 Adrew Thompson 在上层 cmets 中给出的 AffineTransform,如果我没有找到令人满意的使用方式,我会回到你的答案。还是谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-08-23
  • 1970-01-01
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多