Swing组件采用MVC模式来管理组件,Swing可以通过改变外观感觉(Look And Feel)来控制组件的外观,选择不同的外观感觉显示不同的外观时,对组件的状态信息不会产生影响。
Swing默认的外观感觉名为Metal;Java 7 又提供了一种名为Nimbus的外观感觉。这二种外观感觉都比较美观。
可如下获得当前系统中可用的外观感觉数组:(不同版本的Widows系统略有不同)
UIManager.LookAndFeelInfo[] ui = UIManager.getInstalledLookAndFeels();
然后再得到外观感觉名称和对应的类名:
String uiName = ui[i].getName();
String className = ui[i].getClassName();
动态地改变界面外观观感,需要调用静态的UIManager.setLookAndFeel()方法,然后再调用静态方法SwingUtilities.updateComponentTreeUI(this)来刷新组件树,这里的参数this是当前框架窗体组件。
下面是一个界面外观感觉用按钮动态切换的例程:
package frame;
/***
* @author QiuGen
* @description 界面外观感觉动态切换例程PlafDemoFrm
* 实现功能:界面外观感觉动态切换演示功能。
* @date 2024/04/23
* ***/
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.Border;
public class PlafDemoFrm extends JFrame {
private JPanel panel = new JPanel();
private JPanel btnPan = new JPanel();
public PlafDemoFrm() {
setTitle("界面观感动态切换演示");
JLabel jLabel1 = new JLabel("姓 名:");
JLabel jLabel2 = new JLabel("性 别:");
jLabel1.setBounds(50, 20, 80, 30);
jLabel2.setBounds(50, 60, 80, 30);
JTextField jFieldName = new JTextField();
JComboBox<Object> cBoxXB = new JComboBox<>();
cBoxXB.addItem("女");
cBoxXB.addItem("男");
jFieldName.setBounds(130, 24, 150, 30);
cBoxXB.setBounds(130, 64, 50, 30);
jFieldName.setText("钱俊杰");
cBoxXB.setSelectedItem("男");
panel.setLayout(null);
panel.add(jLabel1);
panel.add(jLabel2);
panel.add(jFieldName);
panel.add(cBoxXB);
// 给panel加边框
Border etched = BorderFactory.createEtchedBorder();
panel.setBorder(etched);
add(panel,BorderLayout.CENTER);
UIManager.LookAndFeelInfo[] uiS = UIManager.getInstalledLookAndFeels();
for (LookAndFeelInfo ui : uiS)
setButton(ui.getName(), ui.getClassName());
add(btnPan,BorderLayout.SOUTH);
setPreferredSize(new Dimension(560, 200)); //设置窗口首选大小
setTitle("界面外观感觉测试");
pack();
}
private void setButton(String name, String classname) {
JButton button = new JButton(name);
btnPan.add(button);
button.addActionListener(event->{ //按钮驱动外观感觉更新
try { //外观感觉更新
UIManager.setLookAndFeel(classname);
SwingUtilities.updateComponentTreeUI(this);
repaint(); //重绘组件
} catch (Exception e) { e.printStackTrace(); }
});
}
public static void main(String[] args) {
JFrame frame = new PlafDemoFrm();
frame.setVisible(true);
}
}
这个例程对于初学者来说,可能难以理解。我碰到不理解的例程,有时候会把它拆解后进行编译测试,然后逐渐组装测试,直至完全理解每一个语句的作用。
上面这种写法简明扼要非常精练,但有点不好理解。我们再来看一种更容易理解的写法:
在程序中新增以下两个方法,用于替换setButton(String name, String classname)方法。
private void setButton(String name) { //新增的代码开始:
JButton button = new JButton(name);
btnPan.add(button);
button.addActionListener(event->{ //按钮驱动外观感觉更新
try {
updateLookAndFeel(event);//外观感觉更新
} catch (Exception e) { e.printStackTrace(); }
});
}
private void updateLookAndFeel(ActionEvent e) throws Exception {
switch (e.getActionCommand()){
case "Metal":
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
break;
case "Nimbus":
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
break;
case "Windows":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
break;
case "Windows Classic": UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
break;
case "CDE/Motif":
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
break;
}
SwingUtilities.updateComponentTreeUI(this); //刷新组件的外观
repaint(); //重绘组件
} //新增的代码结束。
然后,再把foreach循环的循环语句:
for (LookAndFeelInfo ui : uiS)
setButton(ui.getName(), ui.getClassName());
更新为:
for (LookAndFeelInfo ui : uiS)
setButton(ui.getName());
重新对程序进行编译测试,其实现的功能完全一样。
下面是我的另一个演示程序的外观感觉效果图