Java, replacement for infinite loops?

拟墨画扇 提交于 2019-12-01 04:37:33
OscarRyz

What you need is use a Timer which changes the state of your component ( in this case the cellular growth ) and then call JComponent.repaint()

This timer can be cancelled to make the pause and then to restart it, you just create a new one:

So you could define the following two methods:

private Timer timer;
...
public void startPaiting() {
    timer = new Timer();
    timer.schedule( new TimerTask(){
        public void run(){
            changeState();
            repaint();
        }
    },0,  10000 ); // 10 s. 
}

public void pause(){
    timer.cancel();
}

And then in your "Pause/Resume" button invoke this "pause/startPaiting" methods:

if( e.getActionCommand().equals("Pause")){
    growPanel.pause();
    setText("Resume");
} else {
    growPanel.startPaiting();
    setText("Pause");
}

Here's the complete source code to see it running:

import javax.swing.*;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;

public class Grow {

    public static void main( String [] args ) {
        JFrame frame = new JFrame();
        final GrowPanel growPanel = new GrowPanel();
        frame.add( growPanel );
        frame.add( new JPanel(){{
            add( new JButton("Pause"){{
                addActionListener( new ActionListener(){
                    public void actionPerformed( ActionEvent e ){
                        if( e.getActionCommand().equals("Pause")){
                            growPanel.pause();
                            setText("Resume");
                        } else {
                            growPanel.startPaiting();
                            setText("Pause");
                        }
                    }
                });
        }});}}, java.awt.BorderLayout.SOUTH );
        frame.setSize( 400, 300 );
        frame.setVisible( true );
    }
}

class GrowPanel extends JComponent {
    private int x;
    private int y;
    private Timer timer;
    GrowPanel() {
        x = 10;
        y = 10;
        startPaiting();
    }

    public void startPaiting() {
        timer = new Timer();
        timer.schedule( new TimerTask(){
            public void run(){
                changeState();
                repaint();
            }
        },0,  100 ); // or 10000 which is 10 s. 
    }

    public void pause(){
        timer.cancel();
    }

    public void paintComponent( Graphics g ){
        g.fillOval( x, y, 10, 10 );
    }
    private void changeState(){
            x+=10;
            if( x >= 400 ) {
                y+=10;
                x = 0;
            }
            if( y >= 300 ){
                y = 10;
            }
    }

}

I would suggest using a seperate thread to handle the array. Make sure you are using thread safe object (check Java Docs) and simply call .start() on your thread object when you want to start. Keep a pointer to it so you can pause it via setPaused(true)

Something like this....

class MyArrayUpdater extends Thread {
    private volatile boolean enabled = true;
    private volatile boolean paused = true;

    @Override
    public void run() {
        super.run();
        try {
            while (enabled) {
                if (!paused) {
                    // Do stuff to your array here.....
                }
                Thread.sleep(1);
            }
        } catch (InterruptedException ex) {
            // handle ex
        }
    }

    public void setEnabled(boolean arg) {
        enabled = arg;
    }

    public void setPaused(boolean arg) {
        paused = arg;
    }
}

If those "buttons" are Swing buttons, then the way to do this is: have the Start button create a new javax.swing.Timer object which does the update every 10 seconds. Then have the Pause button stop that timer.

You want to run your simulation in a Thread ( Look for Runnable Interface ). Then you can pass messages to this Thread to pause, continue and stop.

I personally prefer using the Timer class rather than Thread or Thread.sleep(). The timer class handles both running the code periodically and canceling it.

Your code would look like:

TimerTask myTask = new TimerTask() {
  public void run() {
    // here goes my code
  }
};

Timer timer = new Timer();
timer.schedule(myTask, 0 /*starts now*/, 10 * 1000 /* every 10 seconds */);

// whenever you need to cancel it:
timer.cancel();

Yep. Sounds like you're doing your drawing on the event dispatcher thread. Events (button presses) never have a chance to get called because you've never returned control from the last time it was called...

What you're looking for is multi-threading. Take the data processing and put it in a second thread, run it asynchronously, and use the main thread to check for user input.

Of course this might also entail using a semaphore to communicate between the two threads. What level class are you in - have you covered both of these topics already?

Take a look at the wait() / notify() machinery. Briefly, a thread can wait for 10 seconds, but still be notified that an external event has occurred,

Another way to handle this problem is by using BlockingQueue of jobs.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!