不支持字符的默认内置字体的系统字体

System Font with default built-in fonts for unsupported characters

我在 Windows 上为 JLabel 使用 Segoe UI 系统字体。 Segoe UI 不支持 CJK 字符,但不会为这些字符默认某些内容(例如 Font.DIALOG),它只会显示占位符。

我想在 Windows 上使用 Segoe UI,因为它看起来更适合拉丁字符,但我不想完全失去对显示 CJK 字符的支持。

有没有办法组合字体?对于拉丁字符,首选 Segoe UI,但默认为 Font.DIALOG(或任何其他系统默认值)以至少呈现可读字符。

例如

Font font = new Font("Segoe UI", Font.PLAIN, 12);
label.setFont(font);

使用 this 答案中建议的想法,您可以使用 JLabel 显示 html 的能力在需要时切换字体:

public static String transformText(String text) {
    Font defaultFont = new JLabel().getFont();
    Font segoe = new Font("Segoe UI", defaultFont.getStyle(), defaultFont.getSize());
    StringBuilder sb = new StringBuilder(
        "<html><span style=\"font-family: " + defaultFont.getFamily() + "\">");
    boolean inDefaultFont = true;

    for (int i = 0; i < text.length(); i++) {
        char current = text.charAt(i);
        if (segoe.canDisplay(current) ^ inDefaultFont) {
            // font already correct
            sb.append(current);
        } else {
            // switch font
            sb.append("</span><span style=\"font-family: "
                + (inDefaultFont ? segoe.getFamily() : defaultFont.getFamily())
                + "\">" + current);
            inDefaultFont = !inDefaultFont;
        }
    }
    sb.append("</span></html>");

    System.out.println(sb.toString());
    return sb.toString();
}

从测试输入 日本 한국 01 abc 到输出 <html><span style="font-family: Dialog">日本</span><span style="font-family: Segoe UI"> </span><span style="font-family: Dialog">한국</span><span style="font-family: Segoe UI"> 01 abc</span></html> 的结果在 JLabel.

中按需要显示

最简单的解决方案是使用 StyleContext#getFont,它将调用内部 api FontUtilities#getCompositeFontUIResource(Font)。此函数将创建一个复合字体,它将为不受支持的字符使用后备字体。

请注意,您无法控制将哪种字体用作备用字体。

因为返回的字体是 UIResource 我们需要包装它以避免它被 LookAndFeel 覆盖。自定义 NonUIResourceFont class 是必需的,因为需要另一个 FontFont 的构造函数受到保护。

public static Font createFont(final String family, final int style, final int size) {
    return new NonUIResourceFont(StyleContext.getDefaultStyleContext().getFont(family, style, size));
}

public static class NonUIResourceFont extends Font {

    public NonUIResourceFont(final Font font) {
        super(font);
    }
}