获取字体度量信息非常缓慢

4
所遇到的问题是,我通过显示简单菜单来启动我的应用程序。为了正确地调整文本的大小和对齐方式,我需要获取字体度量信息,但我找不到快速完成此操作的方法。我测试了我的程序,无论使用哪种方法获取字体度量信息,第一次调用都需要超过500毫秒!因此,启动我的应用程序所需的时间比必要的时间长得多。
我不知道这是否与平台有关,但以防万一,我正在使用Mac OS 10.6.2在MacBook Pro上(硬件不是问题)。
如果您知道更快获取字体度量信息的方法,请帮助解决。
我尝试了这3种获取字体度量信息的方法,无论选择哪种方法,第一次调用总是非常缓慢。
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;

import javax.swing.JFrame;

public class FontMetricsTest extends JFrame {
 public FontMetricsTest() {
  setVisible(true);
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 }

 @Override
 public void paint(Graphics g) {
  Graphics2D g2 = (Graphics2D) g;

  Font font = new Font("Dialog", Font.BOLD, 10);
  long start = System.currentTimeMillis();

  FontMetrics fontMetrics = g2.getFontMetrics(font);
//  LineMetrics fontMetrics1 =
//     font.getLineMetrics("X", new FontRenderContext(null, false, false));
//  FontMetrics fontMetrics2 = g.getFontMetrics();

  long end = System.currentTimeMillis();
  System.out.println(end - start);
  g2.setFont(font);
 }

 public static void main(String[] args) {
  new FontMetricsTest();
 }
}

第一次运行程序需要0.6秒,之后的运行时间大约为20毫秒(WinXP,JDK 1.6.0_18)。所以可能与字体文件在磁盘缓存中有关。 - Ha.
可能与连接字体服务器有关的问题?(我听说过一个小程序导致运行字体服务器的机器崩溃(两台 Solaris 机器),但那是十年前的事了。)我添加了缓存来清除问题,尽管我猜如果图形对象可能应用了变换,那么这可能不会很好地工作。 - Tom Hawtin - tackline
1
哦,还有一个Font的缓存。你可以在API文档中看到它们有一个finalize但没有dispose... - Tom Hawtin - tackline
2个回答

3

虽然我无法告诉您如何解决这个问题,但您可以使用此方法来确定何时初始化它:

new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY).createGraphics().getFontMetrics();

这是非常有用的,因为你可以将它放置在任何地方 - 例如,在显示加载屏幕时可以使用。如果你在paint()期间使用Graphics对象,则仅限于在渲染时初始化。

编辑:

实际上,这可以简化为:

FontUtilities.getFont2D(new Font("Dialog", 0, 12));

慢的部分是getFont2D的调用,而不是Font构造函数。

编辑2:

最后,这可以简化为:

sun.font.FontManagerFactory.getInstance();

这个单例类的问题在于需要很长时间才能启动,因为它枚举了所有系统字体。
编辑3:
如果你想使用标准的Graphics系统,那么没有好的解决方法来避免这个问题。

这对我有效,但我必须使用getFont2D:在我的特定字体上,我测试了90毫秒的FontManagerFactory.getInstance,然后仍然需要2700毫秒的getFont2D(该字体在系统中缺失)。 - lapo

1

不太清楚为什么速度这么慢,但对于第三种方法,你应该先调用“setFont”吧?

public void paint(Graphics g) {
    g.setFont(font);
    FontMetrics fm = g.getFontMetrics();
}

尽管如此,速度方面并没有什么区别 :-(

此外,在每次调用paint()时(这经常发生),创建新的Font有点不经济,您可以将其移动到构造函数中。但这在这里不能是问题,因为您只在创建字体后才开始计时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接