简体   繁体   中英

Thread.sleep() doesn't strike when expected

I'm wondering why Thread.sleep() does not strike in the expected point of time.

I expected the first rectangle to be drawn, a pause of 2 seconds and then the appearance of the second rectangle. However, the pause kicks in first and then both rectangles are drawn 'at once'.

Why does this happen to be the case?

Thanks in advance for any advices.

public class Figure extends JPanel

{

  Point a = new Point(10, 10);

  Point b = new Point(110, 10);

  Point c = new Point(110, 110);

  Point d = new Point(10, 110);

  @Override
  protected void paintComponent(Graphics g)
  {

    super.paintComponent(g);

    g.drawLine(a.x, a.y, b.x, b.y);

    g.drawLine(b.x, b.y, c.x, c.y);

    g.drawLine(c.x, c.y, d.x, d.y);

    g.drawLine(d.x, d.y, a.x, a.y);

    try
    {
      Thread.sleep(2000);
    }
    catch(InterruptedException ex)
    {
    }
    Point newA = rotate(a, 45);
    Point newB = rotate(b, 45);
    Point newC = rotate(c, 45);
    Point newD = rotate(d, 45);

    g.drawLine(newA.x, newA.y, newB.x, newB.y);
    g.drawLine(newB.x, newB.y, newC.x, newC.y);
    g.drawLine(newC.x, newC.y, newD.x, newD.y);
    g.drawLine(newD.x, newD.y, newA.x, newA.y);
  }

  private Point rotate(Point p, int degree)

  {

    //to shift the resulting Point some levels lower
    int offset = 100;

    int x = (int)(Math.cos(degree) * p.x + Math.sin(degree) * p.y);
    int y = (int)(-Math.sin(degree) * p.x + Math.cos(degree) * p.y) + offset;

    Point ret = new Point(x, y);
    return ret;
  }

}

This happens because you do not enter Swings Event Loop; only then are paint commands guaranteed to execute. Also, that is also one reason why it's a good idea never to sleep in the event loop thread...

I changed the code for the second rectangle to

try
{
  Thread.sleep(2000);
}

catch(InterruptedException ex)
{
}

a = rotate(a, 45);
b = rotate(b, 45);
c = rotate(c, 45);
d = rotate(d, 45);

g.drawLine(a.x, a.y, b.x, b.y);
g.drawLine(b.x, b.y, c.x, c.y);
g.drawLine(c.x, c.y, d.x, d.y);
g.drawLine(d.x, d.y, a.x, a.y);

The method paintComponent seems to be ran through pereptually: Now a rectangle is rotated, its predecessor disappears and so on and so on...

Calling all those draw methods doesn't physically draw anything, it just puts drawing commands into the graphics pipeline, and all your sleep() is doing is holding up processing of the pipeline. What you should be doing is toggling a variable that tells the method which bits to draw, and externally firing repaint() from a separate thread at the required intervals.

Never ever use Thread.sleep() in AWT event thread (eg paintComponent() or various onclick handlers, which are always run in AWT event thread) - you are blocking all events from being processed - key, mouse, etc and your app will look like it froze. A quick-and-dirty solution:

private boolean isRotating = false;

 @Override
protected void paintComponent(Graphics g)
{
  super.paintComponent(g);
  if (!isRotating) {
  g.drawLine(a.x, a.y, b.x, b.y);
  g.drawLine(b.x, b.y, c.x, c.y);
  g.drawLine(c.x, c.y, d.x, d.y);
  g.drawLine(d.x, d.y, a.x, a.y);
  isRotating = true;
  Utils.swingInvokeDelayed(new Runnable() { public void run(){ repaint();}}, 2000);
} else {
  Point newA = rotate(a, 45);
  Point newB = rotate(b, 45);
  Point newC = rotate(c, 45);
  Point newD = rotate(d, 45);
  g.drawLine(newA.x, newA.y, newB.x, newB.y);
  g.drawLine(newB.x, newB.y, newC.x, newC.y);
  g.drawLine(newC.x, newC.y, newD.x, newD.y);
  g.drawLine(newD.x, newD.y, newA.x, newA.y);
  isRotating = false;
}
}

public class Utils {
// ideal is to keep 0 as corePoolSize, but then the executor simply does not work :(
private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, newDaemonThreadFactory(Utils.class.getSimpleName()));
private static ThreadFactory newDaemonThreadFactory(final String threadName) {
    return new ThreadFactory() {

        public Thread newThread(Runnable r) {
            final Thread result = new Thread(r, threadName);
            result.setDaemon(true);
            return result;
        }
    };
}
public static void swingInvokeDelayed(final Runnable r, final long delay) {
    executor.schedule(new Runnable() {

        public void run() {
            SwingUtilities.invokeLater(r);
        }
    }, delay, TimeUnit.MILLISECONDS);
}
}

Swingworker is what you are searching for

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