简体   繁体   English

Java:系统 L&F 仅第二次正确出现

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

I am using this code to set up a look and feel on a program: UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName());我正在使用此代码在程序上设置外观: UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); I am only using the system look and feel on a JPanel (inside a JFrame) that i show during the runtime of the program.我只在程序运行时显示的 JPanel(在 JFrame 内)上使用系统外观。 The first time i show the JPanel, the L&F is wrong (looks like it is for an older version of windows or something, not the same as i used before, on the other components).我第一次展示 JPanel 时,L&F 是错误的(看起来它是针对旧版本的 windows 之类的,与我以前在其他组件上使用的不一样)。 I hide the JPanel then open it agin, the L&F is now correct.我隐藏了JPanel,然后再次打开它,L&F 现在是正确的。 Sadly i wasn't able to produce a reproducaple example but the problem persists in the original program.可悲的是,我无法制作可重现的示例,但问题仍然存在于原始程序中。 It consists of multiple classes, and has an object orientedly written UI, this is the code responsible for the problematic JPanel:它由多个类组成,并有一个面向 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();
    }

}

Establish the look and feel state BEFORE you create ANY UI elements.在创建任何 UI 元素之前,先确定外观 state。 The ability to switch the L&F at runtime is actually a side effect and is generally discouraged as it was never a feature of the system.在运行时切换 L&F 的能力实际上是一种副作用,通常不鼓励使用,因为它从来都不是系统的功能。

Instead, probably in your main method, set the look and feel and then build your UI after it.相反,可能在您的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();
        }

    }
}

Solution:解决方案:

Error13660 , have you fixed your problem? Error13660 ,你的问题解决了吗? Here is my solution to change look and feel.这是我改变外观和感觉的解决方案。

And see This answer .并看到这个答案

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

Before edition of 24-02-21:在 24-02-21 版之前:

Have you tried using SwingUtilities.updateComponentTreeUI(frame);您是否尝试过使用SwingUtilities.updateComponentTreeUI(frame);

Changing the Look and Feel After Startup: You can change the L&F with setLookAndFeel even after the program's GUI is visible.启动后更改外观:即使程序的 GUI 可见,您也可以使用 setLookAndFeel 更改 L&F。 To make existing components reflect the new L&F, invoke the SwingUtilities updateComponentTreeUI method once per top-level container.要使现有组件反映新的 L&F,请为每个顶级容器调用一次 SwingUtilities updateComponentTreeUI 方法。 Then you might wish to resize each top-level container to reflect the new sizes of its contained components.然后您可能希望调整每个顶级容器的大小以反映其包含的组件的新大小。 For example:例如:

see: lookandfeel/plaf#Dynamic参见: lookandfeel/plaf#Dynamic

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

Update: /,\ if successful loaded L&F, all components use that L&F .更新: /,\ 如果成功加载 L&F,则所有组件都使用该 L&F lookandfeel/plaf#Steps 外观/plaf#Steps

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM