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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 22:52:58