Очень медленное получение метрик шрифта

Итак, проблема в том, что я запускаю свое приложение, отображая простое меню. Для правильного размера и выравнивания текста мне нужно получить метрики шрифта, и я не могу найти способ сделать это быстро. Я протестировал свою программу, и похоже, что какой бы метод я ни использовал для получения метрик шрифта, первый вызов занимает более 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();
 }
}

person Artur    schedule 16.03.2010    source источник
comment
У меня есть 0,6 секунды для первого запуска программы и ~ 20 мс для следующих запусков (WinXP, JDK 1.6.0_18). Так может быть это связано с тем, что файл шрифтов находится в кеше диска?   -  person Ha.    schedule 16.03.2010
comment
Возможно, проблема связана с подключением к серверу шрифтов? (Я слышал об одном апплете, убивающем машину, на которой работает сервер шрифтов (обе машины Solaris), но это было более десяти лет назад.) работать так хорошо, если к графическому объекту может быть применено преобразование.   -  person Tom Hawtin - tackline    schedule 16.03.2010
comment
(О, и кеш для Font. Вы можете видеть в документах API, что у них есть finalize, но нет dispose...)   -  person Tom Hawtin - tackline    schedule 16.03.2010


Ответы (2)


Хотя я не могу сказать вам, как обойти саму проблему, вы можете использовать этот метод, чтобы точно решить, когда ее запускать:

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

Это полезно, потому что вы можете поместить его где угодно — так, например, вы можете сделать это во время отображения экрана загрузки или что-то в этом роде. Если вы используете объект Graphics во время paint(), то вы ограничены только инициализацией во время рендеринга.

РЕДАКТИРОВАТЬ:

На самом деле это можно свести к:

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

(Медленная часть — это вызов getFont2D, а не конструктор Font.)

РЕДАКТИРОВАТЬ 2:

И, наконец, это можно свести к:

sun.font.FontManagerFactory.getInstance();

Проблема в том, что этому одноэлементному классу нужно много времени для запуска, так как он перечисляет все системные шрифты.

РЕДАКТИРОВАТЬ 3:

Нет хорошего способа обойти эту проблему, если вы хотите использовать стандартную графическую систему.

person Cel Skeggs    schedule 01.11.2015
comment
Это работает для меня, но мне пришлось использовать getFont2D: я протестировал 90 мс на FontManagerFactory.getInstance, а затем еще 2700 мс на getFont2D для моего конкретного шрифта (который отсутствует в системе). - person lapo; 18.04.2016

Нет реальной подсказки, почему это так медленно, но для метода 3, разве вы не должны сначала вызывать setFont?

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

Хотя на скорость это не влияет :-(

Кроме того, немного неэкономично создавать новый Font каждый раз, когда вызывается paint() (что происходит часто), вы можете переместить это в свой конструктор. Но это не может быть проблемой здесь, так как вы начинаете измерять время только после создания шрифта.

person Thomas    schedule 16.03.2010