在运行时更改字体

Posted

技术标签:

【中文标题】在运行时更改字体【英文标题】:Change Font at runtime 【发布时间】:2012-04-15 00:37:08 【问题描述】:

对于整个 AWT/Swing GUI,是否有另一种方法可以,就像使用 FontUIResource 一样,而不需要任何关于是否存在局部变量和 JComponents 类型的知识/兴趣

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 代表sscce;另见FontShower 小注:只需要javax.swing.Timer的一个实例;只需要一个setSelectedItem();考虑getAvailableFontFamilyNames(Locale.getDefault())。适用于 Mac OS。 @trashgod 再次确定我无用的镇流器的一部分,以前我从 Timer 为 JComboBox 设置了 auto_select,然后从 JComboBox 的 selectedItem 中按值更改字体,对此我很抱歉 更新看起来不错; manItemInCombo() 看起来也很方便。 @trashgod 我知道也许,我猜这已经是一个大胆的风险...... 【参考方案1】:

例如:从 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);
    

【讨论】:

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

以上是关于在运行时更改字体的主要内容,如果未能解决你的问题,请参考以下文章

在运行时更改字体

运行不相关的动画时,Safari 会更改字体粗细

Qt应用程序以root身份运行时更改字体

在 Android 4.4+ 上运行时如何忽略 Cordova App 的字体大小设置更改?

C#在运行时修改控制台字体、字体大小?

使用静态 Qt 应用程序时如何更改 Qt 字体的路径?