3

I'm writing a simple Game of Life program in Java and am having a bit of trouble getting it to animate. I've got a JComponent class called LifeDraw, which displays a grid of pixels, with the following paint method:

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

    for (int y = 0; y < lGrid.getHeight(); y++) {
        for (int x = 0; x < lGrid.getWidth(); x++) {
            if (lGrid.getCell(x,y) == 1) {
                g.setColor(Color.red);
                g.fillRect(x * lGrid.getSqSize(), y * lGrid.getSqSize(), lGrid.getSqSize(), lGrid.getSqSize());
            } else {
                g.setColor(Color.white);
                g.fillRect(x * lGrid.getSqSize(), y * lGrid.getSqSize(), lGrid.getSqSize(), lGrid.getSqSize());
            }
        }
    }
}

And then another class LifeGrid that has a method run(), which when called will update the grid of pixels for one generation and then call LifeDraw.repaint(). However, if I try to call run() in a loop, the JComponent doesn't repaint until the loop is finished so all that is ever displayed is the first generation and the last one. I figured it was probably just updating too quickly to repaint, so I tried using Thread.sleep() between iterations but still had the same problem. Theoretically (or at least I was hoping it would), it should repaint the component between each iteration and display an animation of the pixels changing.

I'm not that well versed in Java GUI, so any help would be really appreciated. Hopefully I've explained it clearly enough, let me know otherwise!

CSchulz
  • 10,882
  • 11
  • 60
  • 114
Adam
  • 57
  • 1
  • 4
  • could be the same problem as here: http://stackoverflow.com/questions/1843677/why-does-invokelater-cause-my-jframe-not-to-display-correctly – user85421 Jan 06 '10 at 21:24

3 Answers3

1

I don't know if it would solve your problem, but you could try calling run() from a Timer instead of a simple for or while loop.

Tyler
  • 21,762
  • 11
  • 61
  • 90
  • Excellent, thank you! Works perfectly. Not entirely sure why it wasn't working, but I guess it had something to do with different threads sleeping while run() still processed the arrays. Thanks a lot :) – Adam Jan 06 '10 at 20:14
  • If that fixed the problem, then chances are your "run()" method or whatever was calling it was busy-waiting in the event loop. I assumed from the name that it was the run() method from a Runnable or Thread, but apparently not. – Paul Tomblin Jan 06 '10 at 20:32
1

Repaint has to be fired in the event loop, not in another thread.
Try replacing your call to repaint() with following code:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        repaint();
    }
}); 
Andy Hayden
  • 359,921
  • 101
  • 625
  • 535
Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • 1
    I thought you were supposed to call repaint() in any thread you want, and then it would cause paintComponent() to be called in the appropriate thread. Am I very mistaken? – Tyler Jan 06 '10 at 20:09
  • You could be right. I'm very overcautious about not doing GUI things outside the event loop. – Paul Tomblin Jan 06 '10 at 20:15
  • I think it's time I bought a book on Swing, there's far too much I don't know. Though I'm pretty sure that'll stay that way considering the size of Swing :) – Adam Jan 06 '10 at 20:20
1

From the JavaDocs for repaint():

Adds the specified region to the dirty region list if the component is showing. The component will be repainted after all of the currently pending events have been dispatched.

All repaint does is signal that the area needs repainting.
Try paintImmediately or update.

CSchulz
  • 10,882
  • 11
  • 60
  • 114
karoberts
  • 9,828
  • 4
  • 39
  • 39
  • Thanks a lot for the help; as above, using a Timer instead of loop/sleep() seemed to sort out the problem, but I'm keeping note of the other answers in case something else goes wrong! – Adam Jan 06 '10 at 20:17
  • 2
    In general, I've found that trying to solve Swing problems using Thread.sleep() is not a good idea. – Tyler Jan 06 '10 at 20:33