2017-07-28 102 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