Jonny L.
Jonny L.

Reputation: 39

Thread.sleep() delaying entire program instead of only what's after it

Pretty much title. The code is supposed to draw one box, wait 1 second, then draw a new one at a different location and repaint. Instead, it will wait for 1 second then paint both boxes. Thanks for the help and sorry if I messed up on formatting.

import javax.swing.*;
import java.awt.*;

public class GameRunner extends JPanel{
   @Override
   public void paintComponent (Graphics g){
      int x = 0;
      boolean directionRight = true;
      g.setColor(Color.blue);
      g.fillRect(300,400,100,100);
      repaint();
      try{
         Thread.sleep(1000);
      }
      catch (Exception ex){}
      g.fillRect(600,400,100,100);
      repaint();  
   }
   public static void main (String[] args){  
      JFrame frame = new JFrame("Submarine");
      GameRunner gameRunner = new GameRunner();
      frame.add(gameRunner);
      frame.setSize(1200,700);
      frame.setVisible(true);
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
   }
}

Upvotes: 3

Views: 82

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

  • Thread.sleep(1000); will block the current running thread
  • paintComponent is called from within the context of the Event Dispatching Thread.
  • Swing won't update the state of the UI until it's finished processing the current (in this case "paint") event, meaning that while it's blocked at Thread.sleep, nothing will be updated on the UI and no new events will be processed.

Swing is a single threaded framework. You should never perform any blocking or long running operations from within the context of the Event Dispatching Thread.

Have a look at Concurrency in Swing for more details and How to use Swing Timers for a possible solution.

As a side note, you should NEVER modify the state if the UI or any variable the UI relies on from within any paint method. Painting should only paint the current state of the component, never modify it, this includes calling repaint directly or indirectly

For example...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class GameRunner extends JPanel {

    private int xPos = 300;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.blue);
        g.fillRect(xPos, 400, 100, 100);
        repaint();
    }

    public GameRunner() {
        Timer timer = new Timer(1000, new ActionListener() {
            private boolean state = false;
            @Override
            public void actionPerformed(ActionEvent e) {
                if (state) {
                    xPos = 300;
                } else {
                    xPos = 600;
                }
                state = !state;
                repaint();
            }
        });
        timer.start();
    }

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

    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) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new GameRunner());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

Upvotes: 10

Related Questions