我有一个每秒更新数百次的 Java FX 2 应用程序。我遇到了一个问题,标签在几分之一秒内部分空白,但这种情况经常发生。我该如何解决?
问问题
1423 次
1 回答
1
每秒调用数百次Platform.runLater()不是一个好主意。我建议您在调用 Platform.runLater() 以更新您的 UI 之前限制数据源的输入速度或将数据一起批处理,这样 Platform.runLater 的调用次数不会超过每秒 30 次。
我提交了一个 jira 请求RT-21569来改进 Platform.runLater 调用的文档,并考虑在底层平台中实现一个优越的 runLater 事件节流系统。
Richard Bair 在此论坛主题中提供了批处理 runLater 事件的示例解决方案。
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;
/**
*
*/
public class BackgroundLoadingApp extends Application {
private ListView<String> listView;
private List<String> pendingItems;
private Semaphore lock = new Semaphore(1);
protected void addItem(String item) throws InterruptedException {
if (Platform.isFxApplicationThread()) {
listView.getItems().add(item);
} else {
// It might be that the background thread
// will update this title quite frequently, and we need
// to throttle the updates so as not to completely clobber
// the event dispatching system.
lock.acquire();
if (pendingItems == null) {
pendingItems = new LinkedList<String>();
pendingItems.add(item);
Platform.runLater(new Runnable() {
@Override public void run() {
try {
lock.acquire();
listView.getItems().addAll(pendingItems);
pendingItems = null;
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
lock.release();
}
}
});
} else {
pendingItems.add(item);
}
lock.release();
}
}
/**
* The main entry point for all JavaFX applications.
* The start method is called after the init method has returned,
* and after the system is ready for the application to begin running.
* <p/>
* <p>
* NOTE: This method is called on the JavaFX Application Thread.
* </p>
*
* @param primaryStage the primary stage for this application, onto which
* the application scene can be set. The primary stage will be embedded in
* the browser if the application was launched as an applet.
* Applications may create other stages, if needed, but they will not be
* primary stages and will not be embedded in the browser.
*/
@Override public void start(Stage primaryStage) throws Exception {
listView = new ListView<String>();
primaryStage.setScene(new Scene(listView));
primaryStage.show();
// Start some background thread to load millions of rows as fast as it can. But do
// so responsibly so as not to throttle the event thread
Thread th = new Thread() {
@Override public void run() {
try {
for (int i=0; i<2000000; i++) {
addItem("Item " + i);
if (i % 200 == 0) {
Thread.sleep(20);
}
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
};
th.setDaemon(true);
th.start();
}
public static void main(String[] args) {
launch(args);
}
}
Richard Bair 的评论从引用的论坛帖子中复制:
这是一个模拟一些长时间运行的线程产生大量数据的示例。我发现它不太符合我的喜好。如果 Thread.sleep 丢失,它仍然会淹没进程(也许这是我在这种情况下处理并发的方式)。我还发现,如果我将它减少到“2”毫秒的睡眠时间,那么我就无法抓住滚动条拇指并移动它。我认为这里的问题是事件队列中有一个用于按下和拖动的鼠标事件,但是在拖动事件之间,新项目被添加到列表中,导致拇指移动,因为这比我的拖动事件更频繁地发生拇指永远不会去我想要的地方。我认为这是由于根据行数处理拇指位置的方式,
于 2012-05-15T23:27:32.643 回答