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

求助:基于JavaFX实现滑块控制的倒计时计时器

JavaFX倒计时计时器实现与问题修复

需求说明

  • 从滑块获取设置的时间作为倒计时初始值
  • 每秒更新显示剩余的分钟和秒数(格式如mm:ss)
  • 点击按钮启动倒计时

原代码存在的问题

  • 变量名不匹配:FXML注入的是timerLabel,代码中错误使用timeLabel,导致编译错误
  • 使用java.util.Timer/TimerTask更新JavaFX UI:这类线程不属于FX应用线程,直接更新UI会触发异常
  • 未定义核心变量:timer和seconds未声明,也未从滑块获取初始时间
  • 倒计时逻辑错误:结束时显示-1,不符合正常显示逻辑
  • 未处理重复启动:多次点击按钮会创建多个计时器,导致计时混乱

修复后的完整代码

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.util.Duration;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @FXML
    private Button button;

    @FXML
    private Slider slider;

    @FXML
    private Label timerLabel;

    // 总剩余秒数
    private int totalSeconds;
    // 计时器实例,用于控制启动/停止
    private Timeline countdownTimeline;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        // 滑块值变化时更新标签,显示初始分钟数(假设滑块范围是1-60分钟)
        slider.valueProperty().addListener((ObservableValue<? extends Number> num, Number oldVal, Number newVal) -> {
            int minutes = newVal.intValue();
            timerLabel.setText(String.format("%02d:00", minutes));
            totalSeconds = minutes * 60;
        });

        // 初始化滑块默认值(比如5分钟)
        slider.setValue(5);
    }

    @FXML
    private void start() {
        // 如果计时器正在运行,先停止
        if (countdownTimeline != null && countdownTimeline.getStatus() == Timeline.Status.RUNNING) {
            countdownTimeline.stop();
            button.setText("启动");
            return;
        }

        // 重新获取当前滑块的时间(防止用户在计时器停止后调整滑块)
        totalSeconds = (int) slider.getValue() * 60;

        // 创建Timeline,每秒执行一次
        countdownTimeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
            if (totalSeconds > 0) {
                totalSeconds--;
                updateTimerLabel();
            } else {
                countdownTimeline.stop();
                timerLabel.setText("00:00");
                button.setText("启动");
            }
        }));

        // 设置循环次数为无限,直到手动停止
        countdownTimeline.setCycleCount(Timeline.INDEFINITE);
        countdownTimeline.play();
        button.setText("暂停"); // 按钮切换为暂停状态
    }

    // 更新标签显示格式为mm:ss
    private void updateTimerLabel() {
        int minutes = totalSeconds / 60;
        int seconds = totalSeconds % 60;
        timerLabel.setText(String.format("%02d:%02d", minutes, seconds));
    }
}

关键修复点说明

  • 使用javafx.animation.Timeline:完全在FX应用线程中执行,安全更新UI组件
  • 统一变量名:修正timeLabel为timerLabel,匹配FXML注入的控件
  • 时间格式化:通过String.format("%02d:%02d", minutes, seconds)实现两位数的分钟和秒数显示
  • 重复启动防护:判断计时器状态,避免多次点击创建多个计时任务
  • 动态获取滑块值:每次启动时重新读取滑块数值,支持中途调整后重启计时
  • 按钮状态切换:启动后按钮显示“暂停”,暂停后恢复“启动”,提升交互体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 15:32:35