Search code examples
javamultithreadingswingrepaint

Continuous call to repaint using thread.start() not working


I am new to Java swing. I want to create 2 cars that move from one end of the screen to another and for now I am testing it out with one.

But after three movements(indicated by "In paint component" printed 3 times) there is no movement.

I have attached the complete code below.

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;

public class Application {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {

                JFrame f = new JFrame("Demo");
                Car car = new Car();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(car);
                f.pack();
                f.setVisible(true);

                Thread thread = new Thread(car);
                thread.start();

            }
        });
    }

}

class Car extends JPanel implements Runnable {

    private int xBase = 0, yBase = 50;

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

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        System.out.println("In paint component");
        xBase = xBase + 20;

        // Draw two wheels
        g.setColor(Color.BLACK);
        g.fillOval(xBase + 10, yBase - 10, 10, 10);
        g.fillOval(xBase + 30, yBase - 10, 10, 10);

        // Draw the car body
        g.setColor(Color.BLUE);
        g.fillRect(xBase, yBase - 20, 50, 10);

        // Draw the top
        g.setColor(Color.DARK_GRAY);
        Polygon polygon = new Polygon();
        polygon.addPoint(xBase + 10, yBase - 20);
        polygon.addPoint(xBase + 20, yBase - 30);
        polygon.addPoint(xBase + 30, yBase - 30);
        polygon.addPoint(xBase + 40, yBase - 20);
        g.fillPolygon(polygon);
    }

    @Override
    public void run() {
        try {
            validate();
            repaint();
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            System.out.println(ex.getMessage());
        }
    }
}

What am I doing wrong.?


Solution

  • You need to call the repaint() method in a loop in order for the car to continue moving after you start the thread. For example:

    @Override
    public void run() {
        int limit = 10;
        try {
            while (limit > 0) {
                limit--;
                repaint();
                Thread.sleep(1000);
            }
        } catch (InterruptedException ex) {
            System.out.println(ex.getMessage());
        }
    }
    

    Currently the repaint() method gets called three time but you don't see any movement because the repaint takes place before the Car object is completely visible.

    In response to your comment: You can create a method to draw the car like so:

    private void drawCar(Graphics g, int x, int y) {
        g.fillOval(x, y, 10, 10);
        g.fillOval(x + 20, y, 10, 10);
        // Draw the car body
        g.setColor(Color.BLUE);
        g.fillRect(x - 10, y - 10, 50, 10);
        // Draw the top
        g.setColor(Color.DARK_GRAY);
        Polygon polygon = new Polygon();
        polygon.addPoint(x, y - 10);
        polygon.addPoint(x + 10, y - 20);
        polygon.addPoint(x + 20, y - 20);
        polygon.addPoint(x + 30, y - 10);
        g.fillPolygon(polygon);
    }
    

    and call it in the paintComponent(...) method multiple times:

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println("In paint component");
        xBase = xBase + 20;
        drawCar(g, xBase, yBase);// draw the first car
        drawCar(g, xBase + 80, yBase);// draw the second car 80 pixels ahead 
        drawCar(g, xBase, yBase + 100); // draw the third car 100 pixels lower
    
        g.dispose();
    }