今天继续来Swing LAF的学习, 希望对有兴趣的新的朋友有帮助。我们为什么要学习LAF呢,其实很简单,就是为了能简单快速地给Swing “化一个漂亮的妆”。可能很多新学的朋友,都喜欢Override 组件的paintComponent(Graphics) 或者paint(Graphics)来完成对Swing的"美化"。其实,如果真的这样做了,那么这个组件的重用性变得很低了,而且代码的可读性也变得很差。更头痛的是,这样的组件如何快速方便切换Style呢(就像网页中的皮肤,可以快速切换)?闲话不多说了,下面来回顾上一篇文章。
看完了第一篇《LAF让Swing漂亮起来》的朋友可能会产生了问题:
1) UIManager.put(String sKey, Object oVal) 这种方法只能用来改变某种类型组件的风格。如:UIManager.put("Button.foreground", Colo.red) 改变了整个APP中所有Button的前景色。但是有些朋友会问,如果只是想改变某个Button的风格呢? 好,下面这篇文章中的例子也会解决。
2)上一篇文章中,有些朋友问到如何来改变渐变,在这篇文章中的例子都会解决。
这篇文章主要是如何使用Nimbus LAF来快速定制自己喜欢的组件。闲话不多说了,一切都在代码中,
下面的代码,没有进行过多的整理,为了方便大家运行,我直接在一个类里面写了。
package org.dui.laf; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.LinearGradientPaint; import java.awt.Paint; import java.awt.Point; import java.lang.reflect.Field; import java.lang.reflect.Method; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.synth.SynthLookAndFeel; import javax.swing.plaf.synth.SynthStyle; /** * <code>LAFDemo01</code> demonstrates how to use <code>Nimbus</code> to custom * your own style. * * @author Jimmy(SZ) * * @since <i>v1.0.0 (Apr 12, 2013)</i> */ public class LAFDemo03 extends JPanel { private static final long serialVersionUID = 1L; { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception e) { e.printStackTrace(); } } /** * Create an instance */ public LAFDemo03() { initGUI(); } /** * Initial the ui * * @since <i>v1.0.0 (Apr 12,2013)</i> */ public void initGUI() { this.setLayout(new GridLayout(7, 2)); this.add(new JLabel("Button1 : ")); this.add(new JButton("Default style")); this.add(new JLabel("Button2 : ")); this.add(new JButton("Default style")); this.add(new JLabel("Button3 : ")); this.add(new JButton("Default style")); this.add(new JLabel("Button4 : ")); JButton btn = new JButton("My style is changed."); this.add(btn); btn.setBorder(BorderFactory.createLineBorder(new Color(0 , 33, 106))); changeStyle(btn, "Button[Enabled].textForeground", new ColorUIResource(Color.darkGray)); changeStyle(btn, "Button.font", new Font("宋体", Font.BOLD, 16)); changeStyle(btn, "Button[Enabled].backgroundPainter", new GradientPainter(true, new Color(33, 249, 249), new Color(238, 4, 238))); changeStyle(btn, "Button[Focused+Pressed].backgroundPainter", new GradientPainter(true, new Color(238, 4, 238), new Color(33, 249, 249) )); changeStyle(btn, "Button[MouseOver].backgroundPainter", new GradientPainter(true, new Color(238, 4, 238), new Color(33, 249, 249) )); changeStyle(btn, "Button[Focused+MouseOver].backgroundPainter", new GradientPainter(false, Color.cyan, Color.blue)); SwingUtilities.updateComponentTreeUI(btn); } /** * Changed the style of single component specified by <code>oComp</code> * * @param oComp * @param sKey * @param oVal * * @since <i>v1.0.0 (Apr 12,2013)</i> */ private void changeStyle(JComponent oComp, String sKey, Object oVal) { UIDefaults uiDefaults = (UIDefaults) oComp.getClientProperty("Nimbus.Overrides"); if (uiDefaults == null) { uiDefaults = createDefs(); } uiDefaults.put(sKey, oVal); oComp.putClientProperty("Nimbus.Overrides.InheritDefaults", false); oComp.putClientProperty("Nimbus.Overrides", uiDefaults); reloadDefault(oComp); } /** * Refresh the synch style. * @param c * * @since <i>v1.0.0 (Apr 12,2013)</i> */ protected static void reloadDefault(JComponent c) { try { SynthStyle oStyle = SynthLookAndFeel.getStyle(c, SynthLookAndFeel.getRegion(c)); Field oStyleField = oStyle.getClass().getDeclaredField("values"); oStyleField.setAccessible(true); oStyleField.set(oStyle, null); Method oStyleMethod = oStyle.getClass().getDeclaredMethod("validate", new Class<?>[] {}); oStyleMethod.setAccessible(true); oStyleMethod.invoke(oStyle, new Object[] {}); } catch (Exception ex) { ex.printStackTrace(); } } /** * @return * * @since <i>v1.0.0 (Apr 12,2013)</i> * */ private UIDefaults createDefs() { return new UIDefaults(); } /** * Launch the app * * @param args * @since <i>v1.0.0 (Apr 12 ,2013)</i> */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame oFrame = new JFrame(); oFrame.setContentPane(new LAFDemo03()); oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); oFrame.setTitle("LAFDemo01"); oFrame.setSize(400, 400); oFrame.setLocationRelativeTo(null); oFrame.setVisible(true); } }); } /** * Simple GradientPainter * * Note that the performance of <code>GradientPainter</code> is poor. It will be improved in the coming days. * * @author Jimmy(SZ) * * @since <i>v1.0.0 (Apr 12,2013)</i> */ static class GradientPainter extends PainterAdaptor { Paint oPaint; Color[] m_aClr; boolean m_bVertical ; public GradientPainter(boolean bVertical, Color... aClr) { m_aClr = aClr; m_bVertical = bVertical; } @Override public void paint(Graphics2D g, JComponent object, int iW, int iH) { Paint oldPaint = g.getPaint(); int iLen = m_aClr.length; float[] aFra = new float[iLen]; float iAct = (1f / iLen); for (int i = 0; i < iLen; ++i) { aFra[i] = i * iAct; } Point ptEnd = null; if(m_bVertical){ ptEnd = new Point(0 , iH); }else{ ptEnd = new Point(iW , 0); } oPaint = new LinearGradientPaint(new Point(0 , 0),ptEnd , aFra, m_aClr); g.setPaint(oPaint); g.fillRect(0, 0, iW, iH); // restore the old paint g.setPaint(oldPaint); } } } class PainterAdaptor implements com.sun.java.swing.Painter<JComponent> { @Override public void paint(Graphics2D g, JComponent object, int iW, int iH) { } }
运行上面的例子大家可以看到:
看了上面例子,只是仅仅改变了一个Button的style,但是我觉得大家会依葫芦画瓢,其实其他组件也一样的。
总结一下不可缺少的步骤:
1 ) UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
2 ) 通过key-value的方式来改变Nimbus.Overrides的内容
3 ) validate synth style. 如#reloadDefault(JComponent)
4 ) SwingUtilities.updateComponentTreeUI(JComponent);
今天就学习到这里,欢迎来提意见 或者讨论。不懂的朋友可以留言,或者Google。想喷的朋友,也欢迎,毕竟写作能力有限,一个憨厚的程序员Jimmy.huang。