【问题标题】:SWT - OS agnostic way to get monospaced fontSWT - 获取等宽字体的操作系统无关方式
【发布时间】:2008-10-21 11:50:49
【问题描述】:

在 SWT 中有没有一种方法可以简单地获得等宽字体,并且可以在各种操作系统中使用?

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

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

或者我是否需要一种方法来尝试加载不同的字体(Consolas、Terminal、Monaco、Mono)直到一个不为空?或者,我可以在启动时在属性文件中指定它。

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

【问题讨论】:

    标签: java fonts swt


    【解决方案1】:

    我花了一段时间猛烈抨击这个,直到我意识到显然 eclipse 必须可以访问等宽字体才能在其文本字段、控制台等中使用。出现了一点挖掘:

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

    如果您感兴趣的只是获取一些等宽字体,那么这很有效。

    编辑:或基于@ctron 的评论:

    Font font = JFaceResources.getTextFont();
    

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

    【讨论】:

    • 非常好!这是这里唯一可用的答案
    • 或者更简单一点:Font font = JFaceResources.getTextFont();
    • 这不一定是等宽字体。 例如,在 Eclipse 应用程序中,它将是用户在 Preferences > General > Colors 中配置的任何字体和字体 > 基本 > 文本字体。它与 Eclipse 中的基本文本编辑器使用的字体相同。当然,几乎所有用户都会使用等宽字体,但您不能确定。
    【解决方案2】:

    根据Internationalization Support相关API的JDK文档中关于Font Configuration Files的部分,Logical Fonts的概念用于定义映射到物理的某些平台无关字体默认字体配置文件中的字体:

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

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

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

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

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

    【讨论】:

    • 这也应该以 java.awt.Font.MONOSPACED 的形式提供
    • 他们现在似乎为此提供了一个SWTFontUtils 类。
    【解决方案3】:

    据我所知,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 以适合自己。

    【讨论】:

    • 感谢您的详细回答。我相信最好的选择就是您所说的 - 指定一个平淡无奇的默认值,例如在所有平台上都可用的 Courier,并允许用户使用字体配置对话框更改此属性。
    • 有没有办法从 Java 资源或“InputStream”中加载“字体”而不是 SWT 中的文件路径?
    • @parxier - 我不知道。这作为一个新问题会更好。
    • 谢谢,新问题 (stackoverflow.com/questions/2734106/…) 已创建。
    【解决方案4】:

    对于有同样问题的人,您可以下载任何字体 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;   }
    

    【讨论】:

    • 这在 Ubuntu 12.04 + Eclipse 3.7 上对我有用,但在 Windows 7 + Eclipse 4.3 loadFont() 的参数是捆绑 URL 而不是文件时返回 false。
    • 你应该认为给定的相对路径“/fonts/DS-DIGI.TTF”在资源目录中,你使用的是maven吗?
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 2014-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 2011-05-11
      相关资源
      最近更新 更多