java - JavaFX 中的快速计数计时器

标签 java javafx timer

为了达到效果,我想要一个像秒表一样显示时间的标签。时间从 0 开始,到 2 或 3 秒左右结束。该服务在需要时停止。我遇到的问题是因为我试图每秒更新文本 1000 次,计时器滞后了。

就像我说的,这是为了效果,一旦计时器停止就会隐藏,但时间应该相当准确,而不是落后 3 秒。

有什么方法可以让它更快吗?如果可能的话,我希望保留所有 4 位小数。

timer = new Label();
DoubleProperty time = new SimpleDoubleProperty(0.0);
timer.textProperty().bind(Bindings.createStringBinding(() -> {
    return MessageFormat.format(gui.getResourceBundle().getString("ui.gui.derbydisplay.timer"), time.get());
}, time));

Service<Void> countUpService = new Service<Void>() {
    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while (!isCancelled()) {
                    Platform.runLater(() -> time.set(time.get() + 0.0001));
                    Thread.sleep(1);
                }
                return null;
            }
        };
    }
};

最佳答案

您的时钟滞后的主要原因是因为您每秒将时间增加 0.0001 秒(即 1/10000 秒)1000 次。所以每秒它会增加 0.1...但是即使你解决了这个问题,它仍然会有少量滞后,因为你没有考虑进行方法调用所花费的时间。您可以通过在启动时检查系统时钟来解决此问题,然后在每次进行更新时检查它。

每秒更新标签 1000 次几乎是多余的,因为 JavaFX 的目的只是每秒更新 UI 60 次。 (如果 UI 线程忙于尝试做太多事情,它会变慢,您也可以通过安排对 Platform.runLater() 的多次调用来实现这种情况。)您可以通过使用AnimationTimer . AnimationTimer.handle(...) 方法在每次渲染帧时被调用一次,所以这有效地更新了 JavaFX 允许 UI 更新的频率。

AnimationTimer timer = new AnimationTimer() {

    private long startTime ;

    @Override
    public void start() {
        startTime = System.currentTimeMillis();
        super.start();
    }

    @Override
    public void handle(long timestamp) {
        long now = System.currentTimeMillis();
        time.set((now - startTime) / 1000.0);
    }
};

您可以使用 timer.start(); 启动它并使用 timer.stop(); 停止它。显然,您可以添加更多功能来设置运行时间等,并在需要时从 handle(...) 方法调用 stop()

上海商会:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Timer extends Application {

    @Override
    public void start(Stage primaryStage) {

        Label label = new Label();
        DoubleProperty time = new SimpleDoubleProperty();
        label.textProperty().bind(time.asString("%.3f seconds"));

        BooleanProperty running = new SimpleBooleanProperty();

        AnimationTimer timer = new AnimationTimer() {

            private long startTime ;

            @Override
            public void start() {
                startTime = System.currentTimeMillis();
                running.set(true);
                super.start();
            }

            @Override
            public void stop() {
                running.set(false);
                super.stop();
            }

            @Override
            public void handle(long timestamp) {
                long now = System.currentTimeMillis();
                time.set((now - startTime) / 1000.0);
            }
        };

        Button startStop = new Button();

        startStop.textProperty().bind(
            Bindings.when(running)
                .then("Stop")
                .otherwise("Start"));

        startStop.setOnAction(e -> {
            if (running.get()) {
                timer.stop();
            } else {
                timer.start();
            }
        });

        VBox root = new VBox(10, label, startStop);
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root, 320, 120);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

传递给handle(...) 方法的值实际上是以纳秒为单位的时间戳。您可以使用它并将 startTime 设置为 System.nanoTime(),尽管您获得的精度远远超过帧渲染时实际使用的精度每秒 60 帧。

关于java - JavaFX 中的快速计数计时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34801227/

相关文章:

java - 创建的 String 对象的数量

java - 使用 kafka 时将 Java 转换为 Avro 并返回

java - 如何使用 Jaxen 选择具有空白命名空间的内容?

java - 除非 ObjectProperty 的源发生更改,否则不会触发 ChangeListener

java - 如何更新 JavaFX?我必须下载新版本的 JDK 吗?

java - 如何在 JavaFX 中制作一个图像覆盖另一个图像并在 ActionTimer 中再次更改它?

java - 使用 JWindow 的 Timer 类

在 c 中为 Windows 操作系统创建中断

java - 字符串索引越界异常 : string index out of range

Silverlight 4等效于.NET计时器控件