【问题标题】:Change font dynamically causes problems on some components动态更改字体会导致某些组件出现问题
【发布时间】:2014-03-22 11:25:36
【问题描述】:

首先,我知道如何更新整个 UI 的字体。我使用以下代码:

private static void setUIFont(final FontUIResource f) {
    for (Map.Entry<Object, Object> entry : UIManager.getLookAndFeelDefaults().entrySet()) {
        Object key = entry.getKey();
        Object value = UIManager.getLookAndFeelDefaults().get(key);
        if (value != null && value instanceof FontUIResource) {
            UIManager.getLookAndFeelDefaults().put(key, f);
        }
    }

    dynamicallyUpdateRootPane(f);
}


private static void dynamicallyUpdateRootPane(FontUIResource f) {
        updateComponent(rootPanel, f);
}


private static void updateComponent(Component c, FontUIResource resource) {
    if (c == null) {
        return;
    }
    if (c instanceof JComponent) {
        JComponent jc = (JComponent) c;
        jc.updateUI();
        JPopupMenu jpm = jc.getComponentPopupMenu();
        if (jpm != null) {
            updateComponent(jpm, resource);
        }
    }
    Component[] children = null;
    if (c instanceof JMenu) {
        children = ((JMenu) c).getMenuComponents();
    }
    else if (c instanceof Container) {
        children = ((Container) c).getComponents();
    }
    if (children != null) {
        for (Component child : children) {
            if (child instanceof Component) {
                updateComponent(child, resource);
            }
        }
    }
    int style = Font.PLAIN;
    Font f = c.getFont();
    if (f == null) {
        f = getFontUIResource(16); // default
    }
    if (f.isBold()) {
        style = Font.BOLD;
    }
    else if (f.isItalic()) {
        style = Font.ITALIC;
    }

    if (c instanceof JEditorPane) {
        ((JEditorPane) c).putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
    }
    c.setFont(resource.deriveFont(style));
}

设置键后,我需要递归更新根面板,因为并非所有组件都会改变其外观。这段代码几乎可以工作 95%。 JButton 和 JMenuItem 有一些问题。

假设我以大字体启动我的程序并将其动态更改为较小的字体。 我的按钮的字体发生了变化(这很好......)但是当我将它们悬停时,字体会从小变大。 当我把鼠标放在一边时,它又从大变小了,我不知道为什么或如何处理它,测试了很多,但似乎没有任何效果。有这种翻转效果,当我悬停元素时,它似乎使用了不同的字体。

另一个奇怪的事情是我的菜单项。 菜单栏更改其字体(菜单),但菜单项不会更改。 我尝试手动更新它们,例如手动设置字体,但根本不起作用。

希望你们能帮助我,因为我在这方面花了太多时间(甚至几天)。 顺便提一句。我正在使用 Nimbus。

最好的问候

** 更新 **

修复了我的代码和我的工作示例。现在,在我动态更改字体大小后,我的 GUI 上的所有组件都将正确显示。有自动取款机。没时间清理我的代码,但对于那些对解决方案感兴趣的人来说,代码应该是清晰的。

    import java.awt.Component;
    import java.awt.Container;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Map;

    import javax.swing.JButton;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.SwingUtilities;
    import javax.swing.UIManager;
    import javax.swing.UIManager.LookAndFeelInfo;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.plaf.FontUIResource;



    public class Test extends JFrame {

        /**
         * 
         */
        private static final long serialVersionUID = 1865556053669711743L;


        public static void main(String[] args) {
            new Test();
        }


        public Test() {
            setLaf();
            prepareFrame();
            setJMenuBar(new MyMenuBar());
            pack();
            setVisible(true);
        }


        private void prepareFrame() {
            setLayout(new FlowLayout(FlowLayout.RIGHT));
            final JComboBox<String> combo = new JComboBox<>(new String[] {
                            "Small", "Large", "Larger"
            });
            JButton button = new JButton("Change");

            button.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    int index = combo.getSelectedIndex();
                    switch (index) {
                        case 0:
                            setUIFont(getFontUIResource(14));
                            break;
                        case 1:
                            setUIFont(getFontUIResource(16));
                            break;
                        case 2:
                            setUIFont(getFontUIResource(17));
                            break;
                    }
                    pack();
                    //SwingUtilities.updateComponentTreeUI(Test.this);
                }
            });
            getContentPane().add(combo);
            getContentPane().add(button);
        }


        private void setLaf() {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    try {
                        UIManager.setLookAndFeel(info.getClassName());
                    }
                    catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                                    | UnsupportedLookAndFeelException e) {
                        e.printStackTrace();
                    }
                }
            }
        }


        private class MyMenuBar extends JMenuBar {

            /**
             * 
             */
            private static final long serialVersionUID = 1434003372646915700L;


            public MyMenuBar() {
                JMenu menu1 = new JMenu("File");
                JMenu menu2 = new JMenu("Help");

                menu1.add(new JMenuItem("This is a test"));
                menu1.add(new JMenuItem("This is a test"));
                menu1.add(new JMenuItem("This is a test"));
                menu1.add(new JMenuItem("This is a test"));
                menu2.add(new JMenuItem("This is a test"));
                menu2.add(new JMenuItem("This is a test"));

                add(menu1);
                add(menu2);
            }
        }


        private FontUIResource getFontUIResource(int size) {
            return new FontUIResource(new Font("Arial", Font.PLAIN, size));
        }


        private void setUIFont(final FontUIResource f) {
            for (Map.Entry<Object, Object> entry : UIManager.getLookAndFeelDefaults().entrySet()) {
                Object key = entry.getKey();
                Object value = UIManager.getLookAndFeelDefaults().get(key);
                if (value != null && value instanceof FontUIResource) {
                    UIManager.getLookAndFeelDefaults().put(key, f);
                }
            }

            dynamicallyUpdateRootPane(f);
        }


        private void dynamicallyUpdateRootPane(FontUIResource f) {
            updateComponent(this, f);
        }


private void updateComponent(Component c, FontUIResource resource) {
    if (c == null) {
        return;
    }
    if (c instanceof JComponent) {
        JComponent jc = (JComponent) c;
        jc.updateUI();
        JPopupMenu jpm = jc.getComponentPopupMenu();
        if (jpm != null) {
            updateComponent(jpm, resource);
        }
    }
    Component[] children = null;
    if (c instanceof JMenu) {
        children = ((JMenu) c).getMenuComponents();
    }
    else if (c instanceof Container) {
        children = ((Container) c).getComponents();
    }
    if (children != null) {
        for (Component child : children) {
            if (child instanceof Component) {
                updateComponent(child, resource);
            }
        }
    }
    int style = Font.PLAIN;
    Font f = c.getFont();
    if (f == null) {
        f = getFontUIResource(16); // default
    }
    if (f.isBold()) {
        style = Font.BOLD;
    }
    else if (f.isItalic()) {
        style = Font.ITALIC;
    }

    if (c instanceof JEditorPane) {
        ((JEditorPane) c).putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
    }
    c.setFont(resource.deriveFont(style));
    }

【问题讨论】:

  • 你有没有试过在你搞砸之后在组件上调用updateUI...
  • 是的,它会还原我的更改。所以按钮有它原来的大小和字体。
  • 为了尽快获得更好的帮助,请发布MCTaRE(经过测试和可读的最小完整示例)。

标签: java swing user-interface dynamic fonts


【解决方案1】:

与其编写自己的递归代码,不如将其视为 LAF 更改并调用:

SwingUtilities.updateComponentTreeUI(frame);

请参阅 Changing the LAF 上的 Swing 教程部分。

此外,无需在代码中调用 revalidate() 和 repaint()。 setFont(...) 方法将自动调用这些方法。

【讨论】:

  • 该函数执行的步骤与我的基本相同:updateComponentTreeUI0(c); c.invalidate(); c.validate(); c.repaint(); 我再次更新了我的代码,因为某些组件没有正确显示。不得不将 setFont(..) 移到我函数的末尾。但你是对的@camickr 我不需要 revalidate() 和 repaint() 因为这是由 setFont(...) 完成的。 JMenuItems 仍然存在我的问题。文本的大小不会改变。
  • @IoannisK., The function performs basically the same steps as mine: - 然后使用 API 函数而不是您自己的函数。使用 JDK API 发布您的 SSCCEBtw. I am using Nimbus - JDK API 可以与其他 LAF 一起使用吗?也许这是一个 Nimbus 错误。我对 Nimbus 一无所知,因此无法发表评论。
  • 我编辑了我的帖子。对 SwingUtilities.updateComponentTreeUI(..) 的函数调用不能解决我的问题。 JMenuItem 上的悬停效果仍然存在。如果我摆脱了我的问题,我会尝试用 API 函数替换我的函数。
【解决方案2】:

终于解决了我的问题。 @camickr 给了我一个很好的提示。 不得不修改 API 代码以防止某些 NPE。 我没有时间让我的代码“更干净”,但对于那些感兴趣的人,我将分享我的代码: 现在所有项目都可以正确更改其大小。

private void updateComponent(Component c, FontUIResource resource) {
    if (c == null) {
        return;
    }
    if (c instanceof JComponent) {
        JComponent jc = (JComponent) c;
        jc.updateUI();
        JPopupMenu jpm = jc.getComponentPopupMenu();
        if (jpm != null) {
            updateComponent(jpm, resource);
        }
    }
    Component[] children = null;
    if (c instanceof JMenu) {
        children = ((JMenu) c).getMenuComponents();
    }
    else if (c instanceof Container) {
        children = ((Container) c).getComponents();
    }
    if (children != null) {
        for (Component child : children) {
            if (child instanceof Component) {
                updateComponent(child, resource);
            }
        }
    }
    int style = Font.PLAIN;
    Font f = c.getFont();
    if (f == null) {
        f = getFontUIResource(16); // default
    }
    if (f.isBold()) {
        style = Font.BOLD;
    }
    else if (f.isItalic()) {
        style = Font.ITALIC;
    }

    if (c instanceof JEditorPane) {
        ((JEditorPane) c).putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
    }
    c.setFont(resource.deriveFont(style));
}

** 编辑 ** 添加了对 JEditorPanes 的支持。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    • 1970-01-01
    • 2012-11-22
    • 2020-12-19
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多