2017-02-05 18 views
-1

私はSwing GUI自体がThreadsを使用していると理解しますが、シミュレーションを実行するために別のスレッドを使用しようとしています。私は、Runnableを実装するクラスを作成し、最も簡単なRunnableの例としてカスタムスレッドを使用します。私のrun()メソッドは基本的に私のシミュレーションを実行し、毎秒更新しています(これはうまくいきます)。しかし、私は現在、シミュレーションを一時停止/再開できるボタンを実装しようとしています。 [スタート]ボタンはスレッドを正常に開始し、[一時停止]ボタンはスレッドを正常に一時停止します。ただし、[一時停止]を選択すると、GUI全体が一時停止し、ボタンがまだ選択されているのがわかり、ボタンを選択したり、GUIとやりとりすることができなくなります。カスタムスレッドでwait()を呼び出すとすぐに、このGUIとは別のスレッドを使用していても、私のGUI全体が停止します。 GUIをフリーズしてwait()を呼び出すのはなぜですか?どのように私はGUI全体ではなく、この特定のスレッドだけを一時停止できますか?Javaのwait()とnotify()をフリーズせずに使用するSwing GUI

[スタート]ボタンは、プログラムを再開するためのボタンである必要があります。ここではGUIのための私のコードは次のとおりです。

import java.awt.BorderLayout; 
import java.awt.GridLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class GridFrame extends JFrame { 

    private static final long serialVersionUID = 2857470112009359285L; 

    private MyGridPanel grid; 
    private Simulation sim; 

    GridFrame(Simulation sim, int w, int h, int rows, int cols) { 
     this.sim = sim; 
     setTitle("Simulation"); 
     setSize(w, h); 
     grid = new MyGridPanel(w, h, rows, cols); 
     add(grid, BorderLayout.CENTER); 

     //Build bottom panel 
     JPanel buttons = new JPanel(); 
     buttons.setLayout(new GridLayout(1,3)); 
     JButton start = new JButton("Start"); 
     JButton pause = new JButton("Pause"); 
     JButton reset = new JButton("Reset"); 

     start.setActionCommand("Start"); 
     start.addActionListener(new ButtonActionListener()); 
     pause.setActionCommand("Pause"); 
     pause.addActionListener(new ButtonActionListener()); 
     reset.setActionCommand("Reset"); 
     reset.addActionListener(new ButtonActionListener()); 

     buttons.add(start); 
     buttons.add(pause); 
     buttons.add(reset); 

     add(buttons, BorderLayout.SOUTH); 
    } 

    public MyGridPanel getGrid(){ 
     return grid; 
    } 

    private class ButtonActionListener implements ActionListener{ 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      switch(e.getActionCommand()){ 
      case "Start": 
       System.out.println("Start"); 
       sim.start(); 
       break; 
      case "Pause": 
       System.out.println("Pause"); 
       sim.pause(); 
       break; 
      case "Reset": 
       System.out.println("Reset"); 
       break; 
      } 

     } 
    } 
} 

そして、ここでは私のRunnableです:Threadオブジェクトにwaitnotifyを呼び出す

public class Simulation implements Runnable{ 

    private Thread t; 
    private GridFrame frame; 
    private boolean paused; 

    public Simulation(){ 
     frame = new GridFrame(this, 300, 300, 10, 10); 
     frame.setVisible(true); 
     paused = true; 
    } 

    public void start() { 
     if(t == null){ 
      //Thread has not been created. Simulation has not started to run yet 
      System.out.println("Starting thread."); 
      t = new Thread(this); 
      t.start(); 
      paused = false; 
     } 
     else if(paused){ 
      //Simulation and thread already started to run but was paused. This should use notify() to resume the thread. 
      resume(); 
      paused = false; 
     } 
    } 

    public void resume(){ 
     synchronized(t){ 
      t.notify(); 
     } 
    } 

    public void pause(){ 
     synchronized(t){ 
      try { 
       t.wait(); 
       paused = true; 
      } catch (InterruptedException e) { 
       System.out.println("Exception when trying to pause simulation"); 
       e.printStackTrace(); 
      } 
     } 
    } 

    @Override 
    public void run() { 
     while(true){ 
      frame.getGrid().step(); 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       System.out.println("Thread interrupted while simulation was running."); 
       e.printStackTrace(); 
      } 
     } 

    } 


    public static void main(String[] a) { 
     Simulation s = new Simulation(); 
    } 

} 

答えて

3

は、他のオブジェクトの上に何も違っそれがないよりも振る舞うん。具体的には、気づいたように、実行中のスレッドに信号を送信しないでください。メッセージはnotifyメッセージを受け取るまで、呼び出しスレッド(この場合はUIスレッド)をブロックします。

UIスレッドからバックグラウンドスレッドにメッセージングシステム(ブロッキングキューなど)を実装して、必要なものを取得する必要があります。

+0

(1+)nice answer。 –

+1

"呼び出しスレッド"が "現在実行中の"スレッドよりも適切な記述であることを除いて、素晴らしい答えです。 –

+0

十分に公正。それに応じて編集。 –

関連する問題