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

在JPanel中实现三角形旋转动画遇闪烁消失问题求助

嘿,我太懂你这个坑了!在Swing里搞动画,线程处理不对真的会出现这种“闪一下就没了”的情况,我当初学的时候也踩过同样的雷😅

解决Swing中三角形旋转闪烁消失的问题

问题根源

Swing是单线程UI框架,所有和UI相关的更新(包括绘制、组件状态修改)都必须在**事件调度线程(EDT)**里执行。你直接在自定义线程里循环修改旋转角度并调用repaint(),会导致线程安全冲突:EDT和你的工作线程同时操作绘制状态,轻则画面闪烁,重则组件直接“消失”或者卡死。另外,如果你的循环没有给线程留休息时间,会把CPU占满,EDT根本没时间处理重绘请求。

解决方案

给你两个靠谱的实现方式,选哪个都能解决问题:

方案1:用Swing Timer(最推荐)

Swing Timer专门为UI动画设计,它的任务会自动在EDT里执行,完美避开线程安全问题。

import javax.swing.*;
import java.awt.*;

class RotatingTrianglePanel extends JPanel {
    private volatile double angle = 0; // 用volatile保证线程可见性

    public RotatingTrianglePanel() {
        Timer timer = new Timer(30, e -> {
            angle += Math.PI / 30; // 每次旋转6度
            repaint();
        });
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // 一定要先调用父类方法,清除旧画面
        Graphics2D g2d = (Graphics2D) g;
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;

        // 保存当前坐标系状态,旋转后恢复
        g2d.translate(centerX, centerY);
        g2d.rotate(angle);
        g2d.translate(-centerX, -centerY);

        // 绘制三角形
        int[] xPoints = {centerX, centerX + 50, centerX - 50};
        int[] yPoints = {centerY - 50, centerY + 50, centerY + 50};
        g2d.fillPolygon(xPoints, yPoints, 3);

        // 恢复坐标系
        g2d.dispose();
    }
}

// 启动类
public class StartAssignment {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("旋转三角形");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new RotatingTrianglePanel());
            frame.setSize(400, 400);
            frame.setVisible(true);
        });
    }
}

方案2:用独立线程+EDT调度

如果你一定要用自定义线程,必须把UI更新的逻辑放到SwingUtilities.invokeLater()里:

import javax.swing.*;
import java.awt.*;

class RotatingTrianglePanel extends JPanel {
    private volatile double angle = 0;

    public RotatingTrianglePanel() {
        new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                angle += Math.PI / 30;
                // 把repaint放到EDT里执行
                SwingUtilities.invokeLater(this::repaint);
                try {
                    Thread.sleep(30); // 给线程休息,控制帧率
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;

        g2d.translate(centerX, centerY);
        g2d.rotate(angle);
        g2d.translate(-centerX, -centerY);

        int[] xPoints = {centerX, centerX + 50, centerX - 50};
        int[] yPoints = {centerY - 50, centerY + 50, centerY + 50};
        g2d.fillPolygon(xPoints, yPoints, 3);

        g2d.dispose();
    }
}

public class StartAssignment {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("旋转三角形");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new RotatingTrianglePanel());
            frame.setSize(400, 400);
            frame.setVisible(true);
        });
    }
}

关键注意点

  • 一定要调用super.paintComponent(g):这会帮你清除上一次的绘制内容,避免残影和闪烁。
  • 用volatile修饰角度变量:保证工作线程修改的值能被EDT及时看到。
  • 控制帧率:不管用Timer还是线程,都要留足够的休息时间(比如30ms,大概30帧),不然会占满CPU,UI反应迟钝。

内容的提问来源于stack exchange,提问作者OscarN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:41:01