java更新标签_Java Timer-使用Platform.runLater更新标签

本文探讨了在JavaFX应用程序中遇到UI无响应的问题及其原因。通过分析无限循环导致的问题,提出了移除循环、使用TimerTask及采用JavaFX动画API等解决方案。提供了使用AnimationTimer实现秒表功能的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小编典典

将Runnable传递给Platform#runLater(Runnable)包含一个无限循环。这意味着您在 JavaFX Application

Thread

上执行了无限循环,这就是UI变得无响应的原因。如果FX线程不能自由执行其工作,则无法处理用户生成的事件,并且无法安排渲染“脉冲”。后一点就是为什么即使您setText(...)不断调用UI也不更新。

如果要继续使用当前方法,解决方法是for

(;;)从Runnable实现中删除循环。您将设置为TimerTask每毫秒执行一次,这意味着您要做的就是计算新状态并为每次执行设置一次标签。换句话说,该run()方法已经“循环”。例如:

TimerTask task = new TimerTask() {

@Override public void run() {

Platform.runLater(() -> {

// calculate new state...

// update labels...

// return (no loop!)

});

}

};

也就是说,没有理由为此使用后台线程。我建议改用JavaFX提供的动画API。它是异步的,但在FX线程上执行,因此更易于实现和推理-

使用多个线程总是更复杂。要执行与当前操作类似的操作,可以使用Timeline或PauseTransition代替java.util.Timer。在JavaFX的周期性后台任务

Q&A给出了使用动画用于此目的的一些很好的例子。

就个人而言,我将使用AnimationTimer来实现秒表。这是一个例子:

import java.util.concurrent.TimeUnit;

import javafx.animation.AnimationTimer;

import javafx.beans.property.ReadOnlyBooleanProperty;

import javafx.beans.property.ReadOnlyBooleanWrapper;

import javafx.beans.property.ReadOnlyLongProperty;

import javafx.beans.property.ReadOnlyLongWrapper;

public class Stopwatch {

private static long toMillis(long nanos) {

return TimeUnit.NANOSECONDS.toMillis(nanos);

}

// value is in milliseconds

private final ReadOnlyLongWrapper elapsedTime = new ReadOnlyLongWrapper(this, "elapsedTime");

private void setElapsedTime(long elapsedTime) { this.elapsedTime.set(elapsedTime); }

public final long getElapsedTime() { return elapsedTime.get(); }

public final ReadOnlyLongProperty elapsedTimeProperty() { return elapsedTime.getReadOnlyProperty(); }

private final ReadOnlyBooleanWrapper running = new ReadOnlyBooleanWrapper(this, "running");

private void setRunning(boolean running) { this.running.set(running); }

public final boolean isRunning() { return running.get(); }

public final ReadOnlyBooleanProperty runningProperty() { return running.getReadOnlyProperty(); }

private final Timer timer = new Timer();

public void start() {

if (!isRunning()) {

timer.start();

setRunning(true);

}

}

public void stop() {

if (isRunning()) {

timer.pause();

setRunning(false);

}

}

public void reset() {

timer.stopAndReset();

setElapsedTime(0);

setRunning(false);

}

private class Timer extends AnimationTimer {

private long originTime = Long.MIN_VALUE;

private long pauseTime = Long.MIN_VALUE;

private boolean pausing;

@Override

public void handle(long now) {

if (pausing) {

pauseTime = toMillis(now);

pausing = false;

stop();

} else {

if (originTime == Long.MIN_VALUE) {

originTime = toMillis(now);

} else if (pauseTime != Long.MIN_VALUE) {

originTime += toMillis(now) - pauseTime;

pauseTime = Long.MIN_VALUE;

}

setElapsedTime(toMillis(now) - originTime);

}

}

@Override

public void start() {

pausing = false;

super.start();

}

void pause() {

if (originTime != Long.MIN_VALUE) {

pausing = true;

} else {

stop();

}

}

void stopAndReset() {

stop();

originTime = Long.MIN_VALUE;

pauseTime = Long.MIN_VALUE;

pausing = false;

}

}

}

警告: 在AnimationTimer运行Stopwatch实例时,无法进行垃圾回收。

上面提供了一个属性,elapsedTime表示经过的时间(以毫秒为单位)。根据该值,您可以计算自秒表启动以来经过的天,小时,分钟,秒和毫秒的数量。您只需收听属性并在属性更改时更新UI。

2020-11-30

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值