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

Java JFrame双弹跳球图形显示异常问题求助

Hey there! Let's break down what's going wrong with your bouncing balls and fix them step by step.

First, let's identify the core issues:

  • Layout Manager Misuse: Using FlowLayout forces each of your Main instances (I assume it's a JPanel subclass) to act as separate, small components. This means each ball's coordinates are relative to its tiny panel, not the whole window—plus, multiple components redrawing independently causes that stuttering.
  • EDT Violations: Your while(true) loop with Thread.sleep() runs directly in the main thread, which breaks Swing's single-thread rule. All UI updates should happen on the Event Dispatch Thread (EDT) to avoid freezes and glitches.
  • Component Structure: Having one component per ball is inefficient; you should draw all balls on a single panel for better control and performance.

Here's the Fixed Solution

Let's restructure the code to follow Swing best practices:

1. Create a Ball Class to Encapsulate Ball Data

This keeps each ball's properties and movement logic clean and reusable:

import java.awt.Color;

public class Ball {
    private int x;
    private int y;
    private int xDir;
    private int yDir;
    private final Color color;
    private static final int SIZE = 50;

    public Ball(int startX, int startY, Color color) {
        this.x = startX;
        this.y = startY;
        this.color = color;
        // Random initial direction for natural movement
        this.xDir = Math.random() > 0.5 ? 1 : -1;
        this.yDir = Math.random() > 0.5 ? 1 : -1;
    }

    public void move(int panelWidth, int panelHeight) {
        x += xDir;
        y += yDir;

        // Bounce off left/right edges
        if (x < 0 || x > panelWidth - SIZE) {
            xDir *= -1;
        }
        // Bounce off top/bottom edges
        if (y < 0 || y > panelHeight - SIZE) {
            yDir *= -1;
        }
    }

    // Getters for drawing
    public int getX() { return x; }
    public int getY() { return y; }
    public Color getColor() { return color; }
    public int getSize() { return SIZE; }
}

2. Build a Single BallPanel to Manage All Balls

This panel handles drawing all balls and updating their positions using a Swing Timer (the correct way to do Swing animations):

import java.awt.Graphics;
import java.awt.Color;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

public class BallPanel extends JPanel {
    private List<Ball> balls;

    public BallPanel() {
        balls = new ArrayList<>();
        // Add your two balls
        balls.add(new Ball(50, 50, Color.RED));
        balls.add(new Ball(200, 200, Color.BLUE));

        // Swing Timer triggers updates on the EDT (no more thread issues!)
        Timer animationTimer = new Timer(5, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                updateAllBalls();
                repaint();
            }
        });
        animationTimer.start();
    }

    private void updateAllBalls() {
        for (Ball ball : balls) {
            ball.move(getWidth(), getHeight());
        }
    }

    // Always use paintComponent for custom Swing drawing (not paint!)
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // Clear the panel background
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());

        // Draw every ball
        for (Ball ball : balls) {
            g.setColor(ball.getColor());
            g.fillOval(ball.getX(), ball.getY(), ball.getSize(), ball.getSize());
        }
    }
}

3. The Main Class to Launch the App

We initialize the UI on the EDT to follow Swing rules:

import javax.swing.JFrame;

public class BouncingBallsDemo {
    public static void main(String[] args) {
        // Run UI setup on the Event Dispatch Thread
        javax.swing.SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Bouncing Balls");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 400);
            frame.add(new BallPanel());
            frame.setVisible(true);
        });
    }
}

Key Improvements Explained

  • Single Panel Drawing: All balls live in one panel, so their coordinates are relative to the whole window, and we only need one repaint call per frame.
  • Swing Timer: Ensures all animation updates run on the EDT, eliminating stutters and thread safety issues.
  • Encapsulated Ball Logic: The Ball class keeps code organized—adding more balls later is as simple as calling balls.add(new Ball(...)).
  • paintComponent Instead of paint: This is the standard method for custom drawing in Swing, as it avoids interfering with border/child component drawing.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:58:37