求助: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:
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); } }
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

