Java Swing弹跳小球启动线程后初始坐标不生效问题
问题根源
你碰到的核心问题是线程启动时机过早+首次获取画板尺寸为0触发了边界修正:
- 你在
Board类的构造函数里就直接启动了移动线程,但此时Board组件还没被添加到JFrame完成布局渲染,第一次调用getWidth()/getHeight()拿到的返回值是0 - 线程第一次循环就会执行坐标更新+边界判断:你初始的X=243、Y=104,判断
X + radius > width(243+4>0)成立,直接触发边界修正逻辑把X重置为radius=4,同理Y也会被重置为4,自然就跑到左上角了。
修复方案
两个改法选一个即可,推荐第二种更符合Swing开发规范:
方案1:新增尺寸有效性判断,未完成初始化时不更新坐标
修改线程内的逻辑即可,原有代码其余部分不用动:
public void run() { while (true) { repaint(); width = getWidth(); height = getHeight(); // 新增判断:宽高未初始化完成时跳过坐标更新 if (width <= 0 || height <= 0) { try { Thread.sleep(10); } catch(InterruptedException ex) {} continue; } // 原有坐标更新、边界判断逻辑保持不变 X = X + dx ; Y = Y + dy; if (X - radius < 0) { dx = -dx; X = radius; } else if (X + radius > width) { dx = -dx; X = width - radius; } if (Y - radius < 0) { dy = -dy; Y = radius; } else if (Y + radius > height) { dy = -dy; Y = height - radius; } try { Thread.sleep(10); } catch(InterruptedException ex) {} } }
也可以选择把线程启动逻辑移到main方法的frame.setVisible(true)之后,此时组件已经完成渲染,宽高是正确值,也能解决问题。
方案2:替换自定义线程为Swing Timer(避免Swing线程安全问题)
Swing官方更推荐用javax.swing.Timer处理界面周期性更新,不需要自己管理线程,修改构造函数即可:
public Board() { // 删掉原有自定义Thread的代码,替换为Timer实现 javax.swing.Timer timer = new javax.swing.Timer(10, e -> { width = getWidth(); height = getHeight(); if (width <=0 || height <=0) return; X = X + dx ; Y = Y + dy; if (X - radius < 0) { dx = -dx; X = radius; } else if (X + radius > width) { dx = -dx; X = width - radius; } if (Y - radius < 0) { dy = -dy; Y = radius; } else if (Y + radius > height) { dy = -dy; Y = height - radius; } repaint(); }); timer.start(); }
内容的提问来源于stack exchange,提问作者GunTish
相关产品推荐
相关产品推荐

