开发者

Really slow obtaining font metrics

So the problem I have is that I start my application by displaying a simple menu. To size and align the text correctly I need to obtain font metrics and I cannot find a way to do it quickly. I tested my program and it looks like whatever method I use to obtain font metrics the first call takes over 500 milliseconds!? Because of it the time it takes to start-up my application is much longer than necessary.

I don't know if it is platform specific or not, but just in case, I'm using Mac OS 10.6.2 on MacBook Pro (hardware isn't an issue here).

If you know a way of obtaining font metrics quicker please help.

I tried these 3 methods for obtaining the font metrics and the first call is always very slow, no matter which method I choose.

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


While I can't tell you how to get around the issue itself, you can use this method to decide exactly when to init it:

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

This is useful because you can put it anywhere - so, for example, you could do it while you display a loading screen or something. If you use a Graphics object during paint(), then you're restricted to only initializing while rendering.

EDIT:

In fact, this can be reduced to:

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

(The slow part is the getFont2D call, not the Font constructor.)

EDIT 2:

And, finally, this can be reduced to:

sun.font.FontManagerFactory.getInstance();

The issue is that this singleton class needs a long time to start up, as it enumerates all of the system fonts.

EDIT 3:

There is no good way around this issue if you want to use the standard Graphics system.


No real clue as for why it's so slow, but for method 3, shouldn't you be calling 'setFont' first?

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

It doesn't make a difference speed-wise, though :-(

Also, it's a bit uneconomic to create a new Font each time paint() is called (which happens a lot), you could move that to your constructor. But that cannot be the problem here, as you start measuring the time only after the Font has been created.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜