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

Java Swing多线程圆形移动:线程启动位置咨询

Java Swing圆形移动线程启动方案及代码修正

核心问题解决:线程启动位置

你需要在Application类的构造方法中,创建完每个Circle实例后立刻调用start()方法,因为Circle继承自Thread,调用start()才会启动线程执行run方法中的移动逻辑。

完整修正代码及优化点

原代码存在线程启动缺失、边界判断逻辑错误、界面重绘未触发、Swing绘制不规范等问题,以下是修正后的完整代码:

修正后的Application类

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Application extends JFrame {
    public Circle c1, c2, c3;
    private DrawPanel drawPanel;

    public Application() {
        drawPanel = new DrawPanel();
        add(drawPanel);

        // 定义窗口边界:左、上、右、下(预留圆形直径10的空间)
        int[] windowBounds = new int[]{0, 0, 990, 990};
        c1 = new Circle(100, 100, 2, 2, windowBounds, Color.blue, drawPanel);
        c2 = new Circle(150, 150, -2, 0, windowBounds, Color.red, drawPanel);
        c3 = new Circle(50, 150, 2, -2, windowBounds, Color.green, drawPanel);

        // 启动每个圆形的线程
        c1.start();
        c2.start();
        c3.start();

        setSize(1000, 1000);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    // 用JPanel负责绘制(Swing推荐方式)
    private class DrawPanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(c1.getColor());
            g.fillOval(c1.getX(), c1.getY(), 10, 10);
            g.setColor(c2.getColor());
            g.fillOval(c2.getX(), c2.getY(), 10, 10);
            g.setColor(c3.getColor());
            g.fillOval(c3.getX(), c3.getY(), 10, 10);
        }
    }

    public static void main(String[] args) {
        // 仅创建一个Application实例(原代码创建两个是冗余错误)
        new Application();
    }
}

修正后的Circle类

import java.awt.Color;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Circle extends Thread {
    private int x, y;
    private int xs, ys;
    private Color color;
    private int[] boundaries;
    private JPanel drawPanel;

    public Circle(int x, int y, int xs, int ys, int[] boundaries, Color color, JPanel drawPanel) {
        this.x = x;
        this.y = y;
        this.xs = xs;
        this.ys = ys;
        this.boundaries = boundaries; // 边界定义:[0]左, [1]上, [2]右, [3]下
        this.color = color;
        this.drawPanel = drawPanel;
    }

    @Override
    public void run() {
        while (true) {
            move();
            // 在Swing事件线程中触发重绘(线程安全要求)
            SwingUtilities.invokeLater(() -> drawPanel.repaint());
            try {
                Thread.sleep(100); // 控制移动帧率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void move() {
        updateSpeedInformation();
        this.x += this.xs;
        this.y += this.ys;
    }

    // 修正边界碰撞逻辑:碰到边缘反转移动方向
    private void updateSpeedInformation() {
        // 左右边界判断(圆形右边缘 = x + 直径10)
        if (x < boundaries[0] || x + 10 > boundaries[2]) {
            xs *= -1;
        }
        // 上下边界判断(圆形下边缘 = y + 直径10)
        if (y < boundaries[1] || y + 10 > boundaries[3]) {
            ys *= -1;
        }
    }

    public int getX() {
        return x;
    }

    public Color getColor() {
        return color;
    }

    public int getY() {
        return y;
    }
}

关键修正说明

  1. 线程启动:在Application构造方法中创建Circle实例后,直接调用start()启动线程,触发run方法中的移动循环。
  2. 界面重绘:每次移动后通过SwingUtilities.invokeLater触发重绘,确保在Swing事件线程中执行绘制操作,避免线程安全问题和界面闪烁。
  3. 边界逻辑修复:原代码的边界判断逻辑完全错误,现在改为判断圆形边缘是否超出窗口边界,碰到后反转速度方向,实现正确的反弹效果。
  4. 绘制优化:改用JPanel的paintComponent方法负责绘制,这是Swing官方推荐的组件绘制方式,比直接重写JFrame的paint更稳定,避免干扰窗口标题栏、边框等元素的绘制。
  5. 冗余代码移除:删除main方法中多余的Application实例创建,避免打开两个窗口。

内容的提问来源于stack exchange,提问作者Umutcan Adıgüzel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:25:23