You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(),但移除方块的旧面板没有触发重绘,系统不知道要刷新这部分区域。只有调整窗口时,系统会自动触发全局重绘,这时才会显示方块的新位置。

  • 修复要点:

    1. 移除红色方块后,给旧面板同时调用revalidate()和repaint(),清空旧位置的显示残留
    2. 添加红色方块到新面板后,除了revalidate(),也要调用repaint()强制刷新新区域
    3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:54:59