【问题标题】:Can't press JButton while in loop在循环中无法按 JButton
【发布时间】:2015-01-16 19:27:09
【问题描述】:

我正在尝试制作一个在用户按下按钮时生成随机数的程序。当用户第二次按下按钮时,它应该停止生成它们,然后它应该打印所有加在一起的随机数和平均随机数,但我不知道该怎么做。当我在循环中时,我无法按下按钮。我会感谢任何帮助。我的代码:

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();

  }

}

【问题讨论】:

  • if (running = false) -> if (running == false)。或者更好,if(!running)
  • 因为你占用了 EDT。我已经为此写了很多次答案并投​​票赞成。不要在 EDT 中循环!使用不同的线程或TimerThe official Oracle lesson on the EDT 正是如此 - Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive. 我强烈建议您阅读整个教程,以熟悉 EDT 工作原理的基础知识。

标签: java multithreading swing loops jbutton


【解决方案1】:

正如 Ordous 在评论中所说,您应该为这项工作创建一个不同的线程。但是您可能需要同步“运行”变量以确保它始终有效。

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();    
  }    
}

要拥有一个简单的线程,“线程”是继承的,并且必须重写 run() 方法才能使用它。 (您也可以使用“Runnable”代替它)

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

    }   
}

你开始吧

threadName.Start() 

ExecutorObject.submit(threadName);

其中 executor 对象有一个用于线程高效运行的池,并由 executor 服务创建。

不要以

开始线程
  threadname.run()

直接。

线程间通信也很重要。一个线程向某处留言,另一个线程读取。如果没有同步,他们可能会争夺变量的可见性,并且可能会发生错误的输出。

您可以锁定一个对象。

  synchronized(lock)
  {

  }

所以这个块只能由单个线程进入,直到它退出这个块。你应该给其他线程留言,说“它准备好了”并唤醒他们(如果他们正在等待)

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

然后让消息离开线程(当前线程)进入等待状态,以便其他线程可以唤醒它并让它退出块。

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

但仅此还不够,因为当前线程意外退出等待状态,因此您可能会强制它继续等待:

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

如果您确保一次只有一个线程可以访问一个变量,您可以使用它与其他线程进行通信。

您可以使用其他一些方法来设置屏障来同步一个点上的所有线程,这样在所有线程都遇到相同的屏障之前,没有线程可以继续。更多的沟通会降低整体性能。

主程序也是一个线程,所以它可以等待、通知和同步。

【讨论】:

  • 你能告诉我你是如何创建一个新线程的吗?我是 Java 新手,想知道这一点
猜你喜欢
  • 2020-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-11
  • 1970-01-01
  • 2021-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多