运行时更改字体

6
请问有没有其他方法可以在运行时更改整个AWT / Swing GUI的字体,而不需要了解/关心是否存在局部变量和JComponents的类型,而不是使用FontUIResource?

enter image description hereenter image description here

import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public class SystemFontDisplayer extends JFrame {

    private static final long serialVersionUID = 1L;
    private JFrame frame = new JFrame("Nimbus UIDeafaults and Font");
    private JComboBox fontsBox;
    private javax.swing.Timer timer = null;
    private JButton testButton = new JButton("testButton");
    private JTextField testTextField = new JTextField("testTextField");
    private JLabel testLabel = new JLabel("testLabel");

    public SystemFontDisplayer() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String[] fontFamilyNames = ge.getAvailableFontFamilyNames(Locale.getDefault());
        fontsBox = new JComboBox(fontFamilyNames);
        fontsBox.setSelectedItem(0);
        fontsBox.setRenderer(new ComboRenderer());
        fontsBox.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final String fontName = fontsBox.getSelectedItem().toString();
                    fontsBox.setFont(new Font(fontName, Font.PLAIN, 16));
                    start();
                }
            }
        });
        fontsBox.setSelectedItem(0);
        fontsBox.getEditor().selectAll();
        frame.setLayout(new GridLayout(4, 0, 20, 20));
        frame.add(fontsBox);
        frame.add(testButton);
        frame.add(testTextField);
        frame.add(testLabel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(200, 105);
        frame.pack();
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                fontsBox.setPopupVisible(true);
                fontsBox.setPopupVisible(false);
            }
        });
        frame.setVisible(true);
    }

    private void start() {
        timer = new javax.swing.Timer(750, updateCol());
        timer.setRepeats(false);
        timer.start();
    }

    public Action updateCol() {
        return new AbstractAction("text load action") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                final Font fnt = new Font(fontsBox.getSelectedItem().toString(), Font.PLAIN, 12);
                /*try {
                    LookAndFeel lnf = UIManager.getLookAndFeel().getClass().newInstance();
                    final FontUIResource res = new FontUIResource(fnt);
                    UIDefaults uiDefaults = lnf.getDefaults();
                    uiDefaults.put("Button.font", res);
                    uiDefaults.put("TextField.font", res);
                    uiDefaults.put("Label.font", res);
                    UIManager.getLookAndFeel().uninitialize();
                    UIManager.setLookAndFeel(lnf);
                } catch (InstantiationException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (UnsupportedLookAndFeelException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                }
                UIDefaults defaults = UIManager.getDefaults();
                final FontUIResource res = new FontUIResource(fnt);
                defaults.put("Button.font", res);
                defaults.put("TextField.font", res);
                defaults.put("Label.font", res);
                SwingUtilities.updateComponentTreeUI(frame);*/
                final FontUIResource res = new FontUIResource(fnt);
                UIManager.getLookAndFeelDefaults().put("Button.font", res);
                UIManager.getLookAndFeelDefaults().put("TextField.font", res);
                UIManager.getLookAndFeelDefaults().put("Label.font", res);
                SwingUtilities.updateComponentTreeUI(frame);
            }
        };
    }

    public static void main(String arg[]) {
        /*try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                SystemFontDisplayer systemFontDisplayer = new SystemFontDisplayer();
            }
        });
    }

    private class ComboRenderer extends BasicComboBoxRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            final Object fntObj = value;
            final String fontFamilyName = (String) fntObj;
            setFont(new Font(fontFamilyName, Font.PLAIN, 16));
            return this;
        }
    }
}

.

编辑:我先发布了使用Nimbus的叙述,然后再发布了Nimbus的代码。
import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public class SystemFontDisplayer extends JFrame {

    private static final long serialVersionUID = 1L;
    private JFrame frame = new JFrame("Nimbus UIDeafaults and Font");
    private JComboBox fontsBox;
    private javax.swing.Timer timer = null;
    private JButton testButton = new JButton("testButton");
    private JTextField testTextField = new JTextField("testTextField");
    private JLabel testLabel = new JLabel("testLabel");

    public SystemFontDisplayer() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String[] fontFamilyNames = ge.getAvailableFontFamilyNames(Locale.getDefault());
        fontsBox = new JComboBox(fontFamilyNames);
        fontsBox.setSelectedItem(0);
        fontsBox.setRenderer(new ComboRenderer());
        fontsBox.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final String fontName = fontsBox.getSelectedItem().toString();
                    fontsBox.setFont(new Font(fontName, Font.PLAIN, 16));
                    start();
                }
            }
        });
        fontsBox.setSelectedItem(0);
        fontsBox.getEditor().selectAll();
        frame.setLayout(new GridLayout(4, 0, 20, 20));
        frame.add(fontsBox);
        frame.add(testButton);
        frame.add(testTextField);
        frame.add(testLabel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(200, 105);
        frame.pack();
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                fontsBox.setPopupVisible(true);
                fontsBox.setPopupVisible(false);
            }
        });
        frame.setVisible(true);
    }

    private void start() {
        timer = new javax.swing.Timer(750, updateCol());
        timer.setRepeats(false);
        timer.start();
    }

    public Action updateCol() {
        return new AbstractAction("text load action") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                final Font fnt = new Font(fontsBox.getSelectedItem().toString(), Font.PLAIN, 12);
                try {
                    LookAndFeel lnf = UIManager.getLookAndFeel().getClass().newInstance();
                    final FontUIResource res = new FontUIResource(fnt);
                    UIDefaults uiDefaults = lnf.getDefaults();
                    uiDefaults.put("Button.font", res);
                    uiDefaults.put("TextField.font", res);
                    uiDefaults.put("Label.font", res);
                    UIManager.getLookAndFeel().uninitialize();
                    UIManager.setLookAndFeel(lnf);
                } catch (InstantiationException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (UnsupportedLookAndFeelException ex) {
                    Logger.getLogger(SystemFontDisplayer.class.getName()).log(Level.SEVERE, null, ex);
                }
                UIDefaults defaults = UIManager.getDefaults();
                final FontUIResource res = new FontUIResource(fnt);
                defaults.put("Button.font", res);
                defaults.put("TextField.font", res);
                defaults.put("Label.font", res);
                SwingUtilities.updateComponentTreeUI(frame);
                /*final FontUIResource res = new FontUIResource(fnt);
                UIManager.getLookAndFeelDefaults().put("Button.font", res);
                UIManager.getLookAndFeelDefaults().put("TextField.font", res);
                UIManager.getLookAndFeelDefaults().put("Label.font", res);
                SwingUtilities.updateComponentTreeUI(frame);*/
            }
        };
    }

    public static void main(String arg[]) {
        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                SystemFontDisplayer systemFontDisplayer = new SystemFontDisplayer();
            }
        });
    }

    private class ComboRenderer extends BasicComboBoxRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            final Object fntObj = value;
            final String fontFamilyName = (String) fntObj;
            setFont(new Font(fontFamilyName, Font.PLAIN, 16));
            return this;
        }
    }
}

+1 for sscce; 也请参考FontShower - trashgod
更新看起来不错;manItemInCombo() 也很方便。 - trashgod
@trashgod 我知道,也许,嗯,我猜这已经是一个大胆的冒险了... - mKorbel
FontUIRessource有什么问题? - user unknown
@用户未知,没有问题,也没有困难,只是没有人知道何时何地需要另一种选择。 - mKorbel
显示剩余2条评论
1个回答

2
例如:从FontFamily列表中创建一个新的字体,并使用c.setFont(font)将其应用于您的组件;
第二种方法是搜索TTF文件(例如),并使用静态方法Font.createFont(new File(“…”))创建新字体;
这个简单的应用程序将创建一个按族列出的字体列表,并将其应用于JButton和JTextField。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
/**
    FontSwitcher

    @author Stefan Wagner
    @date So 13. Mai 03:25:23 CEST 2012    
*/
public class FontSwitcher extends JFrame implements ActionListener
{
    private static final String progname = "FontSwitcher 0.1";

    private JTextField feedback;
    private JButton jb;
    private JList fontList;

    public FontSwitcher ()
    {
        super (progname);
        JPanel mainpanel = new JPanel ();
        mainpanel.setLayout (new BorderLayout ());
        this.getContentPane ().add (mainpanel);

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment ();
        String [] fonts = ge.getAvailableFontFamilyNames ();
        fontList = new JList (fonts);
        JScrollPane js = new JScrollPane (fontList);

        feedback = new JTextField ("Feedback");
        jb = new JButton ("apply font");
        jb.addActionListener (this);
        mainpanel.add (feedback, BorderLayout.NORTH);
        mainpanel.add (js, BorderLayout.CENTER);
        mainpanel.add (jb, BorderLayout.SOUTH);

        setSize (400, 800);
        setLocation (100, 100);
        setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        setVisible (true);
    }

    public void actionPerformed (final ActionEvent e)
    {
        SwingWorker worker = new SwingWorker () 
        {
            protected String doInBackground () throws InterruptedException 
            {
                String cmd = e.getActionCommand ();
                if (cmd.equals ("apply font"))
                {
                    String selectedFont = fontList.getSelectedValue ().toString ();
                    Font font = new Font (selectedFont, Font.TRUETYPE_FONT, 14);
                    jb.setFont (font);
                    feedback.setFont (font);
                }
                return "done";
            }
            protected void done () 
            {
                feedback.setText ("done");
            }
        };
        worker.execute ();
    }

    public static void main (final String args[])
    {
        Runnable runner = new Runnable () 
        {
            public void run () 
            {
                new FontSwitcher ();
            }
        };
        EventQueue.invokeLater (runner);
    }
}

现在我明白我的问题没有正确提出,当然我错过了整个AWT/Swing GUI,对于局部变量没有任何兴趣,谢谢。 - mKorbel
@mKorbel:对不起,我不确定我是否理解。您只对切换整个外观感兴趣,即所有组件的字体 - 而不是单独的字体?您正在寻找第二种方法,仅出于纯粹的兴趣 - 而不是因为您无法解决特定问题吗?您是否搜索过“LookAndFeel”?多年前我读到了一些关于它的东西,但没有进行调查。我认为它是关于切换应用程序的整个外观和感觉,并且应该也会更改字体。 - user unknown
另一个想法是使用访问者模式,遍历整个GUI树(不知道有多难),并在所有地方应用某种字体。 - user unknown
我没有任何问题,也不会出现各种外观(在Substance L&F之后),ComponentTree可能是另一种方式。 - mKorbel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接