据我所知,AWT API 不公开底层字体信息。如果你能得到它,我希望它依赖于实现。当然,比较几个 JRE lib 目录中的字体映射文件,我可以看到它们的定义方式不一致。
您可以加载自己的字体,但这似乎有点浪费,因为您知道该平台带有您需要的东西。
这是一个加载 JRE 字体的 hack:
private static Font loadMonospacedFont(Display display) {
String jreHome = System.getProperty("java.home");
File file = new File(jreHome, "/lib/fonts/LucidaTypewriterRegular.ttf");
if (!file.exists()) {
throw new IllegalStateException(file.toString());
}
if (!display.loadFont(file.toString())) {
throw new IllegalStateException(file.toString());
}
final Font font = new Font(display, "Lucida Sans Typewriter", 10,
SWT.NORMAL);
display.addListener(SWT.Dispose, new Listener() {
public void handleEvent(Event event) {
font.dispose();
}
});
return font;
}
它适用于 IBM/Win32/JRE1.4、Sun/Win32/JRE1.6、Sun/Linux/JRE1.6,但这是一种非常脆弱的方法。根据您对 I18N 的需求,那里也可能有问题(我还没有检查过)。
另一个技巧是测试平台上可用的字体:
public class Monotest {
private static boolean isMonospace(GC gc) {
final String wide = "wgh8";
final String narrow = "1l;.";
assert wide.length() == narrow.length();
return gc.textExtent(wide).x == gc.textExtent(narrow).x;
}
private static void testFont(Display display, Font font) {
Image image = new Image(display, 100, 100);
try {
GC gc = new GC(image);
try {
gc.setFont(font);
System.out.println(isMonospace(gc) + "\t"
+ font.getFontData()[0].getName());
} finally {
gc.dispose();
}
} finally {
image.dispose();
}
}
private static void walkFonts(Display display) {
final boolean scalable = true;
for (FontData fontData : display.getFontList(null, scalable)) {
Font font = new Font(display, fontData);
try {
testFont(display, font);
} finally {
font.dispose();
}
}
}
public static void main(String[] args) {
Display display = new Display();
try {
walkFonts(display);
} finally {
display.dispose();
}
}
}
这可能不是一个好方法,因为它可能会让您面临语言环境问题。此外,您不知道您遇到的第一个等宽字体是否不是一些绕组图标集。
最好的方法可能只是根据字体/区域设置映射白名单进行最佳猜测,并确保用户可以通过FontDialog轻松地重新配置 UI 以适合自己。