簡體   English   中英

Java:系統 L&F 僅第二次正確出現

[英]Java: system L&F only appearing correctly for second time

我正在使用此代碼在程序上設置外觀: UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); 我只在程序運行時顯示的 JPanel(在 JFrame 內)上使用系統外觀。 我第一次展示 JPanel 時,L&F 是錯誤的(看起來它是針對舊版本的 windows 之類的,與我以前在其他組件上使用的不一樣)。 我隱藏了JPanel,然后再次打開它,L&F 現在是正確的。 可悲的是,我無法制作可重現的示例,但問題仍然存在於原始程序中。 它由多個類組成,並有一個面向 object 編寫的 UI,這是導致有問題的 JPanel 的代碼:

package almanah;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SeriesProperties extends JPanel {

    JButton button_close = new JButton();
    JPanel container = new JPanel();
    JScrollPane scPane = new JScrollPane(container);

    public SeriesProperties(ItemLib lib) {
        
        try {
            UIManager.setLookAndFeel(
            UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(SeriesProperties.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(SeriesProperties.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(SeriesProperties.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(SeriesProperties.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        this.setLayout(new BorderLayout());

        this.add(button_close, BorderLayout.EAST);
        button_close.addActionListener((e) -> {
            Almanah.frame.swapToTiles();
        });

        scPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.add(scPane, BorderLayout.CENTER);
        
        //container
        container.setBackground(Color.red);
        container.setLayout(new WrapLayout());
        
        for (int i = 0; i < 100; i++) {
            JPanel panel=new JPanel();
            panel.setPreferredSize(new Dimension(100, 100));
            container.add(panel);
        }
        this.updateUI();
    }

}

在創建任何 UI 元素之前,先確定外觀 state。 在運行時切換 L&F 的能力實際上是一種副作用,通常不鼓勵使用,因為它從來都不是系統的功能。

相反,可能在您的main方法中,設置外觀,然后在它之后構建您的 UI。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(
                            UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                JFrame frame = new JFrame();
                // I don't know what ItemLib, as the source is incomplete
                frame.add(new SeriesProperties(...));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SeriesProperties extends JPanel {

        JButton button_close = new JButton();
        JPanel container = new JPanel();
        JScrollPane scPane = new JScrollPane(container);

        public SeriesProperties(ItemLib lib) {

            this.setLayout(new BorderLayout());

            this.add(button_close, BorderLayout.EAST);
            button_close.addActionListener((e) -> {
                // This seems like a bad idea
                // You should consider using a observer/delegate
                // pattern instead, reducing the coupling of your code
                Almanah.frame.swapToTiles();
            });

            scPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            scPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            this.add(scPane, BorderLayout.CENTER);

            //container
            container.setBackground(Color.red);
            container.setLayout(new WrapLayout());

            for (int i = 0; i < 100; i++) {
                JPanel panel = new JPanel();
                panel.setPreferredSize(new Dimension(100, 100));
                container.add(panel);
            }
            //this.updateUI();
        }

    }
}

解決方案:

Error13660 ,你的問題解決了嗎? 這是我改變外觀和感覺的解決方案。

並看到這個答案

package snippet;

import java.awt.EventQueue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(() -> {
            
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                    | UnsupportedLookAndFeelException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            var frame = new JFrame();
            
            var panel = new JPanel();
            
            { // Button 0: onclick change theme 0
                var btn = new JButton("Theme 0");
                btn.addActionListener((e) -> {
                    System.out.println("actionPerformed: change theme 0");
                    Test.changeLaF(frame, "javax.swing.plaf.metal.MetalLookAndFeel");
                });
                panel.add(btn);
            }
         
            { // Button 1: onclick change theme 1
                var btn = new JButton("Theme 1");
                btn.addActionListener((e) -> {
                    System.out.println("actionPerformed: change theme 1");
                    Test.changeLaF(frame, "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
                });
                panel.add(btn);
            } 
            
            frame.add(panel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
 
    
    public static final void changeLaF(final JFrame frame, final String nameLookAndFeel) {
        try {
            UIManager.setLookAndFeel(nameLookAndFeel);
            SwingUtilities.updateComponentTreeUI(frame);
            frame.pack ();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                | UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在 24-02-21 版之前:

您是否嘗試過使用SwingUtilities.updateComponentTreeUI(frame);

啟動后更改外觀:即使程序的 GUI 可見,您也可以使用 setLookAndFeel 更改 L&F。 要使現有組件反映新的 L&F,請為每個頂級容器調用一次 SwingUtilities updateComponentTreeUI 方法。 然后您可能希望調整每個頂級容器的大小以反映其包含的組件的新大小。 例如:

參見: lookandfeel/plaf#Dynamic

UIManager.setLookAndFeel(lnfName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();

更新: /,\ 如果成功加載 L&F,則所有組件都使用該 L&F 外觀/plaf#Steps

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM