1

2 つのテーマでルック アンド フィールを開発しています。

問題は:

  • 2 つのテーマを動的に切り替えられるようにしたい (起動後にテーマを変更することを意味します)。
  • ただし、テーマには 2 つの異なるアイコンのセットがあります (実際には、同じアイコンで色が異なります)。

アプリケーション全体のアイコンを動的に変更する方法がわかりません。

解決策の 1 つは、各コンポーネントにアイコンとアイコン ID を使用してアイコン マネージャーに登録し、2 種類のアイコンを切り替えることですが、非常に重い解決策のようです。

4

1 に答える 1

2

多くの異なるアプローチが存在する可能性があります (どれが最適かはわかりません):

  1. javax.swing.Icon に基づいて独自のアイコン クラスを作成し、現在インストールされている L&F に基づいて実際のアイコンをペイントします。
  2. コンポーネント UI のインストール時または再インストール時に呼び出されるため (L&F が変更された場合など)、installUI メソッド内にコンポーネント アイコンをセットアップします。
  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 に答える