Java Swing中JFrame未即时更新,仅调整窗口后生效问题求助
问题:WASD移动红色方块无即时视觉反馈,调整窗口后才显示移动
我正在做学校项目的小游戏,遇到个问题:本该用WASD键移动的红色方块,按完键后看不到移动效果,只有调整或最大化窗口后,才发现方块其实已经移动了。附上我的代码:
package Mini_Game; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class GridGUI extends JFrame implements KeyListener { private JPanel[][] squarePanels; private JPanel redDot; private int redDotRow; private int redDotCol; public GridGUI() { setTitle("10x10 Grid"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel gridPanel = new JPanel(new GridLayout(11, 11)); // create a panel with 11x11 grid layout (including labels) // add labels for x-axis numbers gridPanel.add(new JLabel("")); // empty label for top-left corner for (int i = 1; i <= 10; i++) { JLabel label = new JLabel(Integer.toString(i), SwingConstants.CENTER); gridPanel.add(label); } // add labels for y-axis numbers and grid squares squarePanels = new JPanel[10][10]; for (int i = 1; i <= 10; i++) { JLabel label = new JLabel(Integer.toString(i), SwingConstants.CENTER); gridPanel.add(label); // add y-axis label for (int j = 1; j <= 10; j++) { JPanel squarePanel = new JPanel(new BorderLayout()); // create a panel for each grid square squarePanel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); // add a border to the square squarePanel.add(new JLabel(), BorderLayout.CENTER); // add an empty label to center the number gridPanel.add(squarePanel); // add the square panel to the grid squarePanels[i-1][j-1] = squarePanel; // add the square panel to the 2D array } } // create the red dot component and add it to the top-left square panel redDot = new JPanel(); redDot.setPreferredSize(new Dimension(10, 10)); redDot.setBackground(Color.RED); squarePanels[4][4].add(redDot); redDotRow = 4; redDotCol = 4; // create the blue square component and add it to a square panel JPanel blueSquare = new JPanel(); blueSquare.setPreferredSize(new Dimension(20, 20)); blueSquare.setBackground(Color.BLUE); squarePanels[4][5].add(blueSquare); squarePanels[4][5].revalidate(); // repaint the panel add(gridPanel); // add the grid panel to the frame gridPanel.addKeyListener(this); pack(); // resize the frame to fit the grid setLocationRelativeTo(null); // center the frame on the screen setVisible(true); // make the frame visible gridPanel.requestFocus(); // give focus to the panel addKeyListener(this); // add the key listener to the frame setFocusable(true); } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); System.out.println("Key pressed: " + keyCode); if (keyCode == KeyEvent.VK_W) { if (redDotRow > 0) { // check if the red dot can move up squarePanels[redDotRow][redDotCol].remove(redDot); // remove the red dot from the current panel redDotRow--; // decrement the row of the red dot squarePanels[redDotRow][redDotCol].add(redDot); // add the red dot to the new panel squarePanels[redDotRow][redDotCol].revalidate(); // repaint the new panel } } else if (keyCode == KeyEvent.VK_S) { if (redDotRow < 9) { // check if the red dot can move down squarePanels[redDotRow][redDotCol].remove(redDot); // remove the red dot from the current panel redDotRow++; // increment the row of the red dot squarePanels[redDotRow][redDotCol].add(redDot); // add the red dot to the new panel squarePanels[redDotRow][redDotCol].revalidate(); // repaint the new panel } } else if (keyCode == KeyEvent.VK_A) { if (redDotCol > 0) { // check if the red dot can move left squarePanels[redDotRow][redDotCol].remove(redDot); // remove the red dot from the current panel redDotCol--; // decrement the column of the red dot squarePanels[redDotRow][redDotCol].add(redDot); // add the red dot to the new panel squarePanels[redDotRow][redDotCol].revalidate(); // repaint the new panel } } else if (keyCode == KeyEvent.VK_D) { if (redDotCol < 9) { // check if the red dot can move right squarePanels[redDotRow][redDotCol].remove(redDot); // remove the red dot from the current panel redDotCol++; // increment the column of the red dot squarePanels[redDotRow][redDotCol].add(redDot); // add the red dot to the new panel squarePanels[redDotRow][redDotCol].revalidate(); // repaint the new panel } } } @Override public void keyTyped(KeyEvent e) { // do nothing } @Override public void keyReleased(KeyEvent e) { // do nothing } public static void main(String[] args) { new GridGUI(); GridGUI gridGUI = new GridGUI(); gridGUI.requestFocusInWindow(); } }
解决方案
问题根源:代码只在新位置的面板调用了
revalidate(),但移除方块的旧面板没有触发重绘,系统不知道要刷新这部分区域。只有调整窗口时,系统会自动触发全局重绘,这时才会显示方块的新位置。修复要点:
- 移除红色方块后,给旧面板同时调用
revalidate()和repaint(),清空旧位置的显示残留 - 添加红色方块到新面板后,除了
revalidate(),也要调用repaint()强制刷新新区域 - main方法里重复创建了两个
GridGUI实例,属于冗余代码,删掉其中一个即可
- 移除红色方块后,给旧面板同时调用
修改后的keyPressed方法:
@Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); System.out.println("Key pressed: " + keyCode); if (keyCode == KeyEvent.VK_W) { if (redDotRow > 0) { // 处理旧面板:移除后刷新 squarePanels[redDotRow][redDotCol].remove(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); redDotRow--; // 处理新面板:添加后刷新 squarePanels[redDotRow][redDotCol].add(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); } } else if (keyCode == KeyEvent.VK_S) { if (redDotRow < 9) { squarePanels[redDotRow][redDotCol].remove(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); redDotRow++; squarePanels[redDotRow][redDotCol].add(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); } } else if (keyCode == KeyEvent.VK_A) { if (redDotCol > 0) { squarePanels[redDotRow][redDotCol].remove(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); redDotCol--; squarePanels[redDotRow][redDotCol].add(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); } } else if (keyCode == KeyEvent.VK_D) { if (redDotCol < 9) { squarePanels[redDotRow][redDotCol].remove(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); redDotCol++; squarePanels[redDotRow][redDotCol].add(redDot); squarePanels[redDotRow][redDotCol].revalidate(); squarePanels[redDotRow][redDotCol].repaint(); } } }
- 修正后的main方法:
public static void main(String[] args) { GridGUI gridGUI = new GridGUI(); gridGUI.requestFocusInWindow(); }
内容的提问来源于stack exchange,提问作者HHEA
相关产品推荐
相关产品推荐

