限制 javafx gui 更新

我以高频率随机接收数据对象,并且需要用这些更新JavaFX GUI。但是,我不想用大量的runnables填充javafx事件队列(我使用Formform.RunLater)。

我一直在思考如何最好地实现限制算法。

  • 最好有一个单独的 GUIUpdater 线程来检查例如新对象的阻塞队列,然后休眠 30 毫秒,然后在无限循环中再次检查?在这种情况下,阻塞队列会是最佳数据结构吗?请注意,我只需要最新的数据对象,而阻塞队列是一个FIFO队列,我似乎不能只选择最新的条目。
  • 或者 - 如果nanoTime-startTime>30ms,那么简单地用Platform.RunLater更新GUI会更好吗?在这种情况下,我不需要单独的线程来执行 Platform.RunLater-call。但是 - 如果在 30 毫秒未过去时收到更新,并且一段时间内未收到任何更新,则上次更新将不会显示在 GUI 中。

关于如何以简短,有效的方式为JavaFX平台设计限制算法的任何建议。RunLater GUI更新?


答案 1

这是 Task 类中用于实现该方法的成语,以及其他类似的方法。它提供了一个很好的,强大的解决方案,以避免淹没FX应用程序线程:updateMessage(...)

import java.util.concurrent.atomic.AtomicLong;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ThrottlingCounter extends Application {

    @Override
    public void start(Stage primaryStage) {
        final AtomicLong counter = new AtomicLong(-1);
        final Label label = new Label();
        final Thread countThread = new Thread(new Runnable() {
            @Override
            public void run() {
                long count = 0 ;
                while (true) {
                    count++ ;
                    if (counter.getAndSet(count) == -1) {
                        updateUI(counter, label);
                    }
                }
            }
        });
        countThread.setDaemon(true);
        countThread.start();

        VBox root = new VBox();
        root.getChildren().add(label);
        root.setPadding(new Insets(5));
        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 150, 100);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void updateUI(final AtomicLong counter,
            final Label label) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                final String msg = String.format("Count: %,d", counter.getAndSet(-1));
                label.setText(msg);
            }
        });
    }

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

保存用于更新标签的当前值。计数不断递增并更新 ,但仅当其当前值为 -1 时才计划调用 。使用 中的当前值更新 ,并将该值翻转回 -1,表示它已准备好进行新的更新。AtomicLongAtomicLongPlatform.runLater(...)Platform.runLater(...)LabelAtomicLongAtomicLong

这里的效果是将新调用安排到 FX 应用程序线程准备好处理它们的时间。没有可能需要调整的硬编码时间间隔。Platform.runLater(...)


答案 2

推荐