updating JFrame again

前端 未结 2 1518
栀梦
栀梦 2021-01-25 16:07

The following code shown below will add 3 JLabels to a JFrame and then remove the 3 JLabels. After 2 seconds it will repaint back the 3 JLabels.

import javax.swi         


        
2条回答
  •  礼貌的吻别
    2021-01-25 16:55

    You are violating the single thread rules of Swing...

    See Concurrency in Swing for more details.

    Essentially, you should never update any UI component from any thread context other than the Event Dispatching Thread.

    Instead, you should use either a SwingWorker or, probably more relevent to your problem, a javax.swing.Timer

    The problem is, as you've clearly noted, is the reference to frameTwo has nothing to do with the reference of frameOne, they are completely separate objects and therefore have nothing in common with each other

    What you need to be able to do is pass some kind of reference of the object you want updated to the class doing the updating...

    In this example, I simply created a reapplyLabels method in RepaintFrameTest and used a Swing Timer set for 2 a second delay, to call this method...

    Personally, I'd prefer to pass an interface as it exposes less and de-couples the code, but this is just a simple example...

    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class RepaintFrameTest extends JFrame {
    
        private JPanel panel = new JPanel();
        private JLabel labelOne = new JLabel("label1");
        private JLabel labelTwo = new JLabel("label2");
        private JLabel labelThree = new JLabel("label3");
    
        public RepaintFrameTest() {
            add(panel);
        }
    
        public void reapplyLabels() {
            panel.add(labelOne);
            panel.add(labelTwo);
            panel.add(labelThree);
    
            revalidate();
            repaint();
        }
    
        public static void main(String args[]) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    RepaintFrameTest frame = new RepaintFrameTest();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setSize(400, 400);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
    
                    Timer timer = new Timer(2000, new RepaintAction(frame));
                    timer.setRepeats(false);
                    timer.start();
                }
            });
        }
    
        public static class RepaintAction implements ActionListener {
    
            private RepaintFrameTest frame;
    
            public RepaintAction(RepaintFrameTest frame) {
                this.frame = frame;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.reapplyLabels();
            }
        }
    
    }
    

    While there's not enough context to make a full judement call, I also agree with HovercraftFullOfEels, a CardLayout would achieve the same result, probably with less mess...

提交回复
热议问题