限制 javafx gui 更新 [英] Throttling javafx gui updates

查看:16
本文介绍了限制 javafx gui 更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I receive data objects at random times at a high frequency, and need to update the JavaFX GUI with these. However, I don't want to fill the javafx event queue with a very large number of runnables (I use Platform.RunLater).

我一直在思考如何最好地实现节流算法.

I have been thinking of how to best implement a throttling algorithm.

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

有关如何以简短、有效的方式为 JavaFX Platform.RunLater GUI 更新设计节流算法的任何建议?

Any suggestions on how to design a throttling algorithm for JavaFX Platform.RunLater GUI updates in a short, efficient way?

推荐答案

这是Task 类,用于实现 updateMessage(...) 方法,以及其他类似的方法.它提供了一个很好的、健壮的解决方案来避免 FX 应用程序线程泛滥:

This is the idiom used in the Task class for implementing the updateMessage(...) method, and other similar methods. It provides a nice, robust solution to avoid flooding the FX Application Thread:

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);
    }
}

AtomicLong 保存用于更新标签的当前值.计数不断增加并更新 AtomicLong,但仅在当前值为 -1 时才安排对 Platform.runLater(...) 的调用.Platform.runLater(...) 使用来自 AtomicLong 的当前值更新 Label 并翻转 AtomicLong> 回到 -1,表示它已准备好进行新的更新.

The AtomicLong holds the current value to be used to update the Label. The count continually increments and updates the AtomicLong, but only schedules a call to Platform.runLater(...) if it's current value is -1. The Platform.runLater(...) updates the Label with the current value from the AtomicLong and flips the AtomicLong back to -1, indicating that it's ready for a new update.

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

The effect here is to schedule new calls to Platform.runLater(...) whenever the FX Application Thread is ready to handle them. There's no hard-coded time interval which could need tuning.

这篇关于限制 javafx gui 更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆