Swing 支援即插即用的外觀架構,允許運行時動態切換 LookAndFeel (LAF)。本文演示如何枚舉系統安裝的 LAF、創建按鈕一鍵切換、使用 SwingUtilities.updateComponentTreeUI 遞歸更新組件樹,提供完整可運行代碼。
使用 EventQueue.invokeLater 確保 GUI 構建在 EDT 執行,創建並顯示主窗體。
public class PlafTest {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
PlafFrame frame = new PlafFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
構造函數中獲取所有已安裝 LAF (UIManager.getInstalledLookAndFeels()),為每個 LAF 動態創建按鈕,點擊時切換外觀並更新組件樹。
class PlafFrame extends JFrame {
private JPanel buttonPanel;
public PlafFrame() {
this.setTitle("PlafTest - 外觀切換演示");
this.setSize(400, 300);
buttonPanel = new JPanel();
// 獲取所有已安裝的 LookAndFeel
UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels();
for (UIManager.LookAndFeelInfo info : infos) {
makeButton(info.getName(), info.getClassName());
}
this.add(buttonPanel);
}
private void makeButton(String name, final String className) {
JButton button = new JButton(name);
buttonPanel.add(button);
button.addActionListener(e -> {
try {
// 設置新的 LookAndFeel
UIManager.setLookAndFeel(className);
// 遞歸更新整個組件樹
SwingUtilities.updateComponentTreeUI(PlafFrame.this);
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
});
}
}
| API | 作用 | 關鍵點 |
|---|---|---|
| UIManager.getInstalledLookAndFeels() | 獲取系統註冊的所有 LAF | 返回 LookAndFeelInfo[],含名稱與類全限定名 |
| UIManager.setLookAndFeel(className) | 設置當前應用的 LAF | 影響後續創建的組件,現有組件需手動更新 |
| SwingUtilities.updateComponentTreeUI(Component) | 遞歸更新組件及其子組件 UI | 調用每個組件的 updateUI() 方法,實現熱切換 |
| EventQueue.invokeLater(Runnable) | 在 EDT 中異步執行任務 | 保證 Swing 組件創建/修改的線程安全 |