2017-07-28 1 views
0

ButtonListenerクラスのMy Thread.sleep(rand.nextInt(delay))コマンドが自分のGUIをクラッシュさせます。何か案は?プログラムは、ArrayListに人を追加し、それらをランダムに選択して、0からtimeText JTextFieldまでのランダムな時間に表示し、sleepコマンドを追加するまで動作します。どんな助けもありがとう!Button.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(btw、 .swing.Timer'、なぜそれを使用しない...) –

答えて

-1

実際に、あなたは同じスレッドにあなたのGUIを実行していて、使用しているときThread.sleep(delay)あなたは、GUIも寝ています。他の処理には新しいスレッドを使用する必要があります。

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

この問題を解決できる他のスレッドはありません。 UIタイマーを使用する必要があります。他のスレッドを導入するとUIの並行性のバグが発生するのは、1つのスレッドだけがUI全体を読み書きするという制約に違反するためです。 – antiduh

0

UIを変更するスレッドは1つだけです。これは、UIが受け取ることができるイベントの多くのソースであっても、並行性のバグがUIの状態を破壊することは不可能であることを意味するため、これは設計によるものです。

UIを変更するスレッドは1つだけです。それは以下を含みます:

  • マウスイベントを受け取ります。
  • キーボードイベントを受信して​​います。
  • 再描画要求を処理しています。
  • UIタイマーを処理しています。

他にも多数あります。

UIを変更するコードを使用している場合は、UIスレッドを使用する必要があります(そうでなければ、バグがあります)。 UIスレッドで、Sleep()を呼び出すと、UIスレッドは処理をやめます。

再描画の要求に応答しなくなります。キーボードイベント、マウスイベントなどに反応しなくなります。

代わりに、フォームタイマーを使用してアニメーションを実行する必要があります。ユーザーが「スタート」ボタンをクリックすると、最初の値を設定し、残りの値を保存してからタイマーを開始し、UIスレッドが処理を続けるようにします。

タイマーが起動するたびに、状態を進めます。表示する次の値でUIを更新します。すべての値を表示するまでこれを続けてから、タイマーを停止し、アニメーションのどこにいるかを示す状態を解放します。

ええ、一部のコンポーネントでテキストを設定するだけですが、これはまだアニメーションパターンの下にあります。

アニメーションタイマーの実行中にUIが閉じていると、削除されたUIを変更しようとします。ですから、あなたのUIコードは、UIが閉じられたときにまだ実行されていればアニメーションタイマーを停止するように注意する必要があります。

+0

タイマーはどのように実装しますか?あなたの助けをありがとう –

+0

あなたの開始ボタンがクリックされたときのハンドラで、遅延を解析し、その遅延でスイングタイマーを開始します。スイングタイマーが起動したら、UIを変更します:ランダムな人を選び、 'person.setText()'を呼び出します。UIがシャットダウンを開始したら、タイマーが無効になっていない場合は無効にしてください。 – antiduh

関連する問題