1

我正在开发具有两个主题的外观。

问题是:

  • 我希望能够在两个主题之间动态切换(这意味着在启动后更改主题)。
  • 但是主题有两组不同的图标(实际上是相同的图标有不同的颜色)。

我不知道如何动态更改整个应用程序中的图标。

一种解决方案是在图标管理器上为每个组件注册一个图标和图标 ID,以在两种图标之间切换,但这似乎是一个非常繁重的解决方案!

4

1 回答 1

2

可能有很多不同的方法(我不能说哪一个是最好的):

  1. 基于 javax.swing.Icon 创建您自己的图标类,并根据当前安装的 L&F 绘制一个实际图标
  2. 在 installUI 方法中设置组件图标,因为它是在安装或重新安装组件 UI 时调用的(例如,当 L&F 更改时)
  3. 创建您自己的组件或其处理图标绘制的 UI
  4. 覆盖使用此类图标的组件并替换图标检索方法

可能还有更多,但首先想到的是……

这是第一个解决方案工作示例:

import com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel;

import javax.swing.*;
import javax.swing.plaf.metal.MetalLookAndFeel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * @see http://stackoverflow.com/a/12301173/909085
 */

public class LafIcon implements Icon
{
    private Map<String, Icon> lafIcons;

    public LafIcon ()
    {
        super ();
        lafIcons = new HashMap<String, Icon> ();
    }

    public void addIcon ( String laf, Icon icon )
    {
        lafIcons.put ( laf, icon );
    }

    private String getLaf ()
    {
        return UIManager.getLookAndFeel ().getClass ().getCanonicalName ();
    }

    private Icon getCurrentIcon ()
    {
        return lafIcons.get ( getLaf () );
    }

    public void paintIcon ( Component c, Graphics g, int x, int y )
    {
        Icon icon = getCurrentIcon ();
        if ( icon != null )
        {
            icon.paintIcon ( c, g, x, y );
        }
    }

    public int getIconWidth ()
    {
        Icon icon = getCurrentIcon ();
        return icon != null ? icon.getIconWidth () : 0;
    }

    public int getIconHeight ()
    {
        Icon icon = getCurrentIcon ();
        return icon != null ? icon.getIconHeight () : 0;
    }

    public static void main ( String[] args )
    {
        installMetalLookAndFeel ();

        JFrame frame = new JFrame ();
        frame.setLayout ( new FlowLayout ( FlowLayout.CENTER, 5, 5 ) );

        frame.add ( new JButton ( "Test button", createIcon () ) );

        String[] laf = { "Metal Look and Feel", "Nimbus Look and Feel" };
        final JComboBox lafType = new JComboBox ( laf );
        lafType.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                if ( lafType.getSelectedIndex () == 0 )
                {
                    installMetalLookAndFeel ();
                }
                else
                {
                    installNimbusLookAndFeel ();
                }
            }
        } );
        frame.add ( lafType );

        frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        frame.pack ();
        frame.setLocationRelativeTo ( null );
        frame.setVisible ( true );
    }

    private static LafIcon createIcon ()
    {
        LafIcon icon = new LafIcon ();    
        try
        {
            icon.addIcon ( MetalLookAndFeel.class.getCanonicalName (), new ImageIcon (
                    new URL ("http://cdn3.iconfinder.com/data/icons/fatcow/32x32_0020/application_form.png") ) );
            icon.addIcon ( NimbusLookAndFeel.class.getCanonicalName (), new ImageIcon (
                    new URL ("http://cdn3.iconfinder.com/data/icons/fatcow/32x32_0040/application_view_gallery.png") ) );
        }
        catch ( MalformedURLException e )
        {
            e.printStackTrace ();
        }    
        return icon;
    }

    private static void installMetalLookAndFeel ()
    {
        installLookAndFeel ( MetalLookAndFeel.class.getCanonicalName () );
    }

    private static void installNimbusLookAndFeel ()
    {
        installLookAndFeel ( NimbusLookAndFeel.class.getCanonicalName () );
    }

    private static void installLookAndFeel ( String name )
    {
        try
        {
            UIManager.setLookAndFeel ( name );

            Window[] windows = Window.getWindows ();
            if ( windows.length > 0 )
            {
                for ( Window window : windows )
                {
                    SwingUtilities.updateComponentTreeUI ( window );
                    window.pack ();
                }
            }
        }
        catch ( ClassNotFoundException e )
        {
            e.printStackTrace ();
        }
        catch ( InstantiationException e )
        {
            e.printStackTrace ();
        }
        catch ( IllegalAccessException e )
        {
            e.printStackTrace ();
        }
        catch ( UnsupportedLookAndFeelException e )
        {
            e.printStackTrace ();
        }
    }
}

实际上,如您所见,大部分代码都是示例。您可以修改图标代码以提供额外的图标添加/设置/删除方法,使图标更易于创建。

此外,您不需要使用这种方式收听 L&F 更改,因为在组件 UI 更改时它将被重新绘制和重新验证,因此将再次调用图标大小和绘制方法,并为更新的 L&F 提供新图标。

于 2012-09-06T13:25:43.700 回答