为何用while循环绘制国际象棋棋盘在台式机显示后消失,笔记本正常?
问题:国际象棋棋盘绘制后瞬间消失
我用while循环绘制国际象棋棋盘,但棋盘方块显示一秒后就消失了。这段代码在笔记本上运行完全正常,但放到台式机上就出现问题——笔记本上棋盘能正常显示,台式机上棋盘只闪一下就没了。
面板代码
package chess; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import javax.swing.JPanel; public class ChessBoard extends JPanel{ public int tileSize = 90; public int cols = 8; public int rows = 8; public int maxCols = cols * tileSize; public int maxRows = rows * tileSize; TileManager tileM = new TileManager(this); ChessBoard(){ this.setPreferredSize(new Dimension(maxCols, maxRows)); this.setBackground(Color.black); this.setDoubleBuffered(true); this.setFocusable(true); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; tileM.drawTiles(g2); } }
绘制逻辑代码
package chess; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import javax.imageio.ImageIO; public class TileManager { ChessBoard cb; public static int [] types = new int[10]; private static int rows = 0; private static int cols = 0; private boolean c = true; String [] alpha = {"a", "b", "c", "d", "e", "f", "g", "h"}; String [] num = {"8", "7", "6", "5", "4", "3", "2", "1"}; TileManager(ChessBoard cb){ this.cb = cb; } public void drawTiles(Graphics g) { Graphics2D g2 = (Graphics2D)g; while (rows < cb.rows && cols < cb.cols) { if (c) g.setColor(Color.white); if (!c) g.setColor(Color.black); g2.setFont(new Font("Comic Sans", Font.BOLD, 20)); g2.fillRect(cols * cb.tileSize, rows * cb.tileSize, cb.tileSize, cb.tileSize); g2.setColor(Color.green); g2.drawString(alpha[cols], 5 + cols * cb.tileSize, 20 + rows * cb.tileSize); g2.drawString(num[rows], 75 + cols * cb.tileSize, 85 + rows * cb.tileSize); c = !c; cols++; if (cols == 8) { c = !c; cols = 0; rows++; } } } }
问题原因
核心问题出在TileManager里的rows和cols被声明为static:
- 第一次调用
drawTiles时,循环会把rows和cols递增到8,满足循环终止条件。 - Swing的
paintComponent方法会被系统多次调用(比如窗口移动、最小化恢复、其他窗口遮挡后恢复等),当第二次调用drawTiles时,rows和cols还是8,循环条件rows < cb.rows && cols < cb.cols不成立,所以不会绘制任何内容,看起来就是棋盘消失了。 - 笔记本可能刚好没触发额外的重绘,所以第一次绘制后没被刷新,而台式机触发了重绘,就出现了消失的问题。
修复方案
把rows和cols的static修饰符去掉,并且每次调用drawTiles时初始化这两个变量为0,确保每次重绘都能重新执行循环绘制棋盘:
修改后的TileManager核心代码:
public class TileManager { ChessBoard cb; public static int [] types = new int[10]; // 去掉static修饰符 private int rows = 0; private int cols = 0; private boolean c = true; String [] alpha = {"a", "b", "c", "d", "e", "f", "g", "h"}; String [] num = {"8", "7", "6", "5", "4", "3", "2", "1"}; TileManager(ChessBoard cb){ this.cb = cb; } public void drawTiles(Graphics g) { Graphics2D g2 = (Graphics2D)g; // 每次绘制前重置变量 rows = 0; cols = 0; c = true; while (rows < cb.rows && cols < cb.cols) { g.setColor(c ? Color.white : Color.black); g2.setFont(new Font("Comic Sans", Font.BOLD, 20)); g2.fillRect(cols * cb.tileSize, rows * cb.tileSize, cb.tileSize, cb.tileSize); g2.setColor(Color.green); g2.drawString(alpha[cols], 5 + cols * cb.tileSize, 20 + rows * cb.tileSize); g2.drawString(num[rows], 75 + cols * cb.tileSize, 85 + rows * cb.tileSize); c = !c; cols++; if (cols == 8) { c = !c; cols = 0; rows++; } } } }
另外,也可以把while循环换成for循环,逻辑会更清晰,避免变量重置的问题:
public void drawTiles(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.setFont(new Font("Comic Sans", Font.BOLD, 20)); for(int row = 0; row < cb.rows; row++){ boolean isWhite = row % 2 == 0; for(int col = 0; col < cb.cols; col++){ g.setColor(isWhite ? Color.white : Color.black); g2.fillRect(col * cb.tileSize, row * cb.tileSize, cb.tileSize, cb.tileSize); g2.setColor(Color.green); g2.drawString(alpha[col], 5 + col * cb.tileSize, 20 + row * cb.tileSize); g2.drawString(num[row], 75 + col * cb.tileSize, 85 + row * cb.tileSize); isWhite = !isWhite; } } }
内容的提问来源于stack exchange,提问作者NotQuiteSoInvisible
相关产品推荐
相关产品推荐

