Java骰子动画问题:JLabel无法显示倒计时式随机数滚动效果
解决骰子滚动动画与重复结果反馈问题
问题根源
你的代码在**事件调度线程(EDT)**中调用Thread.sleep(),导致UI线程被阻塞,所有JLabel的更新操作都会在循环结束后一次性执行,因此看不到中间滚动过程。另外,重复数字时缺少视觉提示,用户无法感知操作完成。
解决方案
使用Swing Timer替代Thread.sleep(),它能在EDT中安全执行定时任务,避免UI冻结;同时添加重复结果的视觉反馈(如颜色闪烁、边框变化)。
完整实现代码
import javax.swing.*; import java.awt.*; import java.util.Random; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class DiceRoller extends JFrame { private JLabel lblDice; private int lastResult = -1; private Random rand = new Random(); private Timer rollTimer; private int rollCount = 0; private final int MAX_ROLLS = 10; // 滚动次数 public DiceRoller() { // 初始化UI setTitle("骰子模拟器"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(300, 200); setLayout(new BorderLayout()); lblDice = new JLabel("0", SwingConstants.CENTER); lblDice.setFont(new Font("Arial", Font.BOLD, 60)); lblDice.setOpaque(true); lblDice.setBackground(Color.WHITE); add(lblDice, BorderLayout.CENTER); JButton rollBtn = new JButton("掷骰子"); rollBtn.addActionListener(e -> startRoll(1, 7)); // 生成1-6的随机数 add(rollBtn, BorderLayout.SOUTH); setVisible(true); } private void startRoll(int lower, int upper) { // 重置滚动状态 rollCount = 0; // 停止之前的定时器(如果存在) if (rollTimer != null && rollTimer.isRunning()) { rollTimer.stop(); } // 创建定时器,动态调整延迟实现减速效果 rollTimer = new Timer(0, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (rollCount < MAX_ROLLS) { // 生成随机数 int currentResult = rand.nextInt(lower, upper); lblDice.setText(String.valueOf(currentResult)); // 逐渐增加延迟,实现减速 int delay = rollCount * 20; rollTimer.setDelay(delay); rollCount++; } else { // 滚动结束,确定最终结果 int finalResult = rand.nextInt(lower, upper); lblDice.setText(String.valueOf(finalResult)); rollTimer.stop(); // 处理重复结果的视觉反馈 if (finalResult == lastResult) { flashLabel(); } lastResult = finalResult; } } }); rollTimer.start(); } private void flashLabel() { // 短暂改变背景色提示重复结果 Timer flashTimer = new Timer(200, e -> { lblDice.setBackground(lblDice.getBackground() == Color.WHITE ? Color.YELLOW : Color.WHITE); }); flashTimer.setRepeats(true); flashTimer.setInitialDelay(0); // 闪烁3次后停止 Timer stopTimer = new Timer(600, e -> { flashTimer.stop(); lblDice.setBackground(Color.WHITE); }); stopTimer.setRepeats(false); stopTimer.start(); flashTimer.start(); } public static void main(String[] args) { // 在EDT中启动UI,符合Swing线程规则 SwingUtilities.invokeLater(DiceRoller::new); } }
关键说明
- Swing Timer的使用:避免在EDT中阻塞,每次定时任务都会更新UI,确保中间滚动过程可见。
- 减速效果实现:通过
rollTimer.setDelay(rollCount * 20),每次滚动增加延迟时间,模拟逐渐减速的动画。 - 重复结果反馈:调用
flashLabel()方法,让JLabel背景色短暂闪烁,用户能清晰感知操作已执行。 - 线程安全:所有UI操作都在EDT中执行,符合Swing的线程规则。
内容的提问来源于stack exchange,提问作者seve
相关产品推荐
相关产品推荐

