繁体   English   中英

使用Java wait()和notify()而不冻结Swing GUI

[英]Using Java wait() and notify() without freezing Swing GUI

我知道Swing GUI本身使用线程,但是我试图使用单独的线程来运行仿真。 我创建了一个实现Runnable的类,并像大多数简单的Runnable示例一样使用自定义线程。 我的run()方法基本上运行我的仿真,每秒更新一次(效果很好),但是我现在尝试实现可以​​暂停/恢复仿真的按钮。 我的开始按钮成功启动线程,我的暂停按钮成功暂停线程。 但是,选择“暂停”后,整个GUI会暂停,您可以看到该按钮仍处于选中状态,而我完全无法选择任何按钮或无法与该GUI进行交互。 一旦我在自定义线程上调用wait(),我的整个GUI就会暂停,即使我正在使用与此GUI分开的线程。 为什么调用wait()冻结了我的GUI? 如何仅暂停该特定线程而不暂停整个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();
    }

}

Thread对象上调用waitnotify行为与在任何其他对象上的行为没有什么不同。 具体来说,正如您所注意到的,它不会向执行线程发送应暂停的信号,而是会阻塞调用线程(在这种情况下为您的UI线程),直到收到notify消息为止。

您将需要实现一个从UI线程到后台线程的消息传递系统(例如阻塞队列),以获取所需的内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM