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; } }
关键修正说明
- 线程启动:在Application构造方法中创建Circle实例后,直接调用
start()启动线程,触发run方法中的移动循环。 - 界面重绘:每次移动后通过
SwingUtilities.invokeLater触发重绘,确保在Swing事件线程中执行绘制操作,避免线程安全问题和界面闪烁。 - 边界逻辑修复:原代码的边界判断逻辑完全错误,现在改为判断圆形边缘是否超出窗口边界,碰到后反转速度方向,实现正确的反弹效果。
- 绘制优化:改用JPanel的
paintComponent方法负责绘制,这是Swing官方推荐的组件绘制方式,比直接重写JFrame的paint更稳定,避免干扰窗口标题栏、边框等元素的绘制。 - 冗余代码移除:删除main方法中多余的Application实例创建,避免打开两个窗口。
内容的提问来源于stack exchange,提问作者Umutcan Adıgüzel
相关产品推荐
相关产品推荐

