运行仿真的Java更新GUI

时间:2019-03-03 14:10:11

标签: java user-interface bluej

我正在尝试对从站到站的火车进行java模拟。我的主要代码在工作,但GUI遇到问题。我具有带“开始”和“停止”按钮的基本布局,但是一旦选择了“开始”按钮,主循环即会运行以进行仿真,并且GUI不会响应。我一直很难找到解决方法。帮助将不胜感激!

这是主要的模拟课程:

  

/ **    *这是运行主循环的主要模拟类。    *它使用两个类的实例:火车和车站。    * @作者Ollie Jones    *    * /   公共课程SimEngine   {

/**
 * Station object array and train object initialised.
 * The line has 16 station so an array of 16 is needed.
 */

Station[] station = new Station[16];
Train train = new Train();
int forwardTimeArray[];
int backwardTimeArray[];


/**
 * Constructor for objects of class SimEngine
 */
public SimEngine()
{

    /**
     * Here that values are initialised.
     */
    train = new Train();
    forwardTimeArray = new int[]{1,4,2,4,6,3,3,5,3,2,5,5,1,4,2};
    backwardTimeArray = new int[]{3,2,4,5,2,2,4,3,4,2,5,2,1,4,5};
    // A for loop is used to initialse the station number
    for(int i=0; i<station.length; i++){
        station[i] = new Station();
        station[i].setStationNumber(i+1);
    }

    /**
     * Each station name is initialised separately as
     * they all have different names.
     */
    station[0].setStationName("Name of 1st station");
    station[1].setStationName("Name of 2nd station");
    station[2].setStationName("Name of 3rd station");
    station[3].setStationName("Name of 4th station");
    station[4].setStationName("Name of 5ht station");
    station[5].setStationName("Name of 6th station");
    station[6].setStationName("Name of 7th station");
    station[7].setStationName("Name of 8th station");
    station[8].setStationName("Name of 9th station");
    station[9].setStationName("Name of 10th station");
    station[10].setStationName("Name of 11th station");
    station[11].setStationName("Name of 12th station");
    station[12].setStationName("Name of 13th station");
    station[13].setStationName("Name of 14th station");
    station[14].setStationName("Name of 15th station");
    station[15].setStationName("Name of 16th station");

}

/**
 * An example of a method - replace this comment with your own
 *
 * @param  y  a sample parameter for a method
 * @return    the sum of x and y
 */

    /**
 * This method stats the train simulation.
 * 
 */
public void start()
{
    int x = 0;
    System.out.println("Station Number:1"); //Print the first staion number.
    while(x == 0){
        int stationNumber = 0;
        int time = 0;
        Boolean forwards;
        stationNumber = train.getStationNumber();
        forwards = train.getDirection();
        if (forwards == true){
            time = forwardTimeArray[stationNumber-1];
            sleep(time);
            stationNumber = stationNumber + 1;
            System.out.println("Station Nubmer:" + stationNumber);
            train.setStationNumber(stationNumber);
        }

        else{
            time = backwardTimeArray[stationNumber-2];
            sleep(time);
            stationNumber = stationNumber - 1;
            System.out.println("Station Number:" + stationNumber);
            train.setStationNumber(stationNumber);
        }
        if (stationNumber == 1){
            forwards = true;
        }
        else if (stationNumber == 16){
            forwards = false;
            //train.setStationNumber(stationNumber-1);

        }
        train.setDirection(forwards);
    }
}
public static void sleep(int time)
{
    try{
        time = time * 100;
        Thread.sleep(time);
    }
    catch(Exception e) {}
}

public void stop()
{
    System.exit(0);
}

}

这是开始模拟的sim类。

public class Sim 
{
    private GUI gui;
    private SimEngine engine;

    /**
     * Constructor for objects of class sim
     * 
     */
    public Sim()
    {
        engine = new SimEngine();
        gui = new GUI(engine);
    }

    /**
     * Opens window if it has been closed.
     */

    public void show()
    {
        gui.setVisable(true);
    }
}

这里是GUI,主要问题是(我认为)。

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class GUI extends JFrame
{
    // instance variables - replace the example below with your own
    private JFrame frame;
    private JTextField display;
    private final SimEngine sim;
    private JLabel infoLabel;

    /**
     * Constructor for objects of class GUI
     */
    public GUI(SimEngine engine)
    {
        // initialise instance variables
        makeFrame();
        frame.setVisible(true);
        sim = engine;
    }

    /**
     * Creates GUI frame!
     */
    public void makeFrame()
    {
        frame = new JFrame("Train Simulation");

        JPanel contentPane = (JPanel)frame.getContentPane();
        contentPane.setLayout(new BorderLayout(8,8));
        contentPane.setBorder(new EmptyBorder(10,10,10,10));

        display = new JTextField();
        contentPane.add(display, BorderLayout.NORTH);

        JPanel buttonPanel = new JPanel(new GridLayout(1,2));
        addButton(buttonPanel, "Start", () -> sim.start());
        addButton(buttonPanel, "Stop", () -> sim.stop());

        contentPane.add(buttonPanel, BorderLayout.CENTER);
        frame.pack();
    }

    private void addButton(Container panel, String buttonText, ButtonAction
            action)
    {
        JButton button = new JButton(buttonText);
        button.addActionListener(e -> {action.act(); redisplay(); });
        panel.add(button);
    }

    private interface ButtonAction
    {
        /**
         * act on button press.
         */
        void act();
    }

    private void redisplay()
    {
    }

    /**
     * Makes frame visable.
     */
    public void setVisable(boolean visable){
        frame.setVisible(visable);
    }
}

2 个答案:

答案 0 :(得分:1)

您正在事件分配线程上运行模拟。在进行计算时,它们将垄断处理UI事件的线程,因此它无法处理任何事情,并且UI冻结。

使用worker threads

您似乎有这个用例(来自链接的教程):

  

后台任务可以通过调用SwingWorker.publish提供中间结果,从而导致从事件分配线程中调用SwingWorker.process。

答案 1 :(得分:0)

如评论和this中所述,在The Event Dispatch Thread上运行长时间的进程会阻止它,因此它不会响应更改。
一种替代方法是使用SwingWorker,该方法以其doInBackground()方法进行后台处理,发布临时值(publish方法)并能够更新gui(process方法) 。
以下是基于您的代码的SwingWorker的基本实现。
可以将其复制粘贴到一个文件(GUI.java)中并运行。
注意代码中的注释:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;

public class GUI extends JFrame
{
    // instance variables - replace the example below with your own
    private JFrame frame;
    private JTextField display;
    private final SimEngine sim;
    private JLabel infoLabel;

    /**
     * Constructor for objects of class GUI
     */
    public GUI(SimEngine engine)
    {
        // initialize instance variables
        makeFrame();
        frame.setVisible(true);
        sim = engine;
    }

    /**
     * Creates GUI frame!
     */
    public void makeFrame()
    {
        frame = new JFrame("Train Simulation");

        JPanel contentPane = (JPanel)frame.getContentPane();
        contentPane.setLayout(new BorderLayout(8,8));
        contentPane.setBorder(new EmptyBorder(10,10,10,10));

        display = new JTextField();
        contentPane.add(display, BorderLayout.NORTH);

        JPanel buttonPanel = new JPanel(new GridLayout(1,2));
        addButton(buttonPanel, "Start", () -> sim.start());
        addButton(buttonPanel, "Stop", () -> sim.stop());

        contentPane.add(buttonPanel, BorderLayout.CENTER);
        frame.pack();
    }

    private void addButton(Container panel, String buttonText, ButtonAction  action)
    {
        JButton button = new JButton(buttonText);
        button.addActionListener(e -> {action.act(); redisplay(); });
        panel.add(button);
    }

    void updateDisplay(String newValue){
        display.setText(newValue);
    }

    private interface ButtonAction
    {
        /**
         * act on button press.
         */
        void act();
    }

    private void redisplay() {  }

    /**
     * Makes frame visible.
     */
    public void setVisable(boolean visable){
        frame.setVisible(visable);
    }

    public static void main(String[] args) {
        Sim sim = new Sim();
        sim.show();
    }
}

//implements Listener so it can listen to SimEngine value changes 
class Sim  implements Listener
{
    private final GUI gui;
    private final SimEngine engine;


    public Sim()
    {
        engine = new SimEngine(this);
        gui = new GUI(engine);
    }

    /**
     * make gui visible 
     */
    public void show()
    {
        gui.setVisable(true);
    }

    @Override
    public void valueChanged(String newValue){
        gui.updateDisplay(newValue);
    }
}

class SimEngine {

    /**
     * Station object array and train object initialized.
     * The line has 16 station so an array of 16 is needed.
     */
    private final Station[] station = new Station[16];
    private Train train = new Train();
    private final int forwardTimeArray[],  backwardTimeArray[];
    private final Listener listener;

    //accept a listener 
    public SimEngine(Listener listener)
    {
        this.listener = listener;
        train = new Train();
        forwardTimeArray = new int[] {1,4,2,4,6,3,3,5,3,2,5,5,1,4,2,3}; //needs 16 values, had only 16
        backwardTimeArray = new int[]{3,2,4,5,2,2,4,3,4,2,5,2,1,4,5,4};
        // A for loop is used to initialize the station number and name
        for(int i=0; i<station.length; i++){
            station[i] = new Station();
            station[i].setStationNumber(i+1);
            station[0].setStationName("Station #"+(i+1));
        }
    }

    /**
     * This method starts the train simulation.
     *
     */
    public void start()
    {
        //have all background processing done by a SwingWorker so GUI does not freeze
        new SimulationWorker().execute();
    }
    public static void sleep(int time)
    {
        try{
            Thread.sleep(time * 300);
        }
        catch(Exception e) {}
    }

    public void stop()
    {
        System.exit(0);
    }

    class SimulationWorker extends SwingWorker<Void,Integer>{

        boolean stop = false; //use if you wish to stop 

        //do background processing 
        @Override
        protected Void doInBackground() throws Exception {
            while(! stop){
                int stationNumber = 0;
                int time = 0;
                boolean forwards;
                stationNumber = train.getStationNumber();

                forwards = train.getDirection();
                if (stationNumber == 1){
                    forwards = true;
                    train.setDirection(forwards);
                }
                else if (stationNumber == 15){
                    forwards = false;
                    train.setDirection(forwards);
                }

                if (forwards == true){
                    time = forwardTimeArray[stationNumber+1];//time = forwardTimeArray[stationNumber-1];
                    sleep(time);
                    stationNumber = stationNumber + 1;
                    //System.out.println("Station Number:" + stationNumber);
                    train.setStationNumber(stationNumber);
                }
                else{
                    time = backwardTimeArray[stationNumber-2];
                    sleep(time);
                    stationNumber = stationNumber - 1;
                    //System.out.println("Station Number:" + stationNumber);
                    train.setStationNumber(stationNumber);
                }
                publish(train.getStationNumber()); //publish result (station number)
            }
            return null;
        }

        //process published information 
        @Override
        protected void process(List<Integer> stationsList) {
            for(int stationNumber : stationsList){
                listener.valueChanged("Train is at "+ stationNumber); //notify listener 
            }
        }
    }
}

class Train {

    private  int stationNumber = 0;
    private  boolean forwards = true ;

    public int getStationNumber() {
        return stationNumber;
    }

    public void setDirection(boolean forwards) {
        this.forwards = forwards;
    }

    public void setStationNumber(int stationNumber) {
        this.stationNumber = stationNumber;
    }

    public boolean getDirection() {
        return forwards;
    }
}

class Station {

    private int stationNumber;
    private String stationName;

    public void setStationNumber(int stationNumber) {
        this.stationNumber = stationNumber;
    }

    public void setStationName(String stationName) {
        this.stationName = stationName;
    }
}

//an interface use by Sim to listen to SimEngine changes 
interface Listener {
    void valueChanged(String newValue);
}