我正在开发具有两个主题的外观。
问题是:
- 我希望能够在两个主题之间动态切换(这意味着在启动后更改主题)。
- 但是主题有两组不同的图标(实际上是相同的图标有不同的颜色)。
我不知道如何动态更改整个应用程序中的图标。
一种解决方案是在图标管理器上为每个组件注册一个图标和图标 ID,以在两种图标之间切换,但这似乎是一个非常繁重的解决方案!
我正在开发具有两个主题的外观。
问题是:
我不知道如何动态更改整个应用程序中的图标。
一种解决方案是在图标管理器上为每个组件注册一个图标和图标 ID,以在两种图标之间切换,但这似乎是一个非常繁重的解决方案!
可能有很多不同的方法(我不能说哪一个是最好的):
可能还有更多,但首先想到的是……
这是第一个解决方案工作示例:
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 提供新图标。