简体   繁体   中英

EDT-swing problems

I have a method that is executed within the EDT. It's something like this:

myMethod()
{
  System.out.prinln(SwingUtilities.isEventDispatchThread());

  for (int i = 0; i < 10; i++)
  {
   Thread.sleep(3000);
   someJPanel.remove(otherJPanel);
  }
}

What I expected to happen: Ten JPanels would be removed from their parent one by one, with three second pauses in between each removal...

What actually happened: Everything froze for 30 seconds, after what all 10 elements were removed at once.

The line in the console was always true (SwingUtilities.isEventDispatchThread()).

Since I'm doing all this in the EDT, why aren't the changes instant? Why does it wait for the method to reach it's end first?

How should I alter my code in order to achieve the three seconds delay inbetween removals?

Swing uses a single thread to dispatch events and process repaint requests. Any time you block this thread, you stop the EDT from processing these repaint requests making the UI look like it's "stopped".

Instead, using something like a javax.swing.Timer to insert the delay and perform the action. This will execute the action within the EDT, but will wait in a back ground thread.

Have a read through The Event Dispatching Thread for details...

Updated with Timer Example

public class SlowDecline {

    public static void main(String[] args) {
        new SlowDecline();
    }
    private TestPane last;

    public SlowDecline() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                TestPane parent = new TestPane(Color.RED);
                TestPane tp = add(parent, Color.BLUE);
                tp = add(tp, Color.GREEN);
                tp = add(tp, Color.CYAN);
                tp = add(tp, Color.LIGHT_GRAY);
                tp = add(tp, Color.MAGENTA);
                tp = add(tp, Color.ORANGE);
                tp = add(tp, Color.PINK);

                last = tp;

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(parent);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                Timer timer = new Timer(1000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (last != null) {
                            Container parent = last.getParent();
                            if (parent != null) {
                                parent.remove(last);
                                parent.repaint();
                                if (parent instanceof TestPane) {
                                    last = (TestPane) parent;
                                }
                            } else {
                                last = null;
                            }
                        } else {
                            (((Timer)e.getSource())).stop();
                        }
                    }
                });
                timer.setRepeats(true);
                timer.setCoalesce(true);
                timer.start();
            }
        });
    }

    public TestPane add(TestPane parent, Color color) {

        TestPane child = new TestPane(color);
        parent.add(child);
        return child;
    }

    public class TestPane extends JPanel {

        public TestPane(Color background) {
            setLayout(new BorderLayout());
            setBorder(new EmptyBorder(10, 10, 10, 10));
            setBackground(background);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(50, 50);
        }
    }
}

This is because the UI thread is responsible for painting the screen, as well as handling events. When you put the UI thread to sleep, no more painting or event handling can occur. When the thread resumes painting, all the panels have already been removed.

This URL is pretty comprehensive on how to handle threading with Swing .

You are best to create a Thread that removes the panels.

(untested)

Thread t = new Thread() {
   @Override
   public void run() {  // override the run() for the running behaviors
     for (int i = 0; i < 10; i++)
     {
        Thread.sleep(3000);
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
           someJPanel.remove(...);
          });
     }
   }
};
t.start();  // call back run()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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