在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
相关产品推荐
相关产品推荐

