Thread.sleep()崩溃了我的GUI

时间:2017-07-28 05:13:35

标签: java user-interface

我的ButtonListener类中的My Thread.sleep(rand.nextInt(delay))命令崩溃了我的GUI。有任何想法吗?该程序应该将人们添加到ArrayList,然后随机选择它们并在0和timeText JTextField之间的随机时间显示它们,直到我添加sleep命令。任何帮助将不胜感激!

import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import javax.swing.Timer;

public class MyProgram extends AppClass{
  protected int x,y,width,height;
  protected Color color;
  private ArrayList<String> people = new ArrayList<String>(); 
  private static JLabel person;
  private Timer timer;
  private ButtonListener listener;
  private Random rand = new Random();
  private JLabel addPeople;
  private JTextField newPerson;
  private JTextField timeText;

  private Font font1 = new Font("Arial",1,17);
  private Font font2 = new Font("Arial",1,65);

  public MyProgram(){
    setPreferredSize(new Dimension(1000,800));

    people.add("me");
    people.add("john");
    people.add("greg");

    JPanel panel = new JPanel();
    panel.setPreferredSize(new Dimension(600,400));
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

    newPerson = new JTextField(2);
    newPerson.setFont(font1);
    addPeople = new JLabel("Add people:");
    addPeople.setFont(font1);
    person = new JLabel();
    person.setFont(font2);
    JButton addButton = new JButton("Add");
    addButton.setFont(font1);
    JButton startButton = new JButton("Start");
    startButton.setFont(font1);
    timeText = new JTextField(2);
    timeText.setFont(font1);
    JLabel time = new JLabel("Maximum time between draws:");
    time.setFont(font1);

    listener = new ButtonListener();
    addButton.addActionListener(listener);
    startButton.addActionListener(listener);

    panel.add(addPeople);
    panel.add(newPerson);
    panel.add(addButton);
    panel.add(time);
    panel.add(timeText);
    panel.add(startButton);
    panel.add(person);

    add(panel);
  }

  private class ButtonListener implements ActionListener{

    public void actionPerformed(ActionEvent ae){
      JButton button = (JButton) ae.getSource();

      if(button.getText().equals("Add")){
        people.add(newPerson.getText());
        System.out.println(newPerson.getText());
        System.out.println("also worked");

      }else if(button.getText().equals("Start")){
        int delay = Integer.parseInt(timeText.getText());
        for(;;){
        person.setText(people.get(rand.nextInt(people.size())));
        try{
        Thread.sleep(rand.nextInt(delay)); // the problem
      }catch(Exception error){
        System.out.println("Error");
      }
          }
      }
    }
  }
  }
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import javax.swing.Timer;

public class AppClass extends JPanel{

  public static void main(String [] args){
    JFrame frame = new JFrame();
    frame.getContentPane().add(new Get());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
    frame.setTitle("My Program");

   }
}

2 个答案:

答案 0 :(得分:0)

只有一个线程可以修改UI。这是设计使然,因为它意味着,即使UI可以接收许多事件源,并发错误也不可能破坏UI状态。

只有一个线程可以修改UI。这包括:

  • 接收鼠标事件。
  • 接收键盘事件。
  • 处理要重新绘制的请求。
  • 处理UI计时器。

其他许多人。

如果你在修改UI的代码中,那么你必须在UI线程上(否则,你有一个bug)。如果您在UI线程上并且调用Sleep(),那么UI线程将停止执行操作。

它会停止响应重绘请求。它将停止响应键盘事件,鼠标事件等。

相反,您必须使用表单计时器来执行动画。当有人点击您的&#34;开始&#34;按钮,你将设置第一个值,保存其余的值,然后启动你的计时器,然后让UI线程继续处理。

每次计时器触发时,都会提前状态 - 您使用要显示的下一个值更新UI。你继续这个直到你显示了所有的值,然后停止计时器并释放你的状态,告诉你你在动画中的位置。

是的,您只是在某个组件上设置文本,但这仍属于动画模式。

但请注意 - 如果您的UI在动画计时器仍在运行时关闭,您将尝试修改已消失的UI。所以现在你的UI代码必须小心停止动画计时器,如果它在UI关闭时仍在运行。

答案 1 :(得分:-1)

实际上,你是在同一个线程中执行你的gui,当你使用Thread.sleep(delay)时,你也会睡觉。所以你必须使用新线程进行其他处理。

Thread t = new Thread(new Runnable(){
    @Override
    public void run() {
    }
});