Using sleep in JPanel

情到浓时终转凉″ 提交于 2021-01-29 03:30:22

问题


I wrote a simple java program to place some rectangles on the screen (after some delay between each other)

package guitest2;
import java.awt.Graphics;
import javax.swing.JPanel;

public class DrawPanel extends JPanel {
    public void paintComponent( Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < 10; i++ ) {
           g.drawRect(10+5*i, 10+5*i, 20, 20);
           try{
              Thread.sleep( 2000 );
           }
           catch (InterruptedException ex) { }
        }
    }
}

I used that class in

package guitest2;
import javax.swing.JFrame;
public class Guitest2 {
    public static void main(String[] args) {
        DrawPanel panel = new DrawPanel();
        JFrame app = new JFrame();
        app.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
        app.add(panel);
        app.setSize(450, 250);
        app.setVisible(true);
    }    
}

The problem with running the above code is that, the squares are not shown. After 10*2S = 20 seconds, the final panel is shown containing all squares. What I want are:

1- Draw a square with g.drawRect.

2- Wait for 2 seconds

3- Remove the previous square and draw the new one.


回答1:


Maybe you could use the code like below, I changed a bit your code with comments.

    import java.awt.Color;
    import java.awt.Graphics;
    import javax.swing.JPanel;
    import javax.swing.JFrame;

    public class RectTest {
     DrawPanel panel;
     int x;
     int y;
     public static void main(String[] args) {
      new RectTest().startApp();
     } 

     public void startApp() {
      panel = new DrawPanel();
      JFrame app = new JFrame();
      app.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
      //modify this line
      app.getContentPane().add(panel);
      app.setSize(450, 250);
      app.setVisible(true);
      //added for loop here
      for (int i = 0; i < 10; i++ ) {
       // x,y here
       x = 10+5*i;
       y = 10+5*i;
       // repaint the panel
       panel.repaint();
       // wait 2sec
       try{
          Thread.sleep( 2000 );
       }
       catch (InterruptedException ex) { }
    }
   }

   class DrawPanel extends JPanel {
    public void paintComponent( Graphics g) {
       //super.paintComponent(g);
       // repaint the backround to see the single reactangles
       g.setColor(Color.white);
       g.fillRect(0, 0, this.getWidth(), this.getHeight());

       g.setColor(Color.green);
       g.drawRect(x, y, 20, 20);
    }
   }
  }



回答2:


You are sleeping on the Event Dispatch Thread (EDT), thereby blocking all GUI related events. The GUI runs on this one thread, the EDT, so you can't block it like that (i.e. sleep in a loop).

A relevant quote from the EDT link:

It's useful to think of the code running on the event dispatch thread as a series of short tasks. [...]

Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.

In your case, you are drawing 10 rectangles, with some sleeping in between. Then the rest of the event queue is handled. That results in a GUI being stuck for 10 x 2000ms, then the drawing is done.

Instead use a Swing Timer to time GUI related events:

A Swing timer (an instance of javax.swing.Timer) fires one or more action events after a specified delay. [...]

[...] we recommend using Swing timers [...] for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread.



来源:https://stackoverflow.com/questions/41247668/using-sleep-in-jpanel

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!