动态更改字体会导致某些组件出现问题

时间:2014-03-19 01:29:33

标签: java swing user-interface dynamic fonts

首先,我知道如何更新整个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上的所有组件都将正确显示。有atm。没有时间清理我的代码,但对于那些对解决方案感兴趣的人,代码应该清楚。

    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));
    }

2 个答案:

答案 0 :(得分:2)

不是编写自己的递归代码,也许你只需将其视为LAF更改而只是调用:

SwingUtilities.updateComponentTreeUI(frame);

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

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

答案 1 :(得分:0)

最后我解决了我的问题。 @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的支持。