英文:
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的生命游戏,但是在按下按钮后,整个屏幕不会立即改变,而是可以看到单个单元格的变化,而且不会立即改变。这是否与双缓冲有关?当屏幕上的存活单元格较少时,它的运行效果更好,而且速度更快。
问题的根本原因和解决方法是什么?如果我的问题或帖子格式不好,请原谅,这是我第一次在这里发布。
解决方案:这个问题可能与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("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);
}
}
}
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论