-1

Hi I wanted to write a simple arcanoid game but for some reason my JPanel.repaint() is never called and my ball doesn't move. So in my main class extends JPanel to the JPanel I add a listener that is called when user wants to start a game and as a result a thread is fired this thread changes the position of the ball and should (ideally) call the repaint on my jpanel class. I checked the position of the ball changes but the repaint method is never called. Can someone please help? Thanks in advance here is my code:

public class test extends JPanel{
int x=250;
int y=470;
int width=100;
int height=20;
Ball b=new Ball();
public static void main(String[] args){
    test t=new test();
    t.draw();
}
public void draw(){
    JFrame frame=new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(520, 520);
    frame.setResizable(false);
    this.setSize(500,500);
    frame.add(this);
    this.addMouseListener(new mouseL());
    frame.setVisible(true);
}
public void paintComponent(Graphics g){
    super.paintComponent(g);
    System.out.println("Yeah I am called");

    Graphics2D g2d=(Graphics2D) g;
    g2d.setColor(Color.blue);
    g2d.fillRect(x, y, width, height);
    g2d.setColor(b.getColor());
    g2d.fillOval(b.x1, b.y1, b.width1, b.height1);
}
class Ball{
    Random rand=new Random();
    int x1=300;
    int y1=450;
    int height1=20;
    int width1=20;
    Color c;
    public Color getColor(){
        return new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
    }
}
class mouseL implements MouseListener{
    Thread t=new Thread(new MyRun());

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub
        t.run();


    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub

    }

}
class MyRun implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try{
        while(true){
            //System.out.println("Yeah I work");
            test.this.b.x1=test.this.b.x1-1;
            test.this.b.y1=test.this.b.y1-1;
            System.out.println("the values are: "+test.this.b.x1+" and "+test.this.b.y1);
            Thread.sleep(2000);
            test.this.repaint();
        }
        }catch(Exception e){
            e.printStackTrace();
        }

    }

}

}

user3428496
  • 49
  • 1
  • 8

1 Answers1

2

t.run(); calls (in your case) Runnabe#run, which is executed from within the context of the Event Dispatching Thread, thereby freezing your UI for ever.

You should have used t.start()

Because Swing is single threaded, you are running the risk of race conditions and dirty read/writes between the variables. A safer and simpler solution would be to use a Swing Timer, see How to use Swing Timers, which schedules it's notifications within the EDT, making safe to update the UI from

Also, take a look at How can I set in the midst? for reasons why you shouldn't use JFrame#setSize and should instead, override the getPreferredSize method of your JPanel and call JFrame#pack instead

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366