gpt4 book ai didi

java - 即使使用 Task 和 Platform.runLater,UI 也会卡住(完整示例)

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:09:55 27 4
gpt4 key购买 nike

我读过类似的问题,但当我向 VBox 添加许多节点时,我的 UI 仍然卡住。我在下面提供了一个功能齐全的程序,它清楚地说明了这个问题。

4 秒后,ProgressIndicator 卡住,因为 5000 个节点被添加到 VBox。尽管使用 Task(用于非 UI 工作)然后使用 Platform.runLater() 将节点添加到场景,但用于演示 JavaFX 线程卡住的数量过多。

在我的实际应用程序中,我没有添加空白的 TitlePane,而是添加了一个通过 new FXMLLoader() 从 FXML 文件获取的 TitlePane >,然后生成的 loader.load() 会初始化关联的 Controller ,后者又会初始化一些要求适中的计算 - 这些计算在 JavaFX 线程上执行!因此,即使我添加了接近 250 个节点,当最终使用 Platform.runLater 时,UI 仍然会卡住。在显示红色背景之前,如何防止 ProgressIndicator 卡住?

完整示例:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.Timer;
import java.util.TimerTask;

public class FreezingUI extends Application {

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

@Override
public void start(Stage primaryStage) {

VBox mainBox = new VBox();
mainBox.setPrefHeight(800);
mainBox.setStyle("-fx-background-color: #f1f1f1; -fx-alignment: center");
Label label = new Label();
label.setMinHeight(50);
label.setStyle("-fx-font-size: 24px; -fx-text-fill: #515151");

ProgressIndicator progressIndicator = new ProgressIndicator(ProgressIndicator.INDETERMINATE_PROGRESS);
mainBox.getChildren().addAll(progressIndicator, label);

Scene scene = new Scene(mainBox, 500, 800);
primaryStage.setScene(scene);
primaryStage.show();

Timer timer = new Timer();
TimerTask task = new TimerTask(){
private int i = 4;
public void run(){
if (i >= 0) {
Platform.runLater(()->{
label.setText("Freezing in " + i--);
});
}else{
addNodesToUI(mainBox);
timer.cancel();
}
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
}

private void addNodesToUI(VBox mainBox) {
final int[] i = {0};
Platform.runLater(() -> {
Accordion temp = new Accordion();
mainBox.getChildren().add(temp);
while (i[0] < 5000) {

TitledPane tp = new TitledPane();
tp.setPrefWidth(300);
tp.setPrefHeight(12);
tp.setPadding(new Insets(10));
tp.setStyle("-fx-background-color: red;");
temp.getPanes().add(tp);
i[0]++;

}

});
}
}

最佳答案

发生这种情况是因为您要求 UI 线程在一个大块中做一大堆事情。在创建所有 5000 个节点并将其添加到场景之前,UI 线程无法退出 while 循环。

private void addNodesToUI(VBox mainBox) {
final int[] i = {0};

Accordion temp = new Accordion();

Platform.runLater(() -> {
mainBox.getChildren().add(temp);
});

while (i[0] < 5000) {
TitledPane tp = new TitledPane();
tp.setPrefWidth(300);
tp.setPrefHeight(12);
tp.setPadding(new Insets(10));
tp.setStyle("-fx-background-color: red;");

i[0]++;

Platform.runLater(() -> {
temp.getPanes().add(tp);
});
}
}

这将允许您的节点以小批量创建。这样,UI 线程可以在逐渐添加节点的同时尝试呈现 UI。

对于您的 FXML 案例,您可以在另一个线程中创建和加载 FXML。当您将场景分支附加到场景中时,您只需要在 UI 线程中。但是,我怀疑这只会减轻影响,因为您仍然要一次性附加一大块。

关于java - 即使使用 Task 和 Platform.runLater,UI 也会卡住(完整示例),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47297759/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com