Java 使用 GUI 的捕食者-猎物模拟无法 运行 模拟

Java predator-prey simulation with GUI can't run simulation

我正在尝试将 GUI 添加到捕食者-猎物模拟中。它可以让用户选择他们想做的模拟(涉及的物种),设置他们想要的模拟领域大小,并显示模拟的进度和结果。

问题是我生成字段后,我无法通过点击我设置的按钮来重置模拟或运行下一步或运行下百步,更不用说显示模拟的进度。

这是我的 GUI 代码 Class:

import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JComboBox;
import javax.swing.JTextField;



/**
 * Illustrate the GUI of the simulator.
 * 
 * @author Jeremy Chu
 * @version 2021.06.02
 */
public class GUI extends JFrame
{
    private JFrame frame;
    private JPanel panel1;
    private JPanel panel2;
    private JPanel panel3;
    private Simulator simulator;
    private Animal animal;
    private Field field;
    private SimulatorView view;
    
    //species2 = {"RF","RW","RB","RH","FW","FB","FH","WB","WH","BH"};
    private SimulatorRF simulatorRF;
    private SimulatorRW simulatorRW;
    private SimulatorRB simulatorRB;
    private SimulatorRH simulatorRH;
    private SimulatorFW simulatorFW;
    private SimulatorFB simulatorFB;
    private SimulatorFH simulatorFH;
    private SimulatorWB simulatorWB;
    private SimulatorWH simulatorWH;
    private SimulatorBH simulatorBH;
    //species3 = {"RFW","RFB","RFH","RWB","RWH","RBH","FWB","FWH","FBH","WBH"};
    private SimulatorRFW simulatorRFW;
    private SimulatorRFB simulatorRFB;
    private SimulatorRFH simulatorRFH;
    private SimulatorRWB simulatorRWB;
    private SimulatorRWH simulatorRWH;
    private SimulatorRBH simulatorRBH;
    private SimulatorFWB simulatorFWB;
    private SimulatorFWH simulatorFWH;
    private SimulatorFBH simulatorFBH;
    private SimulatorWBH simulatorWBH;
    //species4 = {"RFWB","RFWH","RFBH","RWBH","FWBH"};
    private SimulatorRFWB simulatorRFWB;
    private SimulatorRFWH simulatorRFWH;
    private SimulatorRFBH simulatorRFBH;
    private SimulatorRWBH simulatorRWBH;
    private SimulatorFWBH simulatorFWBH;
    
    
    JComboBox comboBox1;
    JComboBox comboBox2;
    JComboBox comboBox3;
    JComboBox comboBox4;
    
    JButton button;
    JButton button1;
    JButton button2;
    JButton button3;
    JButton button4;
    JButton button5;
    JButton reset_butt;
    JButton nextstep_butt;
    JButton longstep_butt;
    
    JTextField depthtxt;
    JTextField widthtxt;
    int depth = 100;
    int width = 100;
    int version = 0;
    
    public GUI() {
        frame = new JFrame();
        panel1 = new JPanel();
        panel2 = new JPanel();
        //panel3 = new JPanel();
        
        panel1.setBackground(Color.lightGray);
        panel2.setBackground(Color.gray);
        //panel3.setBackground(Color.blue);
        
        

        String[] species2 = {"","Rabbits & Foxes","Rabbits & Wolves","Rabbits & Bears","Rabbits & Hunters","Foxes & Wolves",
                                "Foxes & Bears","Foxes & Hunters","Wolves & Bears","Wolves & Hunters","Bears & Hunters"};
        String[] species3 = {"","Rabbits & Foxes & Wolves","Rabbits & Foxes & Bears","Rabbits & Foxes & Hunters","Rabbits & Wolves & Bears",
                                "Rabbits & Wolves & Hunters","Rabbits & Bears & Hunters","Foxes & Wolves & Bears","Foxes & Wolves & Hunters",
                                "Foxes & Bears & Hunters","Wolves & Bears & Hunters"};
        String[] species4 = {"","Rabbits & Foxes & Wolves & Bears","Rabbits & Foxes & Wolves & Hunters","Rabbits & Foxes & Bears & Hunters",
                                "Rabbits & Wolves & Bears & Hunters","Foxes & Wolves & Bears & Hunters"};
        String[] species5 = {"","ALL"};
        
        comboBox1 = new JComboBox(species2);
        comboBox1.addActionListener(new Combobox1Handler());
        comboBox1.setEnabled(false);
        comboBox2 = new JComboBox(species3);
        comboBox2.addActionListener(new Combobox2Handler());
        comboBox2.setEnabled(false);
        comboBox3 = new JComboBox(species4);
        comboBox3.addActionListener(new Combobox3Handler());
        comboBox3.setEnabled(false);
        comboBox4 = new JComboBox(species5);
        comboBox4.addActionListener(new Combobox4Handler());
        comboBox4.setEnabled(false);
        
        
        JLabel label1 = new JLabel("");
        JLabel label2 = new JLabel("Choose Options to generate Simulation");
        JLabel label3 = new JLabel("");
        JLabel label4 = new JLabel("Choose species in the field: ");
        JLabel label5 = new JLabel("");
        JLabel label6 = new JLabel("<html><font size='4'color=gray> Rabbits</font> <font size='4'color=orange> Foxes</font><font size='4'color=blue> Wolves</font><font size='4'color=red> Bears</font><font size='4'color=black> Hunters</font></html>");
        JLabel label7 = new JLabel("");
        JLabel label17 = new JLabel("");
        JLabel label18 = new JLabel("");
        JLabel label8 = new JLabel("Simulate:");
        JLabel label9 = new JLabel("");
        JLabel label10 = new JLabel("");
        JLabel label11 = new JLabel("depth:");
        JLabel label12 = new JLabel("Width:");
        JLabel label13 = new JLabel("");
        JLabel label14 = new JLabel("Reset");
        JLabel label15 = new JLabel("Next step");
        JLabel label16 = new JLabel("Next hundred step");


        button1 = new JButton("Two species");
        button1.addActionListener(new Button1Handler());
        button2 = new JButton("Three species");
        button2.addActionListener(new Button2Handler());
        button3 = new JButton("Four species");
        button3.addActionListener(new Button3Handler());
        button4 = new JButton("All");
        button4.addActionListener(new Button4Handler());
        button5 = new JButton("Reset");
        button5.addActionListener(new Button5Handler());
        
        button = new JButton("Generate Field");
        button.addActionListener(new ButtonHandler());

        reset_butt = new JButton("Reset");
        reset_butt.addActionListener(new ResetbuttHandler());

        nextstep_butt = new JButton("Next step");
        nextstep_butt.addActionListener(new NextstepbuttHandler());

        longstep_butt = new JButton("Next hundred steps");
        longstep_butt.addActionListener(new LongstepbuttHandler());

        depthtxt = new JTextField();
        depthtxt.setText("100");
        //depthtxt.setEnabled(false);
        widthtxt = new JTextField();
        widthtxt.setText("100");    
        
        
        panel1.setLayout(new GridLayout(7,5,10,0));
        panel1.add(label1);         panel1.add(label2);         panel1.add(label3);
        panel1.add(label4);         panel1.add(label5);         panel1.add(label6);
        panel1.add(button1);        panel1.add(button2);        panel1.add(button3);
        panel1.add(comboBox1);      panel1.add(comboBox2);      panel1.add(comboBox3);
        panel1.add(button4);        panel1.add(label7);         panel1.add(label18);
        panel1.add(comboBox4);      panel1.add(label17);        panel1.add(button5);
        panel2.setLayout(new GridLayout(5,4,10,0));
        panel2.add(label8);         panel2.add(label9);         panel2.add(label10);
        panel2.add(label11);        panel2.add(label12);        panel2.add(label13);
        panel2.add(depthtxt);       panel2.add(widthtxt);       panel2.add(button);
        panel2.add(reset_butt);     panel2.add(nextstep_butt);  panel2.add(longstep_butt);
        //panel3.setLayout(new GridLayout(5,4,10,0));
        
        frame.add(panel1,BorderLayout.NORTH);
        frame.add(panel2,BorderLayout.SOUTH);
        //frame.add(panel3,BorderLayout.SOUTH);
        
        
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.setTitle("Predator and Prey simulator");
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args){
        new GUI();
    }
    
    
    private class Button1Handler implements ActionListener{//Two Species
        public void actionPerformed(ActionEvent e){
            button2.setEnabled(false);
            button3.setEnabled(false);
            button4.setEnabled(false);
            comboBox1.setEnabled(true);
            comboBox2.setEnabled(false);
            comboBox3.setEnabled(false);
            comboBox4.setEnabled(false);
        }
    }
    private class Button2Handler implements ActionListener{//Three Species
        public void actionPerformed(ActionEvent e){
            button1.setEnabled(false);
            button3.setEnabled(false);
            button4.setEnabled(false);
            comboBox1.setEnabled(false);
            comboBox2.setEnabled(true);
            comboBox3.setEnabled(false);
            comboBox4.setEnabled(false);
        }
    }
    private class Button3Handler implements ActionListener{//Four Species
        public void actionPerformed(ActionEvent e){
            button1.setEnabled(false);
            button2.setEnabled(false);
            button4.setEnabled(false);
            comboBox1.setEnabled(false);
            comboBox2.setEnabled(false);
            comboBox3.setEnabled(true);
            comboBox4.setEnabled(false);
        }
    }
    private class Button4Handler implements ActionListener{//All Species
        public void actionPerformed(ActionEvent e){
            button1.setEnabled(false);
            button2.setEnabled(false);
            button3.setEnabled(false);
            comboBox1.setEnabled(false);
            comboBox2.setEnabled(false);
            comboBox3.setEnabled(false);
            comboBox4.setEnabled(true);
        }
    }
    private class Button5Handler implements ActionListener{//Reset Species
        public void actionPerformed(ActionEvent e){
            button1.setEnabled(true);
            button2.setEnabled(true);
            button3.setEnabled(true);
            button4.setEnabled(true);
            comboBox1.setEnabled(false);
            comboBox2.setEnabled(false);
            comboBox3.setEnabled(false);
            comboBox4.setEnabled(false);
            comboBox1.setSelectedIndex(0);
            comboBox2.setSelectedIndex(0);
            comboBox3.setSelectedIndex(0);
            comboBox4.setSelectedIndex(0);
        }
    }
    private class Combobox1Handler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            //species2 = {"RF","RW","RB","RH","FW","FB","FH","WB","WH","BH"}
            if(comboBox1.getSelectedIndex() == 1){//RF
                version = 1;
            }
            else if(comboBox1.getSelectedIndex() == 2){//RW
                version = 2;
            }
            ...
            else if(comboBox1.getSelectedIndex() == 10){
                version = 10;
            }
        }
    }
    private class Combobox2Handler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            //species3 = {"RFW","RFB","RFH","RWB","RWH","RBH","FWB","FWH","FBH","WBH"};
            if(comboBox2.getSelectedIndex() == 1){
                version = 11;
            }
            else if(comboBox2.getSelectedIndex() == 2){
                version = 12;
            }
            ...
            else if(comboBox2.getSelectedIndex() == 10){
                version = 20;
            }
        }
    }
    private class Combobox3Handler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            //species4 = {"RFWB","RFWH","RFBH","RWBH","FWBH"};
            if(comboBox3.getSelectedIndex() == 1){
                version = 21;
            }
            else if(comboBox3.getSelectedIndex() == 2){
                version = 22;
            }
            ...
            else if(comboBox3.getSelectedIndex() == 5){
                version = 25;
            }
        }
    }
    private class Combobox4Handler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            //species5 = {"All"};
            if(comboBox4.getSelectedIndex() == 1){
                version = 0;
            }
        }
    }  
    private class ButtonHandler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            String depthstr = depthtxt.getText();
            String widthstr = widthtxt.getText();
            int depth = Integer.parseInt(depthstr);
            int width = Integer.parseInt(widthstr);
            switch(version) {
                case 0:
                    Simulator setsize = new Simulator();
                    setsize.Simulator(depth,width);
                    break;
                case 1:
                    SimulatorRF setsizeRF = new SimulatorRF();
                    setsizeRF.SimulatorRF(depth,width);
                    break;
                case 2:
                    SimulatorRW setsizeRW = new SimulatorRW();
                    setsizeRW.SimulatorRW(depth,width);
                    break;
                ...
                case 25:
                    SimulatorFWBH setsizeFWBH = new SimulatorFWBH();
                    setsizeFWBH.SimulatorFWBH(depth,width);
                    break;
            }            
        }
    }      
    private class ResetbuttHandler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            simulator = new Simulator();
            Simulator reseting = new Simulator();
            reseting.reset();//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        }
    }   
    private class NextstepbuttHandler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            simulator = new Simulator();
            Simulator onestep = new Simulator();
            onestep.simulateOneStep();//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        }
    }
    private class LongstepbuttHandler implements ActionListener{
        public void actionPerformed(ActionEvent e){
            simulator = new Simulator();
            Simulator longstep = new Simulator();
            longstep.runLongSimulation();//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        }
    }
}

而且无论我点击按钮“重置”或“下一步”或“下一步”,它都显示相同的错误消息:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.simulateOneStep(Simulator.java:112)
    at GUI.actionPerformed(GUI.java:463)
    ...
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.simulate(Simulator.java:95)
    at Simulator.runLongSimulation(Simulator.java:85)
    at GUI.actionPerformed(GUI.java:468)
    ...
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.reset(Simulator.java:132)
    at GUI.actionPerformed(GUI.java:458)
    ...
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.simulate(Simulator.java:95)
    at Simulator.runLongSimulation(Simulator.java:85)
    ...
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.simulateOneStep(Simulator.java:112)
    at GUI$NextstepbuttHandler.actionPerformed(GUI.java:485)
    ...
java.lang.NullPointerException
    at Simulator.simulateOneStep(Simulator.java:112)
java.lang.NullPointerException
    at Simulator.simulateOneStep(Simulator.java:112)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.simulateOneStep(Simulator.java:112)
    at GUI$NextstepbuttHandler.actionPerformed(GUI.java:481)
    ...
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Simulator.reset(Simulator.java:132)
    at GUI$ResetbuttHandler.actionPerformed(GUI.java:474)
    ...

我知道这可能很难理解,但是有人能找出我的代码可能出了什么问题吗? 抱歉给您带来不便...

这是我第一次发帖,如果有任何问题,请告诉我。

*编辑---------------------------------------- ---------------------------------------------- --------

这里是模拟器的代码Class,可能会导致问题:

import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Color;

/**
 * A simple predator-prey simulator, based on a rectangular field
 * 
 * @author Jeremy Chu
 * @version 2021.05.30
 */
public class Simulator
{
    // Constants representing configuration information for the simulation.
    // The default width for the grid.
    private static final int DEFAULT_WIDTH = 100;
    // The default depth of the grid.
    private static final int DEFAULT_DEPTH = 100;
    // The probability that a hunter will be created in any given grid position.
    private static final double HUNTER_CREATION_PROBABILITY = 0.05;
    // The probability that a bear will be created in any given grid position.
    private static final double BEAR_CREATION_PROBABILITY = 0.01;
    // The probability that a wolf will be created in any given grid position.
    private static final double WOLF_CREATION_PROBABILITY = 0.02;
    // The probability that a fox will be created in any given grid position.
    private static final double FOX_CREATION_PROBABILITY = 0.03;
    // The probability that a rabbit will be created in any given grid position.
    private static final double RABBIT_CREATION_PROBABILITY = 0.08;    
    
    
    // List of animals in the field.
    private List<Animal> animals;
    // The current state of the field.
    private Field field;
    // The current step of the simulation.
    private int step;
    // A graphical view of the simulation.
    private SimulatorView view;
    
    /**
     * Construct a simulation field with default size.
     */
    public void Simulator()
    {
        Simulator(100, 100);
    }
    
    /**
     * Create a simulation field with the given size.
     * @param depth Depth of the field. Must be greater than zero.
     * @param width Width of the field. Must be greater than zero.
     */
    public void Simulator(int depth, int width)
    {
        if(width <= 0 || depth <= 0) {
            System.out.println("The dimensions must be greater than zero.");
            System.out.println("Using default values.");
            depth = DEFAULT_DEPTH;
            width = DEFAULT_WIDTH;
        }
        
        animals = new ArrayList<Animal>();
        field = new Field(depth, width);

        // Create a view of the state of each location in the field.
        view = new SimulatorView(depth, width);
        view.setColor(Rabbit.class, Color.gray);
        view.setColor(Fox.class, Color.orange);
        view.setColor(Wolf.class, Color.blue);
        view.setColor(Bear.class, Color.red);
        view.setColor(Hunter.class, Color.black);
        
        // Setup a valid starting point.
        reset();
    }
    
    /**
     * Run the simulation from its current state for a reasonably long period,
     * e.g. 100 steps.
     */
    public void runLongSimulation()
    {
        simulate(100);//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    }
    
    /**
     * Run the simulation from its current state for the given number of steps.
     * Stop before the given number of steps if it ceases to be viable.
     * @param numSteps The number of steps to run for.
     */
    public void simulate(int numSteps)
    {
        for(int step = 1; step <= numSteps && view.isViable(field); step++) {//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
            simulateOneStep();
        }
    }
    
    /**
     * Run the simulation from its current state for a single step.
     * Iterate over the whole field updating the state of each
     * wolf, fox and rabbit.
     */
    public void simulateOneStep()
    {
        step++;

        // Provide space for newborn animals.
        List<Animal> newAnimals = new ArrayList<Animal>();        
        // Let all rabbits act.
        for(Iterator<Animal> it = animals.iterator(); it.hasNext(); ) {//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
            Animal animal = it.next();
            animal.act(newAnimals);
            if(! animal.isAlive()) {
                it.remove();
            }
        }
               
        // Add the newly born wolves, foxes and rabbits to the main lists.
        animals.addAll(newAnimals);

        view.showStatus(step, field);
    }
        
    /**
     * Reset the simulation to a starting position.
     */
    public void reset()
    {
        step = 0;
        animals.clear();//*Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        populate();
        
        // Show the starting state in the view.
        view.showStatus(step, field);
    }
    
    /**
     * Randomly populate the field with wolves, foxes and rabbits.
     */
    private void populate()
    {
        Random rand = Randomizer.getRandom();
        field.clear();
        for(int row = 0; row < field.getDepth(); row++) {
            for(int col = 0; col < field.getWidth(); col++) {
                if(rand.nextDouble() <= HUNTER_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Hunter hunter = new Hunter(true, field, location);
                    animals.add(hunter);
                }
                else if(rand.nextDouble() <= BEAR_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Bear bear = new Bear(true, field, location);
                    animals.add(bear);
                }
                else if(rand.nextDouble() <= WOLF_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Wolf wolf = new Wolf(true, field, location);
                    animals.add(wolf);
                }
                else if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Fox fox = new Fox(true, field, location);
                    animals.add(fox);
                }
                else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
                    Location location = new Location(row, col);
                    Rabbit rabbit = new Rabbit(true, field, location);
                    animals.add(rabbit);
                }
                // else leave the location empty.
            }
        }
    }
}

好像我的generate按钮生成的数据在我用其他按钮的时候是访问不到的,但是我试了很久还是没解决...

这是我的代码: https://github.com/KasmaJC/predator-prey-simulation-with-GUI

没关系...我找出问题所在:

当我单击这些按钮时,我再次创建新对象方法,这就是为什么当我使用其余按钮时,生成按钮生成的数据无法访问的原因。

private class ResetbuttHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
        simulator = new Simulator();
        Simulator reseting = new Simulator();// HERE
        reseting.reset();        
    }
}   
private class NextstepbuttHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
        simulator = new Simulator();
        Simulator onestep = new Simulator();// HERE
        onestep.simulateOneStep();        
    }
}
private class LongstepbuttHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
        simulator = new Simulator();
        Simulator longstep = new Simulator();// HERE
        longstep.runLongSimulation();        
    }
} 

我应该使用与生成按钮使用相同的对象方法。

但后来又演变成另一个问题... 如何让按钮的其余部分使用与生成按钮使用相同的对象方法,但也不再生成该字段? (也许这是我猜的逻辑问题...)

我可能会问另一个问题...