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

求助:Swing小游戏方块每秒重绘失效与点击后空指针异常问题

Hey there! Let's fix your two issues and get your click-the-square game working as intended. I'll break down the solutions step by step:

1. Fixing the NullPointerException

The error pops up because after you click the square, you set point = null and trigger a repaint. In your paintComponent method, you’re calling controller.updateLabel(point) outside the if (point != null) check—so when point is null, updateLabel tries to access point.x and point.y, which causes the null pointer exception.

Fix: Move the controller.updateLabel(point) call inside the if (point != null) block in paintComponent:

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (point != null) {
        g.drawRect(point.x, point.y, rectWidth - 1, rectHeight - 1);
        g.setColor(Color.yellow);
        g.fillRect(point.x + 1, point.y + 1, rectWidth - 2, rectHeight - 2);
        // Only update the label when the point exists
        controller.updateLabel(point);
    }
}
2. Implementing Automatic Rectangle Redraw Every Second

Your Timer is running but doing nothing because the actionPerformed method is empty. We need to make it generate a new random square every second. Also, your current logic stops the Timer when you click a square—we shouldn’t do that if we want the game to keep spawning new squares until the time runs out.

Fixes:

  • Add a score variable to track successful clicks, and update the UI to display it.
  • Make the Timer spawn a new random square every second in actionPerformed.
  • Adjust the click logic to increment the score and spawn a new square immediately for better feedback.

Here's the full modified code with all fixes and score tracking added:

import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class RectangleDemo extends JPanel {
    JLabel clickLabel;
    JLabel scoreLabel;
    int score = 0;

    void buildUI(Container container) {
        container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
        RectangleArea rectangleArea = new RectangleArea(this);
        container.add(rectangleArea);
        
        clickLabel = new JLabel("Click within the framed area.");
        scoreLabel = new JLabel("Score: 0");
        container.add(clickLabel);
        container.add(scoreLabel);
        
        rectangleArea.setAlignmentX(LEFT_ALIGNMENT);
        clickLabel.setAlignmentX(LEFT_ALIGNMENT);
        scoreLabel.setAlignmentX(LEFT_ALIGNMENT);
    }

    public void updateLabel(Point point) {
        clickLabel.setText("Click occurred at coordinate (" + point.x + ", " + point.y + ").");
    }

    public void incrementScore() {
        score++;
        scoreLabel.setText("Score: " + score);
    }

    public static void main(String[] args) {
        JFrame f = new JFrame("Click the Square Game");
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        RectangleDemo controller = new RectangleDemo();
        controller.buildUI(f.getContentPane());
        f.pack();
        f.setVisible(true);

        // Add game duration timer (30 seconds by default)
        Timer gameTimer = new Timer(30000, e -> {
            JOptionPane.showMessageDialog(f, "Game Over! Your score is: " + controller.score);
            System.exit(0);
        });
        gameTimer.setRepeats(false);
        gameTimer.start();
    }
}

class RectangleArea extends JPanel implements ActionListener {
    Random rand = new Random();
    Point point;
    RectangleDemo controller;
    Dimension preferredSize = new Dimension(500, 500);
    int rectWidth = 50;
    int rectHeight = 50;
    Timer spawnTimer;

    public void actionPerformed(ActionEvent e) {
        // Generate new random square position each second
        int a = rand.nextInt(400);
        int b = rand.nextInt(400);
        point = new Point(a, b);
        repaint();
    }

    public RectangleArea(RectangleDemo controller) {
        this.controller = controller;
        // Initialize first square
        point = new Point(rand.nextInt(400), rand.nextInt(400));
        
        // Start spawn timer (1 second intervals)
        spawnTimer = new Timer(1000, this);
        spawnTimer.start();

        Border raisedBevel = BorderFactory.createRaisedBevelBorder();
        Border loweredBevel = BorderFactory.createLoweredBevelBorder();
        Border compound = BorderFactory.createCompoundBorder(raisedBevel, loweredBevel);
        setBorder(compound);

        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                int x = e.getX();
                int y = e.getY();
                if (point != null && point.x <= x && x <= point.x + rectWidth 
                    && point.y <= y && y <= point.y + rectHeight) {
                    // Increment score when square is clicked
                    controller.incrementScore();
                    // Spawn new square immediately
                    int a = rand.nextInt(400);
                    int b = rand.nextInt(400);
                    point = new Point(a, b);
                    repaint();
                }
            }
        });
    }

    public Dimension getPreferredSize() {
        return preferredSize;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (point != null) {
            g.drawRect(point.x, point.y, rectWidth - 1, rectHeight - 1);
            g.setColor(Color.yellow);
            g.fillRect(point.x + 1, point.y + 1, rectWidth - 2, rectHeight - 2);
            controller.updateLabel(point);
        }
    }
}

Key changes made:

  • Added score tracking with a dedicated label
  • Fixed the null pointer exception by moving the label update inside the non-null check
  • Made the spawn Timer generate a new square every second in actionPerformed
  • Adjusted click logic to increment score and spawn a new square immediately
  • Added a game duration timer (30 seconds by default) that shows the final score when time runs out

内容的提问来源于stack exchange,提问作者TheDayAfterDark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:16:04