Can't press JButton while in loop

I'm trying to make a program that generates random numbers if the user presses a button. It should stop generating them, when the user presses the button the second time, and then it should print all the random numbers added together and the average random number, but I don't know how I should do this. When I'm in the loop i can't press the button. I'll be thankful for any help. My Code:

package Test;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class Average

{

static int sizeX = 200;
static int sizeY = 200;
static int maxNum = 100;
static int minNum = 1;
static boolean running = true;

static JButton b1 = new JButton("Click me");

static void JFrame()

{

     Toolkit tk = Toolkit.getDefaultToolkit();
      Dimension dim = tk.getScreenSize();

    JFrame f = new JFrame("Test");
    f.setSize(sizeX, sizeY);
    f.setVisible(true);
    f.setLocation((dim.width - sizeX) / 2, (dim.height - sizeY) / 2);
    f.setResizable(false);
    f.setAutoRequestFocus(true);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    f.add(b1);

}

static void ActionListener()

{

    b1.addActionListener(new ActionListener()//ActionListener

    {

      public void actionPerformed(ActionEvent e)//Execute when button is pressed

      {

            int numsGenerated = 0;
            double ave = 0;

            if (running == true)

            {

                while (true)

                {

                    double r = Math.random() * (maxNum - minNum) + minNum; //(maxNum - minNum) + minNum
                    numsGenerated++;

                      ave = ave + r;

                          System.out.println("Random: " + r);   

                          if (!running)

                          {

                              break;

                          }

                }

                running = false;

            }

            else

                {

                  System.out.println("");
                  System.out.println("All: " + ave);
                  System.out.println("Average: " + ave / numsGenerated);

                running = true;

                }

      }


    }); //ActionListenerEnd

}

  public static void main(String[] args)//Main

  {

  JFrame();
  ActionListener();

  }

}

Upvotes: 0

Views: 1513

Answers (1)

huseyin tugrul buyukisik
huseyin tugrul buyukisik

Reputation: 11910

As Ordous told in a comment, you should make a different thread for this work. But you may need to synchronize on "running" variable to make sure it works always.

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class Average    
{
static Object lock=new Object();
static int sizeX = 200;
static int sizeY = 200;
static int maxNum = 100;
static int minNum = 1;
static boolean running = false;    
static JButton b1 = new JButton("Click me");    
static void JFrame()   
{   
     Toolkit tk = Toolkit.getDefaultToolkit();
      Dimension dim = tk.getScreenSize();  
    JFrame f = new JFrame("Test");
    f.setSize(sizeX, sizeY);
    f.setVisible(true);
    f.setLocation((dim.width - sizeX) / 2, (dim.height - sizeY) / 2);
    f.setResizable(false);
    f.setAutoRequestFocus(true);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
    f.add(b1);

}

public class Thr extends Thread
{       
    @Override 
    public void run()
    {
          int numsGenerated = 0;
          double ave = 0;
          synchronized(lock)
          {
              running=!running;
          }
          if (running == true)
          {
              while (true)    
              {

                  double r = Math.random() * (maxNum - minNum) + minNum; //(maxNum - minNum) + minNum
                  numsGenerated++;    
                    ave = ave + r;    
                        System.out.println("Random: " + r);   
                        synchronized(lock)
                        {
                            if (!running)
                            {
                                break;
                            }
                        }
              }                  
              synchronized(lock)
              {
                  running = false;
              }
          }                 
              System.out.println("");
              System.out.println("All: " + ave);
              System.out.println("Average: " + ave / numsGenerated);
              running = true;       
    }   
}
static Thr thread=null;
static void ActionListener()    
{  
    b1.addActionListener(new ActionListener()//ActionListener  
    {    
      public void actionPerformed(ActionEvent e)//Execute when button is pressed

      {
          Average av=new Average();
          if(thread==null)
          {
               thread=av.new Thr(); // should add in an executor
               thread.start();
          }
          else
          {
              synchronized(lock)
              {
                  running=false;
              }
          }
      }


    }); //ActionListenerEnd    
}

  public static void main(String[] args)//Main    
  {    
      JFrame();
      ActionListener();    
  }    
}

To have a simple thread, "Thread" is inherited and run() methoud must be overridden to use it. (you can use a "Runnable" instead of this too)

public class Thr extends Thread
{       
    @Override 
    public void run()
    {

    }   
}

You start it like

threadName.Start() 

or

ExecutorObject.submit(threadName);

where executor object has a pool for threads to run efficiently and is created by executor service.

Do not start threads with

  threadname.run()

directly.

Also inter-thread communication is important. One thread leaves a message to somewhere, another thread reads. If there is no synchronization, they can race for the variable's visibility and wrong output can happen.

You can have an object to lock on.

  synchronized(lock)
  {

  }

so this block can be entered by only single thread until it exits from this block. You should leave a message for other threads, to say "its ready" and wake them up(iff they are waiting) with

  synchronized(lock)
  {
           lock.notifyAll();
  }

then make the message-leaving thread (current thread) go on a waiting state so other threads can wake it up and let it exit the block.

  synchronized(lock)
  {
           lock.notifyAll();
           lock.wait();
  }

but this alone is not enough because current thread accidentally exit the waiting state so you may force it to keep waiting:

  synchronized(lock)
  {
           lock.notifyAll();
           while(condition)
                lock.wait();
  }

if you make sure only a single thread can access a variable at a time, you can use it to communicate with other threads.

You can use some other ways to have barriers to synchronize all threads on a point so no threads can continue until all hit the same barrier. More communication can decrease overall performance.

Main program is a thread too, so it can wait, notify and synchronize.

Upvotes: 2

Related Questions