Swing 應用在開源 Look & Feel(如 Substance、Nimbus)間切換容易,但切換至系統原生或 JDK 內建外觀時,常出現「無標題欄」或「標題欄未變」問題。根因在於啟動時設定:
JFrame.setDefaultLookAndFeelDecorated(true);
此行強制使用 Java 繪製視窗裝飾,導致切換原生外觀時衝突。本文提供核心解法:銷毀舊 JFrame、重建新 JFrame、保持位置大小。
private static JFrame config;
private Rectangle savedBounds;
public SkinChangeDemo() { initComponents(); }
public SkinChangeDemo(boolean decor) {
setUndecorated(decor); // 關鍵:控制是否使用 Java 裝飾
initComponents();
}
private void saharaButtonActionPerformed(ActionEvent evt) {
LookAndFeel old = UIManager.getLookAndFeel();
SubstanceSkin skin = new SaharaSkin();
if (old instanceof SubstanceLookAndFeel) {
SubstanceLookAndFeel.setSkin(skin); // 同家族直接換膚
} else {
changSkin(skin); // 非 Substance 需重建視窗
}
}
private void nimbusButtonActionPerformed(ActionEvent evt) {
try {
UIManager.setLookAndFeel(new NimbusLookAndFeel());
savedBounds = getBounds(); // 保存位置大小
dispose(); // 銷毀舊視窗
config = null;
config = new SkinChangeDemo(false); // 重建,不使用 Java 裝飾
config.setBounds(savedBounds); // 恢復位置大小
config.setVisible(true);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(SkinChangeDemo.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.updateComponentTreeUI(this);
}
private void changSkin(SubstanceSkin skin) {
savedBounds = getBounds();
dispose();
config = new SkinChangeDemo(true); // 使用 Java 裝飾
config.getRootPane().setWindowDecorationStyle(JRootPane.FRAME); // 關鍵:啟用 FRAME 裝飾
config.setBounds(savedBounds);
SubstanceLookAndFeel.setSkin(skin);
config.setVisible(true);
config.getRootPane().updateUI();
SwingUtilities.updateComponentTreeUI(this);
}
public static void main(String args[]) {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
try {
SubstanceImageWatermark watermark = new SubstanceImageWatermark(
SkinChangeDemo.class.getResourceAsStream("/demo/031be.jpg"));
watermark.setKind(ImageWatermarkKind.APP_CENTER);
watermark.setOpacity(0.7f);
UIManager.setLookAndFeel(new SubstanceOfficeBlue2007LookAndFeel());
SubstanceSkin skin = new OfficeBlue2007Skin().withWatermark(watermark);
SubstanceLookAndFeel.setSkin(skin);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(SkinChangeDemo.class.getName()).log(Level.SEVERE, null, ex);
}
EventQueue.invokeLater(() -> {
config = new SkinChangeDemo();
config.setVisible(true);
config.setLocationRelativeTo(null);
});
}
點擊按鈕在 Substance 皮膚(Sahara、Business、OfficeBlue2007)、Nimbus、系統原生間自由切換,標題欄、邊框、按鈕風格完整跟隨:




setDefaultLookAndFeelDecorated(true) 只能在啟動前設定一次,不可動態改變setUndecorated(false) 讓系統接管裝飾setUndecorated(true) + getRootPane().setWindowDecorationStyle(JRootPane.FRAME) 由 Java 繪製裝飾getBounds(),重建後 setBounds() 保持視窗位置大小不變SwingUtilities.updateComponentTreeUI() 更新元件樹 UI掌握此模式,Swing 外觀切換不再是痛點。