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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 00:31:18