首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Swing 外觀切換難題:從 Substance 到系統原生 Look & Feel 的完美解法

     編輯:Java 相關知識

Swing 應用在開源 Look & Feel(如 Substance、Nimbus)間切換容易,但切換至系統原生或 JDK 內建外觀時,常出現「無標題欄」或「標題欄未變」問題。根因在於啟動時設定:

JFrame.setDefaultLookAndFeelDecorated(true);

此行強制使用 Java 繪製視窗裝飾,導致切換原生外觀時衝突。本文提供核心解法:銷毀舊 JFrame、重建新 JFrame、保持位置大小。

核心代碼實現

1. 表單建構子支援裝飾開關

private static JFrame config;
private Rectangle savedBounds;

public SkinChangeDemo() { initComponents(); }

public SkinChangeDemo(boolean decor) {
    setUndecorated(decor); // 關鍵:控制是否使用 Java 裝飾
    initComponents();
}

2. 切換至 Substance 皮膚(無需重建視窗)


private void saharaButtonActionPerformed(ActionEvent evt) {
    LookAndFeel old = UIManager.getLookAndFeel();
    SubstanceSkin skin = new SaharaSkin();
    if (old instanceof SubstanceLookAndFeel) {
        SubstanceLookAndFeel.setSkin(skin); // 同家族直接換膚
    } else {
        changSkin(skin); // 非 Substance 需重建視窗
    }
}

3. 切換至 Nimbus(JDK 內建,需重建視窗)


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);
}

4. 通用切換至 Substance 邏輯(重建視窗 + 關鍵設定)


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);
}

主程式啟動預設 Substance 外觀


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、系統原生間自由切換,標題欄、邊框、按鈕風格完整跟隨:

多種外觀切換示意

無水印效果

Substance OfficeBlue2007

Nimbus 外觀

關鍵點總結

  1. setDefaultLookAndFeelDecorated(true) 只能在啟動前設定一次,不可動態改變
  2. 切換至原生/JDK 外觀必須 重建 JFrame,並以 setUndecorated(false) 讓系統接管裝飾
  3. 切換至 Substance 需 setUndecorated(true) + getRootPane().setWindowDecorationStyle(JRootPane.FRAME) 由 Java 繪製裝飾
  4. 重建前保存 getBounds(),重建後 setBounds() 保持視窗位置大小不變
  5. SwingUtilities.updateComponentTreeUI() 更新元件樹 UI

掌握此模式,Swing 外觀切換不再是痛點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved