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

Java图形编程含事件处理:解决小球重复绘制问题

Hey there! Let’s fix that annoying repeated ball drawing issue in your Java graphics program. I’ve dealt with this exact problem plenty of times, so here’s the breakdown of what’s going wrong and how to fix it step by step:

Why Your Ball Keeps Getting Redrawn Repeatedly

Java Swing uses a passive drawing system—every time your component (like a JFrame) needs to refresh (e.g., window resizing, being uncovered), its paint/paintComponent method gets called automatically. If you’re drawing the ball directly inside event handlers (like key presses or mouse moves), you’re adding a new ball instance every time the event fires, leading to overlapping drawings. You’re also not clearing the old drawings before rendering the new state.

Step-by-Step Fix

1. Use a JPanel for Custom Drawing

Never draw directly on a JFrame—use a dedicated JPanel instead. Its paintComponent method is designed for custom graphics, and calling super.paintComponent(g) will automatically clear the old canvas before drawing new content.

2. Only Update State, Let paintComponent Handle Drawing

Store the ball’s coordinates as class variables. In your event handlers, only update these coordinates and call repaint() to trigger a fresh render. This ensures you’re always drawing one ball at its latest position.

3. Fix Event Listener Registration

You implemented MouseMotionListener but forgot to register it in your constructor. Also, make sure your component can receive keyboard focus so KeyListener works.

Full Corrected Code

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MouseGui extends JFrame {
    // Ball coordinates and size
    private int ballX = 10;
    private int ballY = 10;
    private static final int BALL_SIZE = 20;
    
    // Fixed rectangle properties
    private final int RECT_X = 200;
    private final int RECT_Y = 200;
    private final int RECT_WIDTH = 50;
    private final int RECT_HEIGHT = 50;
    private final int MOVE_STEP = 5; // Movement speed for ball

    public MouseGui() {
        initComponents();
        DrawingPanel drawingPanel = new DrawingPanel();
        
        // Register key listener for direction control
        drawingPanel.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_UP: ballY -= MOVE_STEP; break;
                    case KeyEvent.VK_DOWN: ballY += MOVE_STEP; break;
                    case KeyEvent.VK_LEFT: ballX -= MOVE_STEP; break;
                    case KeyEvent.VK_RIGHT: ballX += MOVE_STEP; break;
                }
                drawingPanel.repaint(); // Trigger fresh render
            }
        });
        
        // Register mouse motion listener for ball-to-rectangle tracking
        drawingPanel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                // Calculate direction to rectangle center
                int rectCenterX = RECT_X + RECT_WIDTH / 2;
                int rectCenterY = RECT_Y + RECT_HEIGHT / 2;
                
                // Move ball toward rectangle center step by step
                if (Math.abs(ballX - rectCenterX) > MOVE_STEP) {
                    ballX += (rectCenterX > ballX) ? MOVE_STEP : -MOVE_STEP;
                }
                if (Math.abs(ballY - rectCenterY) > MOVE_STEP) {
                    ballY += (rectCenterY > ballY) ? MOVE_STEP : -MOVE_STEP;
                }
                drawingPanel.repaint(); // Trigger fresh render
            }
        });
        
        drawingPanel.setFocusable(true); // Allow panel to receive keyboard input
        this.add(drawingPanel);
        this.setSize(400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    // Custom panel for drawing logic
    private class DrawingPanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); // Clear old drawings first
            
            // Draw rectangle
            g.setColor(Color.BLUE);
            g.fillRect(RECT_X, RECT_Y, RECT_WIDTH, RECT_HEIGHT);
            
            // Draw ball at current coordinates
            g.setColor(Color.RED);
            // Offset coordinates to center the ball on (ballX, ballY)
            g.fillOval(ballX - BALL_SIZE/2, ballY - BALL_SIZE/2, BALL_SIZE, BALL_SIZE);
        }
    }

    // IDE-generated init method (keep your existing code here)
    private void initComponents() {
        this.setTitle("Ball & Rectangle Controller");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(MouseGui::new); // Run on Swing thread
    }
}

Key Notes About This Solution

  • Single Drawing Source: All rendering happens in paintComponent, so you never have overlapping ball drawings—super.paintComponent(g) clears the canvas each time.
  • State-Driven Updates: Event handlers only modify the ball’s coordinates, then call repaint() to tell Swing to redraw the latest state.
  • Mouse Tracking Logic: The ball smoothly moves toward the rectangle’s center whenever the mouse moves (you can adjust MOVE_STEP to change speed).
  • Focus Management: Setting setFocusable(true) on the panel ensures keyboard events are detected.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:05:10