SWT – OS获取等宽字体的不可知方式

SWT中是否有一种方法可以简单地获得等宽字体,适用于各种操作系统?

例如。 这适用于Linux,但不适用于Windows:

Font mono = new Font(parent.getDisplay(), "Mono", 10, SWT.NONE); 

或者我需要一个方法尝试加载不同的字体(Consolas,终端,摩纳哥,单声道),直到一个不为空? 或者,我可以在启动时在属性文件中指定它。

我尝试从Display获取系统字体,但这不是等宽字体。

根据国际化支持相关API的JDK文档中的字体配置文件部分, 逻辑字体的概念用于定义某些与平台无关的字体​​,这些字体映射到默认字体配置文件中的物理字体:

Java平台定义了每个实现必须支持的五个逻辑字体名称:Serif,SansSerif,Monospaced,Dialog和DialogInput。 这些逻辑字体名称以依赖于实现的方式映射到物理字体。

所以在你的情况下,我会尝试

Font mono = new Font(parent.getDisplay(), "Monospaced", 10, SWT.NONE);

获取运行代码的当前平台的物理等宽字体的句柄。

编辑 :似乎SWT对逻辑字体一无所知(eclipse.org上的错误48055详细描述了这一点)。 在这个错误报告中,提出了一个hackish解决方法,其中可以从AWT字体检索物理字体的名称…

我花了一些时间来反对这个,直到我意识到显然eclipse必须能够访问monospace字体,以便在其文本字段,控制台等中使用。一点点挖掘出现了:

 Font terminalFont = JFaceResources.getFont(JFaceResources.TEXT_FONT); 

如果您感兴趣的是获得一些等宽字体,哪个有效。

编辑:或根据@ ctron的评论:

 Font font = JFaceResources.getTextFont(); 

编辑:警告(基于@ Lii的评论):这将为您提供已配置的文本字体,可由用户覆盖,也可能不是等宽字体。 但是,它将与编辑器和控制台中使用的字体一致,这可能是您想要的。

据我所知,AWT API不会暴露底层的Font信息。 如果你能够实现它,我希望它是依赖于实现的。 当然,比较几个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以适合自己。

对于有相同问题的人,您可以下载任何字体ttf文件,将其放在资源文件夹(在我的情况下为/ font / * * .ttf)中,并将此方法添加到您的应用程序中。 这是100%的工作。

 public Font loadDigitalFont(int policeSize) { URL fontFile = YouClassName.class .getResource("/fonts/DS-DIGI.TTF"); boolean isLoaded = Display.getCurrent().loadFont(fontFile.getPath()); if (isLoaded) { FontData[] fd = Display.getCurrent().getFontList(null, true); FontData fontdata = null; for (int i = 0; i < fd.length; i++) { if (fd[i].getName().equals("DS-Digital")) { fontdata = fd[i]; break; }} if (fontdata != null) { fontdata.setHeight(policeSize); fontdata.setStyle(SWT.BOLD);return new Font(getDisplay(), fontdata));} }return null; } 

如果您只想使用Monospaced字体,请使用“Courier”=> new Font(display, "Courier", 10, SWT.NORMAL)