Вам нужно будет выполнить метод загрузки в фоновом потоке. По сути, создаваемый вами интерфейс и все его события выполняются в потоке приложений JavaFX (JFXAT).
Эти события обычно выполняются по одному, поэтому, если вы выполняете длинный процесс в этом потоке, пользовательский интерфейс будет зависать до тех пор, пока этот процесс не будет завершен.
Хотя есть несколько способов создания фоновых задач в JavaFX, ниже приведено простое демонстрационное приложение, которое использует для этого Task
.
Пример кода прокомментирован повсюду, чтобы объяснить, что мы делаем. В примере используется ListView
вместо TreeView
, просто для простоты, но концепция одинакова независимо.
В этом примере показан базовый интерфейс с ListView
и Button
для запуска процесса загрузки. Внизу находится Label
, который будет держать пользователя в курсе текущего шага в процессе Задачи.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Just a simple interface
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// Create the list view
ListView<String> listView = new ListView<>();
listView.setPrefHeight(200);
// Status label
Label lblStatus = new Label();
// Here we will create a new Task that will run in the background
Task<List<String>> loadDataTask = new Task<List<String>>() {
// We override the call() method; this is the code that is run when the task is started. When the Task
// is completed, it will return a new List of Strings
@Override
protected List<String> call() throws Exception {
// Tasks have a messageProperty that allows us to keep the UI informed. We will bind this value to
// our Label later
updateMessage("Loading data ...");
// Generate some sample data
List<String> listOfItems = new ArrayList<>();
listOfItems.add("One");
listOfItems.add("Two");
listOfItems.add("Three");
listOfItems.add("Four");
listOfItems.add("Five");
// Simulate a long-running task by pausing the thread for 10 seconds
Thread.sleep(10000);
// Now we can update the messageProperty again and return the completed data List
updateMessage("Finished!");
return listOfItems;
}
};
// We can now tell our application what to do once the Task has finished (either successfully or failure)
loadDataTask.setOnFailed(wse -> {
// This is called if an exception is thrown during the execution of the Task
// We will just print the Exception in this sample
loadDataTask.getException().printStackTrace();
});
// The Task completed successfully so lets now bind the List to our ListView
loadDataTask.setOnSucceeded(wse -> {
listView.setItems(FXCollections.observableArrayList(loadDataTask.getValue()));
});
// Now that we've defined our background Task and what to do when it's completed, let's create a button
// that allows us to start the task.
Button button = new Button("Load Data");
button.setOnAction(e -> {
// Let's bind our Label to the Task's messageProperty. This will cause the Label to update automatically
// whenever the Task calls the updateMessage() method.
lblStatus.textProperty().bind(loadDataTask.messageProperty());
// Now let's start the Task on a background Thread. This will cause the rest of the UI to remain
// responsive.
new Thread(loadDataTask).start();
});
// Add the controles to the Scene
root.getChildren().addAll(
button,
listView,
new Label("Status:"),
lblStatus);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
При нажатии кнопки выполняется фоновая задача, Label
обновляется и отображает «Загрузка данных ...», и начинается долгосрочное задание.
Когда задание завершается, ListView
обновляется с данными, и Label
показывает «Завершено!»