遇到问题,无法使 JGrid 内部的 JPanel 立即对变化作出反应。

huangapple go评论92阅读模式
英文:

Having trouble making the JPanels inside Jgrid react to change immediately

问题

我目前正在尝试使用Java和Swing编写John Conway的生命游戏。然而,我在使用GridLayout中的JPanel单元格方面遇到了问题。以下是有问题的代码部分:

GameOfLifeFrame(int size, int generations, Random random, boolean[][] grid, final GameOfLife life) {
    super("Game of life");
    this.size = size;
    this.generations = generations;
    this.random = random;
    this.grid = grid;
    this.life = life;
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300, 300);
    var contentPane = getContentPane();
    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
    JLabel generationMaker = new JLabel("Generation: ");
    add(generationMaker);
    JLabel alive = new JLabel("Alive: 0");
    add(alive);

    var gridPanel = new JPanel();
    gridPanel.setLayout(new GridLayout(size, size, 0, 0));
    contentPane.add(gridPanel);
    var cellArray = new javax.swing.JPanel[size][size];
    for (var i = 0; i < size; i++) {
        for (var j = 0; j < size; j++) {
            var cell = new JPanel();
            cellArray[i][j] = cell;
            cell.setBorder(BorderFactory.createLineBorder(Color.BLACK));
            gridPanel.add(cell);
        }
    }
    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
    var button = new JButton();
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            generateGrid(cellArray);
            alive.setText("Alive: " + countAlive(life.grid));
            incrementGeneration();
            generationMaker.setText("Generation #" + generationCounter);
        }
    });
    contentPane.add(button);
    setVisible(true);
}

private void generateGrid(JPanel[][] cellArray) {
    var grid2 = getGrid();
    fillInPanels(cellArray, grid2);
    life.grid = grid2;
}

protected void fillInPanels(javax.swing.JPanel[][] panelArray, boolean[][] grid) {
    for (var i = 0; i < size; i++) {
        for (var j = 0; j < size; j++) {
            if (grid[i][j]) {
                panelArray[i][j].setBackground(Color.BLACK);
            } else {
                panelArray[i][j].setBackground(Color.WHITE);
            }
        }
    }
}

这段代码可以很好地模拟Conway的生命游戏,但是在按下按钮后,整个屏幕不会立即改变,而是可以看到单个单元格的变化,而且不会立即改变。这是否与双缓冲有关?当屏幕上的存活单元格较少时,它的运行效果更好,而且速度更快。

问题的根本原因和解决方法是什么?如果我的问题或帖子格式不好,请原谅,这是我第一次在这里发布。

这是35x35大小网格的效果

解决方案:这个问题可能与Swing的绘制机制有关,而不是双缓冲。当屏幕上的单元格较多时,Swing可能会在更新整个界面时产生明显的延迟。为了解决这个问题,你可以尝试使用Swing的repaint方法来手动刷新JPanel,以便更快地更新整个界面。在按钮的actionPerformed方法中,调用gridPanel.repaint(),这将强制刷新gridPanel,以便更快地更新界面。

修改后的代码如下:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        generateGrid(cellArray);
        alive.setText("Alive: " + countAlive(life.grid));
        incrementGeneration();
        generationMaker.setText("Generation #" + generationCounter);
        
        // 刷新gridPanel
        gridPanel.repaint();
    }
});

这应该可以改善界面的更新速度,使其更加流畅。希望这对你有所帮助!

英文:

I am currently attempting to write John Conway's game of life in java using Swing. I have however run into problems regarding JPanel cells in GridLayout. Here is the code that is problematic

    GameOfLifeFrame(int size, int generations, Random random, boolean[][] grid, final GameOfLife life) {
super(&quot;Game of life&quot;);
this.size = size;
this.generations = generations;
this.random = random;
this.grid = grid;
this.life = life;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
var contentPane = getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
JLabel generationMaker = new JLabel(&quot;Generation: &quot;);
add(generationMaker);
JLabel alive = new JLabel(&quot;Alive: 0&quot;);
add(alive);
var gridPanel = new JPanel();
gridPanel.setLayout(new GridLayout(size, size, 0, 0));
contentPane.add(gridPanel);
var cellArray = new javax.swing.JPanel[size][size];
for (var i = 0; i &lt; size; i++) {
for (var j = 0; j &lt; size; j++) {
var cell = new JPanel();
cellArray[i][j] = cell;
cell.setBorder(BorderFactory.createLineBorder(Color.BLACK));
gridPanel.add(cell);
}
}
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
var button = new JButton();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
generateGrid(cellArray);
alive.setText(&quot;Alive: &quot; + countAlive(life.grid));
incrementGeneration();
generationMaker.setText(&quot;Generation #&quot; + generationCounter);
}
});
contentPane.add(button);
setVisible(true);
}
private void generateGrid(JPanel[][] cellArray) {
var grid2 = getGrid();
fillInPanels(cellArray, grid2);
life.grid = grid2;
}
protected void fillInPanels(javax.swing.JPanel[][] panelArray, boolean[][] grid) {
for (var i = 0; i &lt; size; i++) {
for (var j = 0; j &lt; size; j++) {
if (grid[i][j]) {
panelArray[i][j].setBackground(Color.BLACK);
} else {
panelArray[i][j].setBackground(Color.WHITE);
}
}
}
}

It works fine, and is a great emulator of Conway's game of life, but it has a strange effect where the entire screen doesn't change right away, but you can see the individual cells changing, and not changing right away, right when I press the button. Is this because of double buffering? It works better when there are less cells alive on screen, and that is when it actually starts going quickly.

Here is how it is like on a 35 by 35 size grid

What is the source of the problem and how do I solve it? Please forgive me if I have poor formatting on either the question or the post, this is my first time posting here.

答案1

得分: 0

The cause of the problem was that the grid was being redrawn every time I changed the paint color of a tile, from black to white or vice versa. Setting "setVisible" to false while "fillInPanels" was executing, and setting it back to true afterwards solved the issue.

英文:

The cause of the problem was that the grid was being redrawn every time I changed the paint color of a tile, from black to white or vice versa. Setting setVisible to false while fillInPanels was executing, and setting it back to true afterwards solved the issue.

huangapple
  • 本文由 发表于 2020年8月1日 09:30:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/63200924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定