【问题标题】:Is there a non-proprietary equivalent to FontUtilities.getCompositeFontUIResource(Font)?是否有与 FontUtilities.getCompositeFontUIResource(Font) 等效的非专有等效项?
【发布时间】:2016-05-11 23:24:15
【问题描述】:

如果您只是使用new Font("Arial", Font.PLAIN, 10) 创建字体,那么稍后,当您尝试在该字体中显示缺失的字形时,您会看到熟悉的方块,指示缺失的字形。

很久以前,我们找到了解决此问题的方法 - 将字体传递给 FontUtilities.getCompositeFontUIResource(Font),然后您会得到一个 Font,它处理不在字体中的字符的后备。

问题是,该实用程序位于sun.font,我想消除编译器警告。

鉴于这段时间已经过去了很多年,现在有合适的方法来做到这一点吗?

演示:

import java.awt.Font;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

import sun.font.FontUtilities;

public class TestFonts implements Runnable
{
    @Override
    public void run()
    {
        Font font = new Font("Arial", Font.PLAIN, 20);

        JLabel label1 = new JLabel("Before \u30C6\u30B9\u30C8");
        label1.setFont(font);

        JLabel label2 = new JLabel("After \u30C6\u30B9\u30C8");
        label2.setFont(FontUtilities.getCompositeFontUIResource(font));

        JFrame frame = new JFrame("Font Test");
        frame.setLayout(new GridLayout(2, 1));
        frame.add(label1);
        frame.add(label2);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new TestFonts());
    }
}

结果:

【问题讨论】:

标签: java fonts awt


【解决方案1】:

在 JDK 源码中挖掘了一下,我发现了一个直接调用内部方法的公共方法。我不知道这被认为是多么狡猾,但它至少是公共 API。 :)

        label2.setFont(StyleContext.getDefaultStyleContext()
            .getFont(familyName, style, size));

【讨论】:

    【解决方案2】:

    您可以利用 JComponents 能够显示 HTML 的事实,并覆盖 JComponent 字体无法显示的字符的字体,方法是将这些字符放在 <span>: 中:

    import java.util.Formatter;
    
    import java.awt.Font;
    import java.awt.GridLayout;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.SwingUtilities;
    
    import sun.font.FontUtilities;
    
    public class TestFonts implements Runnable
    {
        /**
         * Replaces plain text meant to be displayed in a JComponent with
         * HTML that forces the font to Dialog for any characters which the
         * specified font cannot natively display.
         *
         * @param originalText text to transform to HTML, with forced fonts
         *                     where needed
         * @param font default font which will be used to display text
         *
         * @return HTML version of original text, which forces fonts where
         *         necessary to ensure all characters will be displayed
         */
        static String toCompositeFontText(String originalText,
                                          Font font) {
            Formatter html = new Formatter();
            html.format("%s", "<html><body style='white-space: nowrap'>");
    
            boolean fontOverride = false;
            int len = originalText.length();
            for (int i = 0; i < len; i = originalText.offsetByCodePoints(i, 1)) {
                int c = originalText.codePointAt(i);
    
                if (font.canDisplay(c)) {
                    if (fontOverride) {
                        html.format("%s", "</span>");
                        fontOverride = false;
                    }
                } else {
                    if (!fontOverride) {
                        html.format("<span style='font-family: \"%s\"'>",
                            Font.DIALOG);
                        fontOverride = true;
                    }
                }
    
                if (c == '<' || c == '>' || c == '&' || c < 32 || c >= 127) {
                    html.format("&#%d;", c);
                } else {
                    html.format("%c", c);
                }
            }
    
            if (fontOverride) {
                html.format("%s", "</span>");
            }
    
            html.format("%s", "</body></html>");
    
            return html.toString();
        }
    
        /**
         * Replaces text of the specified JLabel with HTML that contains the
         * same text, but forcing the font to Dialog for any characters which
         * the JLabel's current font cannot display.
         *
         * @param label JLabel whose text will be adjusted and replaced
         */
        static void adjustText(JLabel label) {
            label.setText(toCompositeFontText(label.getText(), label.getFont()));
        }
    
        @Override
        public void run()
        {
            Font font = new Font("Arial", Font.PLAIN, 20);
    
            JLabel label1 = new JLabel("Before \u30C6\u30B9\u30C8");
            label1.setFont(font);
    
            JLabel label2 = new JLabel("After \u30C6\u30B9\u30C8");
            label2.setFont(FontUtilities.getCompositeFontUIResource(font));
    
            JLabel label3 = new JLabel("Corrected \u30C6\u30B9\u30C8");
            label3.setFont(font);
            adjustText(label3);
    
            JFrame frame = new JFrame("Font Test");
            frame.setLayout(new GridLayout(3, 1));
            frame.add(label1);
            frame.add(label2);
            frame.add(label3);
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(new TestFonts());
        }
    }
    

    更新:

    此外,您可以监控标签的text 属性,以自动实现:

    label.addPropertyChangeListener("text", new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent event) {
            String text = (String) event.getNewValue();
            if (text != null && !text.startsWith("<html>")) {
                adjustText((JLabel) event.getSource());
            }
        }
    });
    

    明显的缺点是没有(简单的)方法来调整已经以&lt;html&gt; 开头的文本。 (实际上我很确定,即使这可以通过将标签的文本加载为HTMLDocument 来完成。)

    【讨论】:

    • 我真的不想在任何可能包含一些可变文本的组件上执行此操作...:/
    • 我同意这很尴尬。您可以添加一个 PropertyChangeListener 以使其成为一个自动过程。答案已相应更新。
    猜你喜欢
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2014-12-19
    • 2021-04-30
    • 2010-09-08
    相关资源
    最近更新 更多