views:

552

answers:

8

I am making a program that shows cellular growth through an array. I have gotten it so when I press the start button, the array updates every 10 seconds in a while(true){} loop. The problem with that is I want to be able to stop the loop by pressing the pause button, but while in the loop, it wont let me use any of the controls. I need something other than a infinite loop in orer to refresh the frames.

I am a bit of a newbie, but I am in a java class at the moment. so I have some grasp of the language.

+1  A: 

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.

fuzzy lollipop
+8  A: 

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;
    }
}
Chris Kannon
+1 Very good answer
Helper Method
+1 glad to see that I don't need to write this myself ;-)
stacker
Since the setPaused and setEnabled should be called from other threads, you should make the enabled and paused booleans volatile, or synchronise when reading/setting them.
Paul Wagland
Paul, nice catch, edited.
Chris Kannon
That would consume a lot of resources if the app is paused for a long period of time ( 1 min for instance ) because the while loop will be running at full speed, only to set the thread to sleep for a millisecond and start it again. That would create 60,000 ( aprox ) unneeded invocations, only for a 1 minute stop.
OscarRyz
Actually, this is a very poor solution. When paused == true, where there is no work to be done, this code incurs two context switches (read: very expensive) every 1 ms (assuming that the OS could provide such accuracy and could keep up). The net effect would be a slowdown to other threads doing actual work.A better solution is to *wait* till the condition "paused == false" is true. Either with an old fashioned lock and Object#wait, #notify, or via a java.util.concurrent.locks.Lock/Condition and appropriate methods.Weird to see this solution got the most votes!
Dimitris Andreou
Paul Clapham's answer is much better. I'd be surprised if SWT didn't have a similar timer event if the app is done in that instead of swing.
Geoff Reedy
The wait period or lock can be handled many different ways. The sleep(1) could be made configurable, or as Dimitris commented could be locked until #notify(I like that method). In general the method above is an easy and generic way of handling a threaded process. I also would not argue the timer based solution below is a valid solution, as long as the asker is using Swing and 1 second updates are fast enough for him.
Chris Kannon
A: 

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...

Brian Knoblauch
A: 

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?

Chris
ahhhh, I am in a highschool java class as an elective, so my training is... minimal. I no what your saying, but I have absolutely no idea how to implement it into code. Thanks though.
Luke
A: 

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,

David Soroko
+2  A: 

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.

Paul Clapham
+1  A: 

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();
notnoop
+2  A: 
OscarRyz
Thank you, this is exactly what I need. I am having a little trouble getting it to work in my code because its set up a bit differently than yours. But 'll work on it Thanks
Luke
@Luke, I'm glad. You can mark my answer as accepted ( I'm telling you this because you're new to StackOverflow :P )
OscarRyz
HAha, alright. Is there a way I can send you my code? I am having the worst time figuring out how to get what you gave me into my code? I understand thats a lot to ask of a stranger, so no worries if thats too much.
Luke
Sure, but, I think it will be much better if you create a new question here. I can take a look at that or any other. Phrase it like: *I asked this <link to this question> and I'm having this problem to make it work ( describe specific problem you're having ). I would like to work as Oscar's solution, but my code is not working. My code is here <link to pastebin.com> )* If you you have several questions, post each one on each. i think you'll have better chance to get it work.
OscarRyz