JFrame面板变速旋转:从快到慢整数插值及数组存储咨询
嘿,这个需求很常见,我来帮你搞定!下面就一步步实现你要的「先快后慢」变速旋转效果,同时把所有角度值存入数组中,还会修正你原来代码里的Swing线程问题~
实现JFrame面板的变速旋转(先快后慢)
首先得提一句:你原来用for循环+Thread.sleep()的方式其实不太适合Swing,因为会阻塞事件调度线程(EDT),导致界面卡顿甚至假死。我们先解决「变速角度生成」的核心问题,再结合Swing推荐的动画方式来实现。
一、生成「先快后慢」的角度数组
要实现初始速度快、后期逐渐减速的平滑效果,我们可以用非线性插值函数。这里推荐用余弦函数的变种,它能自然实现从快到慢的过渡,而且最终刚好停在360度。
公式逻辑:angle = 360 * (1 - cos( (t / 总帧数) * π/2 ))
t是当前步数(从0到总帧数)- 当
t=0时,角度为0,旋转速度最快;当t接近总帧数时,角度趋近360,速度慢慢降到0
生成角度数组的代码:
import java.util.ArrayList; import java.util.List; import java.lang.Math; public class RotationAngleGenerator { // 生成变速旋转的整数角度数组 public static int[] generateSlowdownAngles(int totalFrames) { List<Integer> angleList = new ArrayList<>(); for (int t = 0; t <= totalFrames; t++) { // 计算当前帧的角度,转为整数 double progress = t / (double) totalFrames; double radians = progress * Math.PI / 2; double angle = 360 * (1 - Math.cos(radians)); angleList.add((int) Math.round(angle)); } // 转成int数组返回 return angleList.stream().mapToInt(Integer::intValue).toArray(); } }
你可以调整totalFrames来控制动画总时长——比如设为120,配合后面15ms的帧间隔,总时长就是1.8秒。如果想要其他减速节奏,也可以换成二次函数:angle = 360 * Math.pow(progress, 2),同样是先快后慢,只是减速的斜率不同。
二、在Swing中正确实现变速旋转动画
用javax.swing.Timer来处理动画,它会在EDT中定时触发事件,保证界面响应不卡顿。完整示例代码:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class RotatingPanelDemo extends JFrame { private JPanel rotatingPanel; private int[] rotationAngles; private int currentFrame = 0; public RotatingPanelDemo() { setTitle("变速旋转面板"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 400); setLocationRelativeTo(null); // 创建要旋转的面板(这里画个蓝色方块方便看效果) rotatingPanel = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); // 以面板中心为旋转原点 int centerX = getWidth() / 2; int centerY = getHeight() / 2; // 应用当前帧的旋转角度 g2d.rotate(Math.toRadians(rotationAngles[currentFrame]), centerX, centerY); // 绘制测试图形 g2d.setColor(Color.BLUE); g2d.fillRect(centerX - 50, centerY - 50, 100, 100); g2d.dispose(); } }; add(rotatingPanel); // 生成120帧的变速角度数组 rotationAngles = RotationAngleGenerator.generateSlowdownAngles(120); // 创建Timer,每15ms触发一次帧更新 Timer timer = new Timer(15, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (currentFrame < rotationAngles.length - 1) { currentFrame++; rotatingPanel.repaint(); // 重绘面板应用新角度 } else { ((Timer) e.getSource()).stop(); // 动画结束停止Timer } } }); timer.start(); // 启动动画 } public static void main(String[] args) { // 在EDT中启动界面,保证线程安全 SwingUtilities.invokeLater(() -> new RotatingPanelDemo().setVisible(true)); } }
三、关键细节说明
- 整数角度处理:用
Math.round()把浮点角度转成整数,完全符合你要的整数插值效果 - EDT安全:所有界面操作都在EDT中进行,避免了线程冲突问题
- 调整动画快慢:可以通过修改
totalFrames(帧数越多越慢)或Timer的间隔值(比如把15改成20,每帧间隔更长)来控制总时长
内容的提问来源于stack exchange,提问作者Icomar
相关产品推荐
相关产品推荐

