Java - repaint JPanel 2 times in one method - java

This is simple version of my problem.
I have 3 classes:
public class TopographyFrame extends JFrame - simple JFrame with JPAnel and button
public class TopograpyPanel extends JPanel - JPanel to fill Rectangles
public class Siec - class to perform calculations and call repaint on JPAnale
in JPanel i overided paintComponent() method
public void paintComponent (Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
System.out.println(rectangles.length);
for(int i = 0 ; i < rectangles.length ; i++){
g2.setPaint(neurony[i].winner);
g2.fillRect((int)rectangles[i].x,(int)rectangles[i].y,(int)rectangles[i].width, (int)rectangles[i].height);
}
}
neurony - array of objects with field public Color winner
in class Siec i have reference to JPanel to repaint it
in class JFrame i have a button with private action listener:
class MyListener implements ActionListener{
Siec s;
public MyListener(Siec s){
this.s = s;
}
public void actionPerformed(ActionEvent arg0) {
try {
s.forPaint();
} catch (Exception e) {
e.printStackTrace();
}
}
method forPaint() in Siec looks like:
public void forPaint(){
setTopography();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setTopography();
}
public void setTopography() {
for (int i = 0; i < vector.colors.length; i++) {
neurony[i].winner = vector.colors[(int)(random() * 900 % vector.colors.length)];
}
panel.repaint();
}
vector.color is array of Colors
So my problem is: when i click a button i would like to JPanel repaint immediately and then after 3 second repaint one more time. Insted JPanel repaints only one time after 3s delay.
}

You can't sleep, wait, or otherwise pause on the event handling thread, ever. Doing so blocks all events from being processed, including painting events. Your first painting can't occur because you're sleeping on the event thread, preventing it from happening.
The right way to do any kind of animation -- even simple stuff like this -- is to create your own thread. That second thread can call repaint(), sleep for 3 seconds, then call repaint() again. The SwingWorker class is nominally a simpler way to do this, but in all honesty, beginners always find creating their own thread to be easier.

You are scheduling a repaint on the UI thread and then sleeping (blocking) the UI thread for 3seconds and then requesting another repaint again. Those two will either happen really close to each other after this method has finished (after 3 seconds) or be merged into one update (afterwards as well).
Instead of sleep(3000) and then calling your setTopography again you could schedule a setTopography call on the UI thread to happen after 3 seconds.
Have a look at the Swing Timer for example:
http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
So something along the lines of:
javax.swing.Timer timer = new javax.swing.Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
setTopography();
}
});
timer.setRepeats(false);
timer.start();

Since your sleep is being performed on the Event Dispatch Thread, the repaint() event cannot be performed until the end of the wait. Do this instead:
private Timer timer = new Timer(); // use java.util.Timer
public void forPaint() {
setTopography();
timer.schedule(new TimerTask() {
#Override
public void run() {
setTopography();
}
}, 3000);
}
public void setTopography() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
for (int i = 0; i < vector.colors.length; i++) {
neurony[i].winner = vector.colors[(int)(random() * 900 % vector.colors.length)];
}
panel.repaint();
}
});
}
Keep in mind that all modifications to a Swing component (e.g. your JPanel) must happen on the EDT.

Related

Java game loop (painting) freezes my window

I'm changing "views" with cardLayout (this class has a JFrame variable). When a user clicks a new game button this happens:
public class Views extends JFrame implements ActionListener {
private JFrame frame;
private CardLayout cl;
private JPanel cards;
private Game game;
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("New game")) {
cl.show(cards, "Game");
game.init();
this.revalidate();
this.repaint();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
game.loop();
}
});
}
}
}
Game's loop method and heading of class:
public class Game extends JPanel implements KeyListener {
public void loop() {
while (player.isAlive()) {
try {
this.update();
this.repaint();
// first class JFrame variable
jframee.getFrame().repaint();
// first class JFrame variable
jframee.getFrame().revalidate();
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void update() {
System.out.println("updated");
}
}
I'm painting using paintComponent()
public void paintComponent(Graphics g) {
System.out.println("paint");
...
}
Actually it's not painting anything. When I do not call loop() method (so it paints it just once) all images are painted correctly. But when I call loop() method, just nothing is happening in the window. (Even close button on JFrame doesn't work.)
How to fix that? (When I was creating JFrame inside game class everything worked fine, but now I want to have more views so I need JFrame in other class.)
Thanks.
Precursor: The Event Dispatch Thread (EDT).
Swing is single-threaded. What does this mean?
All processing in a Swing program begins with an event. The EDT is a thread that processes these events in a loop along the following lines (but more complicated):
class EventDispatchThread extends Thread {
Queue<AWTEvent> queue = ...;
void postEvent(AWTEvent anEvent) {
queue.add(anEvent);
}
#Override
public void run() {
while (true) {
AWTEvent nextEvent = queue.poll();
if (nextEvent != null) {
processEvent(nextEvent);
}
}
}
void processEvent(AWTEvent theEvent) {
// calls e.g.
// ActionListener.actionPerformed,
// JComponent.paintComponent,
// Runnable.run,
// etc...
}
}
The dispatch thread is hidden from us through abstraction: we generally only write listener callbacks.
Clicking a button posts an event (in native code): when the event is processed, actionPerformed is called on the EDT.
Calling repaint posts an event: when the event is processed, paintComponent is called on the EDT.
Calling invokeLater posts an event: when the event is processed, run is called on the EDT.
Everything in Swing begins with an event.
Event tasks are processed in sequence, in the order they are posted.
The next event can only be processed when the current event task returns. This is why we cannot have an infinite loop on the EDT. actionPerformed (or run, as in your edit) never returns, so the calls to repaint post paint events but they are never processed and the program appears to freeze.
This is what it means to "block" the EDT.
There are basically two ways to do animation in a Swing program:
Use a Thread (or a SwingWorker).
The benefit to using a thread is that the processing is done off the EDT, so if there is intensive processing, the GUI can still update concurrently.
Use a javax.swing.Timer.
The benefit to using a timer is that the processing is done on the EDT, so there is no worry about synchronization, and it is safe to change the state of the GUI components.
Generally speaking, we should only use a thread in a Swing program if there's a reason to not use a timer.
To the user, there is no discernible difference between them.
Your call to revalidate indicates to me that you are modifying the state of the components in the loop (adding, removing, changing locations, etc.). This is not necessarily safe to do off the EDT. If you are modifying the state of the components, it is a compelling reason to use a timer, not a thread. Using a thread without proper synchronization can lead to subtle bugs that are difficult to diagnose. See Memory Consistency Errors.
In some cases, operations on a component are done under a tree lock (Swing makes sure they are thread-safe on their own), but in some cases they are not.
We can turn a loop of the following form:
while ( condition() ) {
body();
Thread.sleep( time );
}
in to a Timer of the following form:
new Timer(( time ), new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if ( condition() ) {
body();
} else {
Timer self = (Timer) evt.getSource();
self.stop();
}
}
}).start();
Here is a simple example demonstrating animation both with a thread and a timer. The green bar moves cyclically across the black panel.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class SwingAnimation implements Runnable{
public static void main(String[] args) {
SwingUtilities.invokeLater(new SwingAnimation());
}
JToggleButton play;
AnimationPanel animation;
#Override
public void run() {
JFrame frame = new JFrame("Simple Animation");
JPanel content = new JPanel(new BorderLayout());
play = new JToggleButton("Play");
content.add(play, BorderLayout.NORTH);
animation = new AnimationPanel(500, 50);
content.add(animation, BorderLayout.CENTER);
// 'true' to use a Thread
// 'false' to use a Timer
if (false) {
play.addActionListener(new ThreadAnimator());
} else {
play.addActionListener(new TimerAnimator());
}
frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
abstract class Animator implements ActionListener {
final int period = ( 1000 / 60 );
#Override
public void actionPerformed(ActionEvent ae) {
if (play.isSelected()) {
start();
} else {
stop();
}
}
abstract void start();
abstract void stop();
void animate() {
int workingPos = animation.barPosition;
++workingPos;
if (workingPos >= animation.getWidth()) {
workingPos = 0;
}
animation.barPosition = workingPos;
animation.repaint();
}
}
class ThreadAnimator extends Animator {
volatile boolean isRunning;
Runnable loop = new Runnable() {
#Override
public void run() {
try {
while (isRunning) {
animate();
Thread.sleep(period);
}
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
};
#Override
void start() {
isRunning = true;
new Thread(loop).start();
}
#Override
void stop() {
isRunning = false;
}
}
class TimerAnimator extends Animator {
Timer timer = new Timer(period, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
animate();
}
});
#Override
void start() {
timer.start();
}
#Override
void stop() {
timer.stop();
}
}
static class AnimationPanel extends JPanel {
final int barWidth = 10;
volatile int barPosition;
AnimationPanel(int width, int height) {
setPreferredSize(new Dimension(width, height));
setBackground(Color.BLACK);
barPosition = ( width / 2 ) - ( barWidth / 2 );
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int currentPos = barPosition;
g.setColor(Color.GREEN);
g.fillRect(currentPos, 0, barWidth, height);
if ( (currentPos + barWidth) >= width ) {
g.fillRect(currentPos - width, 0, barWidth, height);
}
}
}
}
What does update do? You probably shouldnt call game.loop() on the EDT. You are running a loop on EDT, your repaint wont ever be invoked since repaint queues an event on EDT and it seems kind busy. Try moving game.loop() to another thread
new Thread(new Runnable() {
#override
public void run() {
game.loop();
}
}).start();
This way you wont block the EDT while the repaint still gets to be executed on the EDT.
Move game.loop() method invocation to something like:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
game.loop()
}
});
Thanks.

JFrame will not close when "X" button is clicked

The JFrame will not shut down when the default "X" button is clicked. I think this problem has something to do with the main thread not being read, but I don't understand the intricacies of swing or honestly, threads in general. "Window" is an extension of JFrame, "Boxy" drives the program. Program is only in initial stages. Also, I'd like to know how to get the main thread run on every loop-over. Couldn't find anything about this in other questions.
public class Window extends JFrame implements KeyListener{
private static final long serialVersionUID = 1L;
JPanel panel;
public Window(){
super("FileTyper");
super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
super.setSize(200,100);
super.setResizable(false);
panel = new JPanel();
super.getContentPane().add(panel);
super.setFocusable(true);
addKeyListener(this);
super.setVisible(true);
}
public void update(){
}
public void render(Graphics2D g){
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_F9:
break;
case KeyEvent.VK_F10:
break;
}
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
public class Boxy {
public Window window;
public static void main (String args[]){
start();
}
public Boxy(){
init();
boolean forever = true;
while(forever){
update();
render();
delay();
}
}
private void init(){
window = new Window();
}
private void update(){
window.update();
}
private void render(){
Graphics2D g2 = (Graphics2D) window.getContentPane().getGraphics();
window.render(g2);
g2.fillRect(0, 0, 100, 100);
}
private void delay(){
try {Thread.sleep(20);} catch (InterruptedException ex) {System.out.println("ERROR: Delay compromised");}
}
public static void start(){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Boxy box = new Boxy();
}
});
}
}
I would suggest that you are blocking the Event Dispatching Thread with
while(forever){
update();
render();
delay();
}
This is preventing the Event Queue from processing the event that would close the window.
Start by taking a look at Concurrency in Swing. I would suggest you might like to take a look at something like javax.swing.Timer to start with, but if you want more control of the frame rate, you're going to need to use some kind of Thread. Remember though, Swing expects all updates to be executed from within the context of the Event Dispatching Thread.
Custom painting in Swing is not done by using something like...
Graphics2D g2 = (Graphics2D) window.getContentPane().getGraphics();
The Graphics context is short lived, anything your paint to it (using this method) will be destroyed on the next paint cycle.
Instead, you should use something like a JPanel as the bases for your painting and override it's paintComponent method and render the state from within it, when ever it is called.
You would then simply need to call repaint when you want to update the component.
Take a look at Performing Custom Painting for more details.
I would also recommend that you take a look at How to use Key Bindings as an aletrnative to KeyListener
Your program's "game" loop is incorrect:
while(forever){
update();
render();
delay();
}
Rather than looping the program, it freezes it by tying up the Swing event thread or EDT (for Event Dispatch Thread). You should use a Swing Timer instead for this functionality.

I am trying to move a ball in applet using thread but its not moving

I am trying to move a ball in applet using thread but its not moving. Can anyone help me out as m new to applet and proceeding for game development..for reference here is my code
public class ballGame extends JApplet implements Runnable
{
int x_pos=50;
int y_pos=100;
int rad=10;
Thread t;
public void start()
{
super.start();
t=new Thread("t");
t.start();
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
setBackground(Color.BLACK);
g.drawOval(x_pos,y_pos,2*rad,2*rad);
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}//end of paint()
}
Swing is a single thread environment. That is, all updates and interactions are executed within a single thread. Swing is also NOT thread safe. This means that all updates to the UI MUST be executed within the context of that thread (the Event Dispatching Thread or ETD).
Any code that blocks the EDT will prevent it from (amongst other things), repainting the UI and responding to input from the user.
You're paint code will NEVER update the screen, in fact it will make your application appear to "hang", as the paint method isn't being allowed to complete and is blocking the ETD.
It is an exception that the paint method will return quickly after been called and may be called repeatedly in quick succession.
Generally speaking, a Thread is probably a little over kill, something like a javax.swing.Timer would be more then suitable under these circumstances.
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
As a side note. You should rarely need to override the paint method of a top level container like JApplet or JFrame, while there are a number of good reasons for this, the one that you're going to most interested in is the fact that they're not double buffered, meaning you are likely to see flickering as the screen is updated.
It's better to use something like JPanel and override it's paintComponent method instead.
Take a look at
Performing Custom Painting
Concurrency in Swing
Painting in AWT and Swing
For more information
nb
While I've used a JFrame for my example, it would be a simple matter to take the animation panel and put it into a JApplet, this is another reasons why you don't need/want to extend from top level containers ;)
Having an infinite loop in paint means that not a single pass of the method can complete.
Also you should never call Thread.sleep(100) in the paint method. This blocks the EDT and degrades performance.
Instead use a Swing Timer to do the update and repainting work. Also I would sub-class a JComponent and override paintComponent.
You can not invoke repaint() method inside paint(). And you can not organize infinitely loop inside paint() method - doing so, you are blocking drawing in your applet.
x_posis an int value, thus it is passed to methods by value, not by reference. That is why, when you change its value, the value inside of your circle is not updated...
You create a Thread without a run() method. This method should contain the runnable code... Furthermore, the paint() method is to paint stuff, not update stuff!
So move your while loop from the paint() method into the run() method of your thread:
t=new Thread("t") {
#Override
public void run()
{
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}
};
Note that ballGame does not require the implement Runnable part. As the thread you created will provide it.
Have the while loop inside the run method of Runnable.
UPDATE:
Have this in the start method.
t=new Thread(this);
t.start();

Combining repaint() with Thread.Sleep()

What im trying to do is pretty simple, I want to show the steps of an algorithm on the screen, hence why im trying to combine repaint() with sleep(), but I am doing it wrong, Id love it if someone knows enough about it to firstly explain whats wrong with this code, and secondly, what do i do to make it work...
thanks!
in summery, what this code was meant to do is paint 10 red vertices, then balcken em one by one in intervals of 200 milliseconds.
here's the code:
public class Tester {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ShowGUIGraph();
}
});
}
private static void ShowGUIGraph() {
JFrame f = new JFrame("something");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p=new JPanel();
p.setLayout(new BorderLayout());
p.add(BorderLayout.CENTER,new SomePanel());
f.add(p);
f.setPreferredSize(new Dimension(800,600));
f.pack();
f.setVisible(true);
}
}
public class SomePanel extends JPanel {
private static final long serialVersionUID = 1L;
LinkedList<Vertex> vertices=new LinkedList<Vertex>();
public SomePanel () {
for (int i=0;i<10;i++) {
Vertex v=new Vertex(i);
v.setLocation(20+30*i, 20+30*i);
vertices.add(v);
}
traverseVerticesRecoursive(0);
traverseVerticesNonRecoursive();
}
public void traverseVerticesRecoursive(int i) {
if (i>=vertices.size()) return;
vertices.get(i).setColor(Color.black);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
repaint();
traverseVerticesRecoursive(i+1);
}
public void traverseVerticesNonRecoursive() {
for (int i=0;i<10;i++) {
vertices.get(i).setColor(Color.red);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i=0;i<vertices.size();i++) {
vertices.get(i).paintVertex(g);
}
}
}
public class Vertex {
private int x,y,tag,r=20;
private Color color=Color.red;
Vertex (int i) {
tag=i;
}
public void setLocation(int x0,int y0) {
x=x0;
y=y0;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setColor(Color c) {
color=c;
}
public boolean colorIs(Color c) {
return (color.equals(c));
}
public void paintVertex(Graphics g) {
g.setColor(color);
g.fillOval(x,y,r,r);
g.setColor(Color.BLACK);
g.drawOval(x,y,r,r);
g.drawString(""+tag, x+r/2, y+r/2+4);
}
public int getR() {
return r;
}
}
Do not sleep in the Event Dispatch Thread; this will cause the GUI to freeze. For animation, use an EDT-friendly utility class, such as javax.swing.Timer.
Just a few ideas that might make your code cleaner:
In your SomePanel class, put the traversing code in a method out of the constructor. Constructors are intended for initializing fields.
First launch your static GUI, then spawn a worker thread to do the updates via the previous method (this would be your small "engine"). In this thread is were you can call sleep.
In your traverseVerticesRecoursive method, do only the repaint on the UI thread, and the status update on your worker thread.
Tha main modification you should do is not to block the GUI thread with sleep calls, as they have told you in the first answer.
Thread.sleep is a long running task. When you a running such a task in the EDT it blocks all repaint requests from being executed. All repaint requests which are pending and which were sent during the sleep phase are queued for future processing.
As a result when the EDT comes out of the sleep phase it coalesce all such repaint request (if coalescing is enabled which is the default property) into a single repaint which gets executed. If coalescing is not enabled then all queued request are executed serially without any time gap in between. As a result it seems that the UI did not update.
To correct the situation use a timer which triggers periodically after specific intervals of time.
Guy, you could use a new Thread differ with EDT thread to make an animation. For example,
void play() {
Thread thread = new Thread() {
#Override
public void run() {
game();
}
};
thread.start();
}
void game() {
for (; ; ) {
switch (state) {
case GameData.ANIMATING:
// call some function as repaint() to update GUI
break;
case GameData.GAME_ENDED:
return;
default:
break;
}
diffTime = System.currentTimeMillis() - beforeTime;
sleepTime = delay - diffTime;
sleepTime = (sleepTime < 0) ? 0 : sleepTime;
Thread.sleep(sleepTime);
}
}

How do I make this java for loop pause for 1/2 a second between each iteration?

private class MultipleGensListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
for(int i = 0; i < 25; i++)
{
game.runSimulationOneGen();
changeGrid();
}
}
}
//this is the loop. The changeGrid method displays a game grid on a GUI but
// only the 25th iteration is visible on screen. I would like each one to be
// visible for about a half a second before the loop continues.
// I have seen some questions answered on here that are very close to what I'm asking,
// but I just don't really understand how to apply it to my program..
// thanks for any help.
If the code performed by the simulation is quick and does not consume too much CPU and time, then consider using a Swing Timer to do your looping and delay. Otherwise, you'll need to use a background thread such as can be done with a SwingWorker object.
For e.g. if using both Swing Timer and SwingWorker:
private class MultipleGensListener implements ActionListener {
protected static final int MAX_INDEX = 25;
public void actionPerformed(ActionEvent e) {
int timerDelay = 500; // ms delay
new Timer(timerDelay, new ActionListener() {
int index = 0;
public void actionPerformed(ActionEvent e) {
if (index < MAX_INDEX) { // loop only MAX_INDEX times
index++;
// create the SwingWorker and execute it
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
game.runSimulationOneGen(); // this is done in background thread.
return null;
}
#Override
protected void done() {
changeGrid(); // this is called on EDT after background thread done.
}
}.execute(); // execute the SwingWorker
} else {
((Timer) e.getSource()).stop(); // stop the timer
}
}
}).start(); // start the Swing timer
}
}
NEVER BLOCK THE GUI EVENT THREAD
you can use a timer for that and have it only fire 25 times
final Timer t = new Timer(500,null);
t.addActionListener(new ActionListener(){
int i=0;
public void actionPerformed(ActionEvent e){
game.runSimulationOneGen();//run 1 iteration per tick
changeGrid();
if(i>25){t.stop();}
i++;
}
});
t.setRepeats(true);
t.start();
btw the reason only the last iteration is shown is that gui updates (redraws) are done in a separate event, but to let another event trigger you need to return from the listener method which you didn't
the Timer I showed is a more elaborate iteration which lets other events run in between iterations allowing the gui to show the changes
check my post that shows both methods java.swing.Timer#setDelay(int)
and
correct usage of Thread.sleep(int)
java wait cursor display problem

Categories

Resources