2017-07-28 70 views
0

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

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

    } 
} 
+5

好吧,你正在让你的GUI睡觉 –

+0

相关:https://stackoverflow.com/questions/4215968/java-thread-sleep-puts-swing-ui-to-sleep-too(顺便说一句,你已经导入'javax .swing.Timer',为什么不使用它...) –

回答

-1

实际上,你执行你的GUI到同一个线程,当你使用Thread.sleep(delay)你还睡你的GUI。所以你必须使用新线程进行其他处理。

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

没有其他线程可以解决这个问题;需要使用UI定时器。引入其他线程只会导致UI并发错误,因为您违反了只有一个线程读取或写入整个UI的约束。 – antiduh

0

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

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

  • 接收鼠标事件。
  • 接收键盘事件。
  • 处理重绘请求。
  • 处理UI定时器。

等等。

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

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

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

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

是的,你只是在一些组件上设置文本,但这仍然属于动画模式。

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

+0

如何实现定时器?感谢您的帮助 –

+0

在点击开始按钮的处理程序中,解析您的延迟,然后启动具有该延迟的摆动计时器。当摆动计时器触发时,修改UI:随机选择一个人并调用'person.setText()'。当您的用户界面开始关闭时,确保定时器在未被禁用的情况下被禁用。 – antiduh