限制 javafx gui 更新
Posted
技术标签:
【中文标题】限制 javafx gui 更新【英文标题】:Throttling javafx gui updates 【发布时间】:2014-06-22 16:30:36 【问题描述】:我在随机时间以高频率接收数据对象,并且需要使用这些更新 JavaFX GUI。但是,我不想用大量可运行对象填充 javafx 事件队列(我使用 Platform.RunLater)。
我一直在思考如何最好地实现节流算法。
最好有一个单独的 GUIUpdater 线程来检查新对象的阻塞队列,然后休眠 30 毫秒,然后在无限循环中再次检查?在那种情况下,阻塞队列会是最优的数据结构吗?请注意,我只需要最新的数据对象,blockingQueue 是一个 FIFO 队列,我似乎不能只选择最新的条目。 或者 - 如果 nanoTime-startTime > 30 毫秒,只需使用 Platform.RunLater 更新 GUI 会更好吗?在这种情况下,我不需要单独的线程来执行 Platform.RunLater 调用。但是 - 如果在 30 毫秒内收到更新,然后一段时间内没有收到更新,则最后一次更新不会显示在 GUI 中。关于如何为 JavaFX Platform.RunLater GUI 更新设计节流算法有什么建议吗?
【问题讨论】:
【参考方案1】:这是Task
类中用于实现updateMessage(...)
方法和其他类似方法的惯用语。它提供了一个很好的、强大的解决方案来避免 FX 应用程序线程泛滥:
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,表示它已准备好进行新的更新。
这里的效果是在 FX 应用程序线程准备好处理它们时安排对Platform.runLater(...)
的新调用。没有可能需要调整的硬编码时间间隔。
【讨论】:
为什么在 platform.runlater-runnable 中设置标签后,AtomicLong 没有设置为“-1”(表示 gui 已准备好更新)? @user3607022 您需要检索当前值并将该值设置为-1
原子地。如果您检索了要显示的值,然后在显示后将其设置为-1
,则其他线程可能会在这两者之间再次设置该值:即1. UI线程检索该值,2.后台线程更新自值为!=-1
没有计划更新,3. ui 将值设置为-1。在这种情况下,您可能会“错过”该中间值;如果这是线程做的最后一件事,你会永远错过它。
有没有一种简单的方法可以准确地描述哪些更新被丢弃了?
@user3607022 不:没有真正的理由关心。您正在专门更新 UI 属性;如果 UI 没有时间显示它,那么如果它没有收到也没关系:最终用户不会注意到。
我明白了。因此,换句话说,被删除的更新是 UI 没有时间显示的更新。我想我必须考虑一下这个实现是如何产生这个结果的。非常感谢您的帮助。以上是关于限制 javafx gui 更新的主要内容,如果未能解决你的问题,请参考以下文章
Atitit 桌面软件跨平台gui解决方案 javafx webview