David Aaron
David Aaron

Reputation: 13

Java, force program to wait for click inside while loop

Okay so this isn't great code, but basically I need to force a more complicated version of this program to wait for a click while inside of a while loop. Any help on making the waitForClick() method below would be awesome. All that is supposed to happen is that the user clicks the JButton finish, and the program will set condition to false, and print "Done".

public class GUI extends JFrame {

private static final long serialVersionUID = 3560258176733156660L;

public static void main(String[] args) {
    new GUI().setVisible(true);
}

private JButton finish;
private boolean condition;

public GUI() {
    condition = true;
    setLayout(null);
    setSize(250, 120);
    setTitle("Silly");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    finish = new JButton("Finish");
    finish.setBounds(50, 40, 100, 30);
    finish.addMouseListener(new MouseClickListener());
    add(finish);
    doThings();

}
public void doThings() {
    while (condition) {
        waitForClick();
    }
    System.out.println("Done");
}

public void waitForClick() {
    // Need this method to make program wait for the Listener below, don't know how to do this!

}

public class MouseClickListener implements MouseListener {

    public void mouseClicked(MouseEvent arg0) {

        if (arg0.getSource()==finish) {
            condition = false;
        }

    }

    @Override
    public void mouseEntered(MouseEvent arg0) {

    }

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

    }

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

    }

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

    }

}

}

Upvotes: 0

Views: 3528

Answers (2)

Joe
Joe

Reputation: 86

Check out http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.concurrent.CountDownLatch;

import javax.swing.JButton;
import javax.swing.JFrame;

public class GUI extends JFrame implements ActionListener {

    private static final long serialVersionUID = 3560258176733156660L;

    public static void main(String[] args) {
        new GUI().setVisible(true);
    }

    private JButton finish;
    private boolean condition;

    private CountDownLatch startSignal = new CountDownLatch(1);
    private CountDownLatch doneSignal = new CountDownLatch(1);

    public Main() {
        condition = true;
        setLayout(null);
        setSize(250, 120);
        setTitle("Silly");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        finish = new JButton("Finish");
        finish.setBounds(50, 40, 100, 30);
        finish.addActionListener(this);
        add(finish);
        //doThings();//Probably better not to put this here.
        // If you need to do things on the button click simply place doThings() in the action listener.
    }

    public void doThings() {
        new Thread(new Worker(startSignal, doneSignal)).start();
        startSignal.countDown(); 
        waitForClick();
        System.out.println("Done");
        System.exit(0);
    }

    public void waitForClick() {
         try {
            doneSignal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        if (arg0.getSource()==finish) {
            condition = false;
            doThings();
        }
    }

         class Worker implements Runnable {
           private final CountDownLatch startSignal;
           private final CountDownLatch doneSignal;
           public Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
              this.startSignal = startSignal;
              this.doneSignal = doneSignal;
           }
           public void run() {
              try {
                startSignal.await();
                doWork();
                doneSignal.countDown();
              } catch (InterruptedException ex) {} // return;
           }

           void doWork() {
               // Do work here before finish
               for (int i = 0; i < 10000; i++) {
                   System.out.println("Running..." + Math.pow(i, i));
               }
           }
         }

}

Upvotes: 0

Robin
Robin

Reputation: 36621

What you want to do is not possible.

Swing is single-threaded. So if you have an infinite loop running on that single thread (the EDT), your UI gets blocked and will not even be capable of handling that mouse click.

So what are your possibilities:

  • Let your loop run on another thread. The Swing thread is then available to handle the mouse event, and you can adjust the flag from the EDT. Since you are then accessing the same flag from multiple threads, consider using the AtomicBoolean. This is of course only an option if your loop actually has to do something. If you just want to wait, see the next option.
  • Do not try to wait but react on the event instead. In the code you posted you can simply remove the call to doThings from the constructor. The MouseClickListener would then call doThings, and you can remove the waiting loop from the doThings method.

Apart from that, I would strongly suggest to get rid of the null layout and switch to a real LayoutManager

Upvotes: 3

Related Questions