所以我遇到的问题是我通过显示一个简单的菜单来启动我的应用程序。为了正确调整文本大小和对齐文本,我需要获取字体规格,但我找不到快速完成此操作的方法。我测试了我的程序,看起来无论我使用什么方法来获取字体指标,第一次调用都会花费超过 500 毫秒!?因此,启动我的应用程序所需的时间比必要的要长得多。
我不知道它是否特定于平台,但以防万一,我在 MacBook Pro 上使用 Mac OS 10.6.2(这里硬件不是问题)。
如果您知道更快地获取字体规格的方法,请提供帮助。
我尝试了这 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();
}
}
虽然我无法告诉您如何解决问题本身,但您可以使用此方法来确定何时启动它:
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();
问题是这个单例类需要很长时间才能启动,因为它枚举了all系统字体。
编辑3:
如果您想使用标准图形系统,则没有解决此问题的好方法。
没有真正的线索说明为什么这么慢,但是对于方法3,你不应该先调用'setFont'吗?
public void paint(Graphics g) {
g.setFont(font);
FontMetrics fm = g.getFontMetrics();
}
不过,速度方面并没有什么区别:-(
此外,每次调用
Font
时创建一个新的 paint()
(这种情况经常发生)有点不经济,您可以将其移至构造函数中。但这不是这里的问题,因为只有在创建字体后才开始测量时间。
虽然代码不完全相同,但我也注意到
drawString
也很慢,在 Apple Macbook M1 上可能需要大约 300 毫秒。
分析显示,调用
drawString
必须加载操作系统字体 (sun.font.CFontManager.loadNativeFonts()
),这在本次运行中花费了约 203 毫秒,有时甚至更慢。
事实上
Graphics2d::getFontMetrics
还必须加载字体以获取其元数据,这是由 sun.font.FontUtilities.getFont2D(Font)
完成的。您可以在这个火焰图片段中注意到它也存在。
因此,像我们这里这样的小程序可能会为第一次使用该字体付出代价。在常规程序中,其他 Swing 组件(例如
JLabel
)可能会为我们付出代价。
因此,建议使用
JLabel
制作常规 Swing UI,并实际在 JPanel
上进行绘制。
如果获取字体涉及大量计算,另一个建议是在与绘制不同的时间解析字体/字体规格,利用
updateUI
在需要时刷新字体(例如 LaF 更改)。伪代码:
class MyCanvas extends JPanel {
private Font myFont; // always set by updateUI
@Override
public void updatedUI() {
myFont = slowFontAccess();
}
public void paintComponent(Graphics g) {
...
g2.getFontMetrics(myFont)
...
}
}