所以我可以看到几种不同的方法来完成我需要的事情,并且我已经做了很多谷歌/堆栈溢出搜索,但找不到我真正想要的东西。我需要运行多个“倒计时器”。我需要在不同时间同时运行大约 6 个(可能最多 10 个)倒计时器。我的主程序上有一个选项卡窗格,我在其中包含 FXML 并将控制器注入其中。计时器选项卡具有与主程序不同的控制器。
所以我的第一个问题是。由于此“选项卡”在单独的控制器上运行但包含在主程序中,因此它是否在单独的应用程序线程上运行?
以下是包含的选项卡 FXML 的示例...
当我按下每个开始按钮时。我可以创建一个Timeline
and KeyFrame
对于每个计时器。然而,我真的不认为这是最好的方法。特别是当您同时运行最多 10 个时间线时,并且绝对不是在与主程序不同的应用程序线程上运行。
我考虑过将每个启动请求发送到ExecutorService
and newCacheThreadPool
但是我需要能够使用当前剩余时间更新 GUI 上的标签,并且我知道您不应该使用后台服务来执行此操作。Platform.runLater()
maybe?
另一个想法是使用Timer
来自java.util.Timer
班级。然而,我认为这与ExecutorService
当我需要更新 GUI 标签时。我也明白,Timer
该类仅创建一个线程并按顺序执行其任务。所以,那是行不通的。
或者,我应该有一个完整的其他“CountDown”类,我可以为每个类创建新实例,然后在其中启动新线程。但是,如果我这样做,我如何不断更新 GUI。我仍然需要使用 CountDown 类进行轮询timeline
正确的?这样就违背了整件事的目的。
所以我的第一个问题是。由于此“选项卡”在单独的控制器上运行但包含在主程序中,因此它是否在单独的应用程序线程上运行?
不,只能有one每个 JVM 的 JavaFX 应用程序实例,以及one每个 JVM 的 JavaFX 应用程序线程。
至于如何更新计时器,可以使用Timeline
- 每个计时器一个。Timeline
不在单独的线程上运行 - 它由底层“场景图渲染脉冲”触发,负责定期更新 JavaFX GUI。拥有更多Timeline
实例基本上只是意味着有更多的侦听器订阅“pulse”事件。
public class TimerController {
private final Timeline timer;
private final ObjectProperty<java.time.Duration> timeLeft;
@FXML private Label timeLabel;
public TimerController() {
timer = new Timeline();
timer.getKeyFrames().add(new KeyFrame(Duration.seconds(1), ae -> updateTimer()));
timer.setCycleCount(Timeline.INDEFINITE);
timeLeft = new SimpleObjectProperty<>();
}
public void initialize() {
timeLabel.textProperty().bind(Bindings.createStringBinding(() -> getTimeStringFromDuration(timeLeft.get()), timeLeft));
}
@FXML
private void startTimer(ActionEvent ae) {
timeLeft.set(Duration.ofMinutes(5)); // For example timer of 5 minutes
timer.playFromStart();
}
private void updateTimer() {
timeLeft.set(timeLeft.get().minusSeconds(1));
}
private static String getTimeStringFromDuration(Duration duration) {
// Do the conversion here...
}
}
当然,你也可以使用Executor
和其他线程方法,前提是您更新Label
via Platform.runLater()
。或者,您可以使用Task
.
这是使用后台线程时的一般示例:
final Duration countdownDuration = Duration.ofSeconds(5);
Thread timer = new Thread(() -> {
LocalTime start = LocalTime.now();
LocalTime current = LocalTime.now();
LocalTime end = start.plus(countDownDuration);
while (end.isAfter(current)) {
current = LocalTime.now();
final Duration elapsed = Duration.between(current, end);
Platform.runLater(() -> timeLeft.set(current)); // As the label is bound to timeLeft, this line must be inside Platform.runLater()
Thread.sleep(1000);
}
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)