JavaFX Обновление Vbox при добавлении содержимого

Есть окно с кнопкой "Добавить", по нажатию по которую открывается FileChooser. После выделения нескольких файлов в VBox добавляются "карточки" (экземпляры класса Controller) с описанием этих файлов. Проблема в том, что они добавляются все одновременно, а я хочу, чтобы они отображались в интерфейсе по мере обработки каждого файла (добавление в интерфейс в конце каждой итерации цикла).

@FXML
private void addHandle() throws IOException {
    FileChooser fc = new FileChooser();
    List<File> list = fc.showOpenMultipleDialog(stage);

    DevFile devFile;
    
    for(int i=0; i<list.size(); i++){
        devFile = new DevFile(device, list.get(i), type);
        Controller controller = createDevFileCard(devFile);

        vbox.getChildren().add(controller.getRoot());
    }
}

private Controller createDevFileCard(DevFile devFile) throws IOException {
    loader = new FXMLLoader();
    loader.setLocation(MainApp.class.getResource("view/devFiles/editor_element.fxml"));
    pane = (AnchorPane) loader.load();
    controller = loader.getController();
    controller.setElement(devFile);

    return controller;
}

Пробовал запускать цикл в отдельном потоке и оттуда вызывать отрисовку Controller в потоке JavaFX через Platform.runlater(), но не получилось. Сначала создаются экземпляры класса Controller, затем они добавляются в vbox, и только затем все разом уже отображаются на экране. Аналогичная проблема возникла и с удалением "карточек" из VBox - удаляются все разом.


Ответы (1 шт):

Автор решения: Андрей Авдеев

Решение проблемы:

  1. Создать отдельный поток, перенести логику в него, создать в нем элемент, который будет добавлен в vbox

  2. Создать статичный метод, который возвращается в поток JavaFX, и в нем уже добавляет в vbox созданный элемент

    //метод JavaFX класса
    private void addHandle(){
        FileChooser fc = new FileChooser();
        List<File> list = fc.showOpenMultipleDialog(stage);
    
        AddNewFiles thread = new AddNewFiles(list, this);
        thread.start();
    }
    
    //поток, в котором реализована логика
    private class AddNewCard extends Thread{
        Controller mainController;
        List<File> list;
    
        public AddNewFiles(List<File> list, Controller mainController){
            this.list = list;
            this.mainController = mainController;
        }
    
        @Override
        public void run(){
            //заполняем карточки контентом
             for(int i=0; i<list.size(); i++){
                //какая-то логика
    
                //создаем элемент, который будем помещать в vbox
                ElementController elementController = createCard();
                //вызываем статичный метод класса, содержащего vbox, передаем в него наш элемент
                Controller.addCardToVBox(mainController, elementController);
            }
        }
    }
    
    private static void addCardToVBox(Controller mainController, ElementController controller) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Runnable updater = new Runnable() {
                    @Override
                    public void run() {
                        mainController.addToVbox(controller);
                    }
                };
                Platform.runLater(updater);
            }
        });
    
        thread.setDaemon(true);
        thread.start();
    }
    
    public void addToVbox(ElementController controller){
        vbox.getChildren().add(controller.getRoot());
    }
    
→ Ссылка