2017-02-05 15 views
-1

Я понимаю, что сами Swing GUI используют Threads, но я пытаюсь использовать отдельный поток для запуска моделирования. Я создал класс, который реализует Runnable и использует пользовательский поток, как это делают самые простые примеры Runnable. Мой метод run() в основном запускает мое моделирование, обновляя каждую секунду (что отлично работает), но теперь я пытаюсь реализовать кнопки, которые могут приостановить/возобновить симуляцию. Моя кнопка «Пуск» успешно запускает поток, и моя кнопка «Пауза» успешно приостанавливает поток. Однако, когда выбрана пауза, весь графический интерфейс приостанавливается, и вы можете видеть, что кнопка по-прежнему выбрана, и я не могу выбрать какие-либо кнопки или вообще взаимодействовать с графическим интерфейсом. Как только я вызываю wait() в свой пользовательский поток, весь мой GUI останавливается, хотя я использую Thread отдельно от этого графического интерфейса. Почему вызов wait() замерзает мой графический интерфейс? Как я могу приостановить только этот конкретный поток, а не весь графический интерфейс?Использование 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:

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

Вызов wait и notify на Thread объект ведет себя не по-другому, чем на любом другом объекте. В частности, как вы заметили, он не посылает сигнал исполнительному потоку, который он должен приостановить, а скорее блокирует вызывающий поток (ваш поток пользовательского интерфейса в этом случае), пока не получит сообщение notify.

Вам понадобится внедрить систему обмена сообщениями (такую ​​как блокирующую очередь) из потока пользовательского интерфейса в фоновый поток, чтобы получить то, что вы хотите.

+0

(1+) приятный ответ. –

+1

Хороший ответ, за исключением того, что «вызывающий поток» является более подходящим описанием, чем «текущий исполняемый» поток. –

+0

Достаточно честно. Отредактировано соответственно. –

 Смежные вопросы

  • Нет связанных вопросов^_^