简体   繁体   中英

JPanel doesn't get new values (anymore)

So, I'm trying to program a Game of Life simulation (Conway), and I want to show it in a JFrame.

For this purpose, I've created a JPanel, and it works perfectly, until I try to actually show a new generation. With prints, I've figured out, that the list is actually correct inside the newGeneration() method, but when paint(Graphics g) gets called (aka, when I try to repaint the JFrame), the list isn't updating.

I'm sure I've missed something obvious, and I'm not well versed in Java, but it's just getting so annoying. I'd really appreciate your help.

Here's my code;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


public class Main {

    public static void main(String[] args) {

        new GameOfLife();

    }
}


class GameOfLife {

    // Initialising all class wide variables; sorted by type

    JFrame frame = new JFrame("Game of Life");
    JPanel panel;

    Scanner gameSize = new Scanner(System.in);

    String dimensions;
    String splitHorizontal;
    String splitVertical;
    String confirmation;

    Boolean accepted = false;

    Integer split;
    Integer horizontal;
    Integer vertical;
    Integer livingNeighbours;

    int[][] cells;
    int[][] newCells;

    public GameOfLife() {

        // Prompt for game Size
        System.out.println("Please enter your game size in the following format; 'Horizontal,Vertical'");

        // Run until viable game Size has been chosen
        while (!accepted) {
            dimensions = gameSize.nextLine();

            // Check for correct format
            if (dimensions.contains(",")) {
                split = dimensions.indexOf(",");
                splitHorizontal = dimensions.substring(0, split);
                splitVertical = dimensions.substring(split + 1);

                // Check for validity of inputs
                if (splitHorizontal.matches("[0-9]+") && splitVertical.matches("[0-9]+")) {
                    horizontal = Integer.parseInt(dimensions.substring(0, split));
                    vertical = Integer.parseInt(dimensions.substring(split + 1));

                    // Check for game Size
                    if (horizontal > 1000 || vertical > 1000) {
                        System.out.println("A game of this Size may take too long to load.");
                    } else {

                        // Confirmation Prompt
                        System.out.println("Your game will contain " + horizontal + " columns, and " + vertical + " rows, please confirm (Y/N)");
                        confirmation = gameSize.nextLine();

                        // Check for confirmation, anything invalid is ignored
                        if (confirmation.matches("Y")) {
                            accepted = true;
                            System.out.println("Thank you for your confirmation. Please select live cells. Once your happy with your game, press Spacebar to start the Simulation.");

                            // Setting parameters depending on Size
                            frame.setSize(horizontal * 25 + 17, vertical * 25 + 40);
                            frame.setVisible(true);
                            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        }
                    }
                }
            }

            // Prompt asking for new dimensions in case of invalid dimensions or non confirmation
            if (!accepted) {
                System.out.println("Please enter different dimensions.");
            }
        }


        // Creating list of cells
        cells = new int[horizontal][vertical];

        // Showing the empty panel for selection of live cells
        panel = new PaintCells(horizontal, vertical, cells);
        frame.add(panel);

        // Select live cells
        panel.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {

                if (cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] == 1) {
                    cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] = 0;
                } else {
                    cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] = 1;
                }
                frame.repaint();

            }
        });

        // Simulation start
        frame.addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(KeyEvent e) {
                if (e.getKeyChar() == ' ') {
                    newGeneration();
                }

            }

            @Override
            public void keyPressed(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }
        });
    }


    // Generating new generations
    void newGeneration() {

        newCells = new int[horizontal][vertical];

        // Pause inbetween generations
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /*
         * Way of Life Rules:
         * Living cells with 2 or 3 living neighbours live on to the next generation.
         * Dead cells with exactly 3 living neighbours become living cells in the next generation.
         * Every other living cell dies.
         */

        // iterate through every cell
        for (int l = 0; l < vertical; l++) {
            for (int k = 0; k < horizontal; k++) {

                livingNeighbours = 0;

                // check amount of neighbours
                if (k - 1 > -1) {
                    if (l - 1 > -1) {
                        if (cells[k - 1][l - 1] == 1) {
                            livingNeighbours++;
                        }
                    }
                    if (l + 1 < vertical) {
                        if (cells[k - 1][l + 1] == 1) {
                            livingNeighbours++;
                        }
                    }
                    if (cells[k - 1][l] == 1) {
                        livingNeighbours++;
                    }
                }
                if (k + 1 < horizontal) {
                    if (l - 1 >= 0) {
                        if (cells[k + 1][l - 1] == 1) {
                            livingNeighbours++;
                        }
                    }
                    if (l + 1 < vertical) {
                        if (cells[k + 1][l + 1] == 1) {
                            livingNeighbours++;
                        }
                    }
                    if (cells[k + 1][l] == 1) {
                        livingNeighbours++;
                    }

                }
                if (l - 1 >= 0) {
                    if (cells[k][l - 1] == 1) {
                        livingNeighbours++;
                    }
                }
                if (l + 1 < vertical) {
                    if (cells[k][l + 1] == 1) {
                        livingNeighbours++;
                    }
                }


                // change cell value depending on amount of neighbours
                if (cells[k][l] == 1) {
                    if (livingNeighbours < 2 || livingNeighbours > 3) {
                        newCells[k][l] = 0;
                    } else {
                        newCells[k][l] = 1;
                    }
                } else {
                    if (livingNeighbours == 3) {
                        newCells[k][l] = 1;
                    }
                }
            }
        }

        cells = newCells;
        frame.validate();
        frame.paint(frame.getGraphics());
        newGeneration();
    }
}


// Our canvas
class PaintCells extends JPanel {

    private Integer horizontal;
    private Integer vertical;
    private int[][] newOriginalCells;

    // Get our X and Y from the original prompts
    public PaintCells(Integer originalHorizontal, Integer originalVertical, int[][] originalCells) {
        this.horizontal = originalHorizontal;
        this.vertical = originalVertical;
        this.newOriginalCells = originalCells;
    }


    @Override
    public void paint(Graphics g) {
        for (int i = 0; i < vertical; i++) {
            for (int j = 0; j < horizontal; j++) {

                // Check cell value
                if (newOriginalCells[j][i] == 1) {
                    g.setColor(Color.black);
                } else {
                    g.setColor(Color.white);
                }

                // paint according to value
                g.fillRect(j * 25, i * 25, 25, 25);
                if (newOriginalCells[j][i] == 1) {
                    g.setColor(Color.white);
                } else {
                    g.setColor(Color.black);
                }                           // maybe change style?
                g.drawRect(j * 25, i * 25, 25, 25);
            }
        }
    }
}

I'm guessing, the problem is somewhere in newGeneration(), but other than that, I really have no idea anymore.

You have a common problem which I had myself a few months ago. Java Swing GUI system works in thread called Event Dispatch Thread (EDT) . This thread handle events like mouse clicks, typing etc. and paint the components to the screen. You should use this thread as your main thread, but as sub-thread which working only once a certain time/when event happens, and not let him run continuously.应该使用这个线程作为主线程,但作为唯一的工作,一旦某个时间子线程/当事件发生时,并没有让他的连续运行。 In your code, since the user choose the cell to live, this thread run non-stop (because you started the program inside a listener, which is part of the EDT), and your GUI stuck, because it's updating only at the end of the thread. You can solve this by using javax.swing.Timer . Timer is an object that allows you do tasks once a while, and it is perfect to this problem. Use code like this:

ActionListener actionListaner = new ActionListener(){
    public void actionPerformed(ActionEvent e){
        //Put here you ne genration repeating code
    }
};
int delay = 1000;//You delay between generations in millis
Timer timer = new timer(delay, actionListener);

The code in the actionPerformed method will repeat every second (or any other time you want it to repeat), and every operation of the timer will call EDT instead of let it run non-stop. 调用 EDT,而不是让它不停地运行。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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