Заполните TreeView и отобразите сообщения о состоянии - PullRequest
0 голосов
/ 26 августа 2018

Я пытаюсь заполнить свой TreeView и обновить текст метки состояния до и после заполнения.

мой код выглядит примерно так:

public void populateTreeView() {
    // start message
    this.label.setText("Process started...");

    // populate the TreeView, this takes several minutes

    // finish message
    this.label.setText("Done!");
}

Это не работает, как я ожидал. Я попытался поместить каждый из 3 основных разделов этого метода в Platform.runLater (), и это тоже не сработало. Приложение просто зависает на несколько секунд, а затем я вижу заполненный TreeView и текст "Done".

Как я могу получить это поведение?

Заранее спасибо

1 Ответ

0 голосов
/ 26 августа 2018

Вам нужно будет выполнить метод загрузки в фоновом потоке. По сути, создаваемый вами интерфейс и все его события выполняются в потоке приложений 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 показывает «Завершено!»

...