Javafx Progress-Indicator не отображается, когда я устанавливаю Progress-Indicator.setVisible(true)

Мое приложение JavaFX вычисляет размеры папок каждой папки на одном уровне под другой папкой. Моя проблема в том, что когда я нажимаю кнопку «Применить», которая запускает расчет в другом классе, я хочу, чтобы неопределенный индикатор прогресса показывал пользователю, что приложение работает прямо сейчас и не зависло. По умолчанию индикатор выполнения установлен на невидимый и отображается только во время расчета. К сожалению, он не появляется, когда я звоню. Я не уверен, но когда расчет завершен и данные из него установлены в JavaFX.Pie-Chart, я мог мельком увидеть индикатор.

Я уже пытался сделать индикатор видимым по умолчанию и просто закрыть его новым прямоугольником, но это тоже не сработало.

Контроллер:

package sample;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Rectangle;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

public class Controller {

    @FXML
    private PieChart pieChart;
    @FXML
    private TextField pathField;
    @FXML
    private Label subfolder;
    @FXML
    private Button up;
    @FXML
    private Button hide;
    @FXML
    private Button showHidden;
    @FXML
    private VBox field1;
    @FXML
    private VBox field2;
    @FXML
    private VBox field3;
    @FXML
    private VBox field4;
    @FXML
    private AnchorPane parentContainer;
    @FXML
    private ProgressIndicator loading;



    private ObservableList<PieChart.Data> pieChartData;
    private Calc calc;
    public File directory;
    String[] unit = {"Bytes", "KB", "MB", "GB", "TB", "PB", "ZB", "EB"};
    int units = 0;
    boolean hideSegment = false;
    String[] hiddenPath = new String[500];
    double[] hiddenSize = new double[500];
    int Stelle = 499;
    boolean first = true;

    @FXML
    void initialize(){
        pieChartData = FXCollections.observableArrayList();
        calc = new Calc(pieChartData);
        updataLabads();
        pieChart.setData(pieChartData);
    }

    @FXML
    private void handleBrowse(){
        Stage stage = new Stage();
        final DirectoryChooser dirChooser = new DirectoryChooser();
        directory = dirChooser.showDialog(stage);
        if(directory != null){
            pathField.setText(directory.toString());
        }
    }

    @FXML
    private void apply(){
        loading.setVisible(true);
        directory = Paths.get(pathField.getText()).toFile();
        if(directory!=null){
            pieChartData.clear();
            String strings = new String(pathField.getText());
            calc.calcSubfoldersSize(strings);
            updataLabads();
        }
        loading.setVisible(false);
    }

    public void updataLabads(){
        pieChart.getData().forEach(data -> {
            data.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED, e -> {

                for(int i=0;(data.getPieValue()/(Math.pow(1024, i))) > 1000;i++){
                    //System.out.println(i);
                    units = i+1;
                }
                subfolder.setText(data.getName() + ", " + Math.round(data.getPieValue()/(Math.pow(1024,units))) + " " + unit[units]);
                //System.out.println(Math.round(data.getPieValue()/(Math.pow(1024,units))) + " " + unit[units]);
            });
        });
        pieChart.getData().forEach(data -> {
            data.getNode().addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
                if(hideSegment == false){
                    pathField.setText(pathField.getText() + "\\" + data.getName());
                    apply();
                }else if(hideSegment == true){
                    pieChartData.remove(data);
                    hideSegment = false;
                    if(first == true){
                        first = false;
                        Stelle = 0;
                    }
                    hiddenPath[Stelle] = data.getName();
                    hiddenSize[Stelle] = data.getPieValue();
                    System.out.println("Hidden Variables have been updatet on Port " + Stelle);
                    Stelle++;
                    pieChart.setData(pieChartData);
                }
            });
        });
    }

    @FXML
    private void up(){
        while(!pathField.getText().substring(pathField.getText().length()-1).equals("\\")){
            pathField.setText(pathField.getText().substring(0, pathField.getText().length()-1));
        }
        pathField.setText(pathField.getText().substring(0, pathField.getText().length()-1));
        apply();
    }

    @FXML
    public void hide(){
        if(hideSegment == false)hideSegment = true;
        else if(hideSegment == true)hideSegment = false;
    }

    @FXML
    public void showHidden(){
        System.out.println("Tried to load HiddenVariables on Port " + (Stelle-1));
        System.out.println(hiddenPath[Stelle-1] + "   " + hiddenSize[Stelle-1]);
        if(!hiddenPath[Stelle-1].equals(null)){
            for(int i=Stelle; i!=0; i--){
                pieChartData.add(new PieChart.Data(hiddenPath[Stelle-1], hiddenSize[Stelle-1]));
                hiddenPath[Stelle-1] = "";
                hiddenSize[Stelle-1] = 0;
                Stelle--;
                pieChart.setData(pieChartData);
                updataLabads();
            }
        }
    }

    @FXML
    public void Home() throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"));
        Scene scene = up.getScene();
        root.translateYProperty().set(scene.getHeight());
        parentContainer.getChildren().add(root);
        Timeline timeline = new Timeline();
        KeyValue kv = new KeyValue(root.translateYProperty(), 0 , Interpolator.EASE_BOTH);
        KeyFrame kf = new KeyFrame(Duration.seconds(.5), kv);
        timeline.getKeyFrames().add(kf);
        timeline.play();
        parentContainer.getChildren().remove(parentContainer);
    }

    @FXML
    public void Files(){}

    @FXML
    public void Settings(){}

    @FXML
    public void Close(){
        Platform.exit();
    }
}

fxml-документ:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.chart.PieChart?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.SVGPath?>
<?import javafx.scene.text.Font?>

<AnchorPane fx:id="parentContainer" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" style="-fx-background-color: #2A2E37;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <HBox prefHeight="600.0" prefWidth="1000.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <VBox alignment="CENTER" prefHeight="600.0" prefWidth="858.0" />
         </children>
      </HBox>
      <PieChart fx:id="pieChart" layoutX="-341.0" layoutY="37.0" legendVisible="false" prefHeight="500.0" prefWidth="2000.0" stylesheets="@pieChart.css" />
      <Label layoutX="620.0" layoutY="24.0" text="Subfolders" textFill="#b2b2b2">
         <font>
            <Font size="24.0" />
         </font>
      </Label>
      <Label fx:id="subfolder" alignment="CENTER" layoutX="374.0" layoutY="551.0" prefHeight="26.0" prefWidth="584.0" textFill="#b2b2b2">
         <font>
            <Font size="25.0" />
         </font>
      </Label>
      <HBox maxHeight="1.7976931348623157E308" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="320.0">
         <children>
            <VBox prefHeight="200.0" prefWidth="20.0">
               <children>
                  <HBox minHeight="-Infinity" prefHeight="320.0" prefWidth="200.0" style="-fx-background-color: #353841;" />
                  <HBox minHeight="-Infinity" prefHeight="280.0" prefWidth="200.0" style="-fx-background-color: #3F434B;" />
               </children>
            </VBox>
            <VBox minHeight="-Infinity" prefHeight="600.0" prefWidth="280.0">
               <children>
                  <VBox prefHeight="604.0" prefWidth="280.0">
                     <children>
                        <VBox style="-fx-background-color: #353841;">
                           <children>
                              <HBox prefHeight="50.0" prefWidth="280.0">
                                 <children>
                                    <Label fx:id="label" alignment="BOTTOM_CENTER" contentDisplay="CENTER" prefHeight="64.0" prefWidth="280.0" text="Options" textAlignment="CENTER" textFill="#b2b2b2">
                                       <font>
                                          <Font size="28.0" />
                                       </font>
                                    </Label>
                                 </children>
                              </HBox>
                              <HBox prefHeight="64.0" prefWidth="200.0">
                                 <children>
                                    <HBox alignment="CENTER" minWidth="-Infinity" prefHeight="64.0" prefWidth="195.0">
                                       <children>
                                          <TextField fx:id="pathField" focusTraversable="false" prefHeight="48.0" prefWidth="175.0" promptText="Type Path                          or:" stylesheets="@textField.css" />
                                       </children>
                                    </HBox>
                                    <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
                                       <children>
                                          <Button fx:id="browse" mnemonicParsing="false" onAction="#handleBrowse" prefHeight="48.0" prefWidth="68.0" stylesheets="@FXbuttons.css" text="Browse" />
                                       </children>
                                    </HBox>
                                 </children>
                              </HBox>
                              <HBox alignment="CENTER" prefHeight="64.0" prefWidth="200.0">
                                 <children>
                                    <Button fx:id="apply" mnemonicParsing="false" onAction="#apply" prefHeight="48.0" prefWidth="262.0" stylesheets="@FXbuttons.css" text="Apply" />
                                 </children>
                              </HBox>
                              <HBox alignment="CENTER" prefHeight="64.0" prefWidth="200.0">
                                 <children>
                                    <Button fx:id="up" mnemonicParsing="false" onAction="#up" prefHeight="48.0" prefWidth="262.0" stylesheets="@FXbuttons.css" text="Up" />
                                 </children>
                              </HBox>
                              <HBox prefHeight="78.0" prefWidth="200.0">
                                 <children>
                                    <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
                                       <children>
                                          <Button fx:id="hide" mnemonicParsing="false" onAction="#hide" prefHeight="48.0" prefWidth="124.0" stylesheets="@FXbuttons.css" text="Hide" />
                                       </children>
                                    </HBox>
                                    <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
                                       <children>
                                          <Button fx:id="showHidden" mnemonicParsing="false" onAction="#showHidden" prefHeight="48.0" prefWidth="124.0" stylesheets="@FXbuttons.css" text="Show hidden" />
                                       </children>
                                    </HBox>
                                 </children>
                              </HBox>
                           </children>
                        </VBox>
                        <VBox prefHeight="280.0" prefWidth="100.0" style="-fx-background-color: #3F434B;">
                           <children>
                              <HBox prefHeight="140.0" prefWidth="200.0">
                                 <children>
                                    <VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#Home" prefHeight="140.0" prefWidth="140.0" styleClass="vbox" stylesheets="@fields.css">
                                       <children>
                                          <SVGPath content="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" fill="#4a4d55" scaleX="2.44" scaleY="2.44" />
                                       </children>
                                    </VBox>
                                    <VBox id="VBox" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#Files" prefHeight="140.0" prefWidth="140.0" styleClass="VBox" stylesheets="@fields.css">
                                       <children>
                                          <SVGPath content="M11 2v20c-5.07-.5-9-4.79-9-10s3.93-9.5 9-10zm2.03 0v8.99H22c-.47-4.74-4.24-8.52-8.97-8.99zm0 11.01V22c4.74-.47 8.5-4.25 8.97-8.99h-8.97z" fill="#4a4d55" scaleX="2.44" scaleY="2.44" />
                                       </children>
                                    </VBox>
                                 </children>
                              </HBox>
                              <HBox prefHeight="140.0" prefWidth="200.0">
                                 <children>
                                    <VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#Settings" prefHeight="140.0" prefWidth="140.0" stylesheets="@locked.css">
                                       <children>
                                          <SVGPath content="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2zM18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z" fill="#4a4d55" scaleX="2.88" scaleY="2.88" styleClass="icon-settings" />
                                       </children>
                                    </VBox>
                                    <VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#Close" prefHeight="140.0" prefWidth="140.0" stylesheets="@fields.css">
                                       <children>
                                          <SVGPath content="M13 3h-2v10h2V3zm4.83 2.17l-1.42 1.42C17.99 7.86 19 9.81 19 12c0 3.87-3.13 7-7 7s-7-3.13-7-7c0-2.19 1.01-4.14 2.58-5.42L6.17 5.17C4.23 6.82 3 9.26 3 12c0 4.97 4.03 9 9 9s9-4.03 9-9c0-2.74-1.23-5.18-3.17-6.83z" fill="#4a4d55" scaleX="2.44" scaleY="2.44" />
                                       </children>
                                    </VBox>
                                 </children>
                              </HBox>
                           </children>
                        </VBox>
                     </children>
                  </VBox>
               </children>
            </VBox>
            <VBox minWidth="-Infinity" prefHeight="200.0" prefWidth="20.0">
               <children>
                  <HBox minHeight="-Infinity" prefHeight="320.0" prefWidth="200.0" style="-fx-background-color: #353841;" />
                  <HBox minHeight="-Infinity" prefHeight="280.0" prefWidth="200.0" style="-fx-background-color: #3F434B;" />
               </children>
            </VBox>
         </children>
      </HBox>
      <ProgressIndicator fx:id="loading" layoutX="627.0" layoutY="250.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="100.0" visible="false" />
   </children>
</AnchorPane>


Класс расчета:

package sample;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import javafx.collections.ObservableList;
import javafx.scene.chart.PieChart;

public class Calc {

    private int totalFolder=0, totalFile=0;
    private static int counter = 0;
    private final ObservableList<PieChart.Data> pieChartData;
    private long filesInRoot = 0;
    Path fileInRoot;


    //added a constructor to receive a reference of the Observable list
    public Calc(ObservableList<PieChart.Data> pieChartData) {
        this.pieChartData = pieChartData;
    }


    public void calcSubfoldersSize(String sPath) { //replaces public void main(String args)

        File nativeFile = new File(sPath);
        File file = new File(nativeFile.toString());

        String[] files = file.list();
        Path path;

        filesInRoot = 0;
        if(file.isDirectory()) {
            for(int i=0; i<=files.length-1; i++) {
                path = Paths.get(files[i]);
                file = path.toFile();
                counter ++;
            }

            String[] paths = new String[counter];
            for(int i=0; i<=files.length-1; i++) {
                path = Paths.get(files[i]);
                file = path.toFile();
                paths[i] = file.toString();
            }

            for(int i=0; i!=counter; i++) {

            }
            for(int i = 0; i+1 <= paths.length; i++) {
                try {
                    Calc size = new Calc(pieChartData); //the only line changed in the method
                    long fileSizeByte = size.getFileSize(new File(nativeFile.toString() + "\\" + paths[i]));
                    add(paths[i],fileSizeByte,i,paths.length);
                } catch (Exception e) {
                    fileInRoot = Paths.get(nativeFile.toString()+"\\" + paths[i]);
                    filesInRoot = filesInRoot + fileInRoot.toFile().length();
                }
            }
            if(filesInRoot!=0){
                pieChartData.add(new PieChart.Data("Files in Directory",filesInRoot));
                System.out.println(filesInRoot);
            }
        }
    }

    //let add update the observable list
    public void add(String loc, long size, int i, int aim){
        pieChartData.add(new PieChart.Data(loc,size));
    }

    public long getFileSize(File folder) {
        long foldersize = 0;

        totalFolder++;
//          System.out.println("Folder: " + folder + "  (Source: getFileSize)");
        File[] filelist = folder.listFiles();
//          System.out.println(folder.listFiles());

        for (int i = 0; i < filelist.length; i++) {
            if (filelist[i].isDirectory()) {
                foldersize += getFileSize(filelist[i]);
            } else {
                totalFile++;
                foldersize += filelist[i].length();
            }
        }

        return foldersize;

    }

    public int getTotalFolder() {
        return totalFolder;
    }

    public int getTotalFile() {
        return totalFile;
    }
}

РЕДАКТИРОВАТЬ:

Основной класс:

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("Files.fxml"));
        primaryStage.setTitle("Fileview.io");
        primaryStage.setScene(new Scene(root));
        primaryStage.setResizable(false);
        primaryStage.show();
    }


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

Класс контроллера:

package sample;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Rectangle;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

public class Controller {

    @FXML
    private PieChart pieChart;
    @FXML
    private TextField pathField;
    @FXML
    private Label subfolder;
    @FXML
    private Button up;
    @FXML
    private Button hide;
    @FXML
    private Button showHidden;
    @FXML
    private VBox field1;
    @FXML
    private VBox field2;
    @FXML
    private VBox field3;
    @FXML
    private VBox field4;
    @FXML
    private AnchorPane parentContainer;
    @FXML
    private ProgressIndicator loading;



    private ObservableList<PieChart.Data> pieChartData;
    private Calc calc;
    public File directory;
    String[] unit = {"Bytes", "KB", "MB", "GB", "TB", "PB", "ZB", "EB"};
    int units = 0;
    boolean hideSegment = false;
    String[] hiddenPath = new String[500];
    double[] hiddenSize = new double[500];
    int Stelle = 499;
    boolean first = true;


    @FXML
    private void handleBrowse(){
        Stage stage = new Stage();
        final DirectoryChooser dirChooser = new DirectoryChooser();
        directory = dirChooser.showDialog(stage);
        if(directory != null){
            pathField.setText(directory.toString());
        }
    }

    @FXML
    private void apply() {
        loading.setVisible(true);

        Task<Void> applyTask = new Task<Void>() {

            @Override
            protected Void call() throws Exception {

                Thread.sleep(0);//sleep for 10 seconds just to show that the progress indicator is working

                directory = Paths.get(pathField.getText()).toFile();
                if (directory != null) {
                    //fx-parts need to be executed by Platform.runLater(...)
                    Platform.runLater(() -> pieChartData.clear());
                    String strings = new String(pathField.getText());
                    calc.calcSubfoldersSize(strings);
                    //again let fx-parts be executed in the fx-application-thread
                    Platform.runLater(() -> updataLabads());
                }

                return null;
            }
        };

        applyTask.setOnSucceeded(e -> loading.setVisible(false));
        applyTask.setOnFailed(e -> loading.setVisible(false));//handle error here...

        new Thread(applyTask, "Apply thread").start();

        //loading.setVisible(false); //done when the task ends
    }

    public void updataLabads(){
        pieChart.getData().forEach(data -> {
            data.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED, e -> {

                for(int i=0;(data.getPieValue()/(Math.pow(1024, i))) > 1000;i++){
                    //System.out.println(i);
                    units = i+1;
                }
                subfolder.setText(data.getName() + ", " + Math.round(data.getPieValue()/(Math.pow(1024,units))) + " " + unit[units]);
                //System.out.println(Math.round(data.getPieValue()/(Math.pow(1024,units))) + " " + unit[units]);
            });
        });
        pieChart.getData().forEach(data -> {
            data.getNode().addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
                if(hideSegment == false){
                    pathField.setText(pathField.getText() + "\\" + data.getName());
                    apply();
                }else if(hideSegment == true){
                    pieChartData.remove(data);
                    hideSegment = false;
                    if(first == true){
                        first = false;
                        Stelle = 0;
                    }
                    hiddenPath[Stelle] = data.getName();
                    hiddenSize[Stelle] = data.getPieValue();
                    System.out.println("Hidden Variables have been updatet on Port " + Stelle);
                    Stelle++;
                    pieChart.setData(pieChartData);
                }
            });
        });
    }

    @FXML
    private void up(){
        while(!pathField.getText().substring(pathField.getText().length()-1).equals("\\")){
            pathField.setText(pathField.getText().substring(0, pathField.getText().length()-1));
        }
        pathField.setText(pathField.getText().substring(0, pathField.getText().length()-1));
        apply();
    }

    @FXML
    public void hide(){
        if(hideSegment == false)hideSegment = true;
        else if(hideSegment == true)hideSegment = false;
    }

    @FXML
    public void showHidden(){
        System.out.println("Tried to load HiddenVariables on Port " + (Stelle-1));
        System.out.println(hiddenPath[Stelle-1] + "   " + hiddenSize[Stelle-1]);
        if(!hiddenPath[Stelle-1].equals(null)){
            for(int i=Stelle; i!=0; i--){
                pieChartData.add(new PieChart.Data(hiddenPath[Stelle-1], hiddenSize[Stelle-1]));
                hiddenPath[Stelle-1] = "";
                hiddenSize[Stelle-1] = 0;
                Stelle--;
                pieChart.setData(pieChartData);
                updataLabads();
            }
        }
    }

    public void initialize(){
        pieChartData = FXCollections.observableArrayList();
        updataLabads();
        calc = new Calc(pieChartData);
        pieChart.setData(pieChartData);
    }

    @FXML
    public void Home() throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"));
        Scene scene = up.getScene();
        root.translateYProperty().set(scene.getHeight());
        parentContainer.getChildren().add(root);
        Timeline timeline = new Timeline();
        KeyValue kv = new KeyValue(root.translateYProperty(), 0 , Interpolator.EASE_BOTH);
        KeyFrame kf = new KeyFrame(Duration.seconds(.5), kv);
        timeline.getKeyFrames().add(kf);
        timeline.play();
        parentContainer.getChildren().remove(parentContainer);
    }

    @FXML
    public void Files(){}

    @FXML
    public void Settings(){}

    @FXML
    public void Close(){
        Platform.exit();
    }
}

Класс Calc доступен в ответе @Tobias. Когда я запускаю проект, я просто запускаю класс Main


person Mr.X    schedule 18.07.2019    source источник
comment
Мне жаль. соглашения об именах... вы имеете в виду имена переменных и методов...? (английский не мой родной язык)   -  person Mr.X    schedule 18.07.2019
comment
точно - и естественный язык не так важен, их легко выучить :)   -  person kleopatra    schedule 18.07.2019
comment
Ты прав. Я работаю над этим (мне всего 14).   -  person Mr.X    schedule 18.07.2019


Ответы (2)


Проблема в том, что выполнение метода применения блокирует FX-Thread, поэтому индикатор выполнения не может отображаться.

Таким образом, выполнение должно быть выполнено в другом потоке (или задаче), чтобы индикатор выполнения был виден. Затем, когда задача выполнена успешно, вы можете снова установить видимость индикатора выполнения на false. (Также проблема заключается в том, что метод применения слишком быстрый, поэтому индикатор не отображается. Я добавил 10-секундный сон, чтобы показать, что он работает)

Решением было бы изменить ваш метод apply() следующим образом:

@FXML
private void apply() {
    loading.setVisible(true);

    Task<Void> applyTask = new Task<Void>() {

        @Override
        protected Void call() throws Exception {

            Thread.sleep(10000);//sleep for 10 seconds just to show that the progress indicator is working

            directory = Paths.get(pathField.getText()).toFile();
            if (directory != null) {
                //fx-parts need to be executed by Platform.runLater(...)
                Platform.runLater(() -> pieChartData.clear());

                String strings = new String(pathField.getText());
                calc.calcSubfoldersSize(strings);

                //again let fx-parts be executed in the fx-application-thread
                Platform.runLater(() -> updataLabads());
            }

            return null;
        }
    };

    applyTask.setOnSucceeded(e -> loading.setVisible(false));
    applyTask.setOnFailed(e -> loading.setVisible(false));//handle error here...

    new Thread(applyTask, "Apply thread").start();

    //loading.setVisible(false); //done when the task ends
}

ИЗМЕНИТЬ:

Чтобы ответить на ваш вопрос в комментариях:

Если вы измените класс Calc таким образом, он должен работать (пометил правки комментариями):

package sample;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;

import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.scene.chart.PieChart;

public class Calc {

    private int totalFolder = 0, totalFile = 0;
    private static int counter = 0;
    private final ObservableList<PieChart.Data> pieChartData;
    private ArrayList<PieChart.Data> pieChartData2;//EDIT: here you don't need an ObservableList, a simple ArrayList will do it
    private long filesInRoot = 0;
    Path fileInRoot;

    //added a constructor to receive a reference of the Observable list
    public Calc(ObservableList<PieChart.Data> pieChartData) {
        this.pieChartData = pieChartData;//EDIT: when you set this.pieChartData = pieChartData2 the parameter would be ignored...
        pieChartData2 = new ArrayList<PieChart.Data>();
    }

    public void calcSubfoldersSize(String sPath) { //replaces public void main(String args)
        File nativeFile = new File(sPath);
        File file = new File(nativeFile.toString());

        String[] files = file.list();
        Path path;

        filesInRoot = 0;
        if (file.isDirectory()) {
            for (int i = 0; i <= files.length - 1; i++) {
                path = Paths.get(files[i]);
                file = path.toFile();
                counter++;
            }

            String[] paths = new String[counter];
            for (int i = 0; i <= files.length - 1; i++) {
                path = Paths.get(files[i]);
                file = path.toFile();
                paths[i] = file.toString();
            }

            for (int i = 0; i != counter; i++) {

            }
            for (int i = 0; i + 1 <= paths.length; i++) {
                try {
                    Calc size = new Calc(pieChartData); //the only line changed in the method
                    long fileSizeByte = size.getFileSize(new File(nativeFile.toString() + "\\" + paths[i]));
                    add(paths[i], fileSizeByte, i, paths.length);
                }
                catch (Exception e) {
                    fileInRoot = Paths.get(nativeFile.toString() + "\\" + paths[i]);
                    filesInRoot = filesInRoot + fileInRoot.toFile().length();
                }
            }
            if (filesInRoot != 0) {
                add("Files in Directory", filesInRoot, 1, 100);
                pieChartData2.add(new PieChart.Data("Files in Directory", filesInRoot));
                System.out.println(filesInRoot);
            }
        }

        //EDIT: let this part be executed by the fx-application thread:
        Platform.runLater(() -> pieChartData.addAll(pieChartData2));
    }

    //let add update the observable list
    public void add(String loc, long size, int i, int aim) {
        pieChartData2.add(new PieChart.Data(loc, size));//EDIT: the error seems to occur here because pieChartData2 was null (but I'm not sure why there was no exception shown...; probably because it's executed in the task...) 
    }

    public long getFileSize(File folder) {
        long foldersize = 0;

        totalFolder++;
        //          System.out.println("Folder: " + folder + "  (Source: getFileSize)");
        File[] filelist = folder.listFiles();
        //          System.out.println(folder.listFiles());

        for (int i = 0; i < filelist.length; i++) {
            if (filelist[i].isDirectory()) {
                foldersize += getFileSize(filelist[i]);
            }
            else {
                totalFile++;
                foldersize += filelist[i].length();
            }
        }

        return foldersize;

    }

    public int getTotalFolder() {
        return totalFolder;
    }

    public int getTotalFile() {
        return totalFile;
    }
}

В обновленном классе Controller, который вы показали в своем ответе, я думаю, что в этой части есть еще одна проблема:

//...
String strings = new String(pathField.getText());
calc.calcSubfoldersSize(strings);
Platform.runLater(() -> initialize());
//...

Даже если вызов метода calc.calcSubfoldersSize(strings) работает, следующий вызов Platform.runLater(() -> initialize()); сбросит найденные результаты. Поэтому вы должны удалить последнюю строку Platform.runLater(() -> initialize());

Для полноты вот полный класс Controller, который работал у меня:

package sample;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Controller {

    @FXML
    private PieChart pieChart;
    @FXML
    private TextField pathField;
    @FXML
    private Label subfolder;
    @FXML
    private Button up;
    @FXML
    private Button hide;
    @FXML
    private Button showHidden;
    @FXML
    private VBox field1;
    @FXML
    private VBox field2;
    @FXML
    private VBox field3;
    @FXML
    private VBox field4;
    @FXML
    private AnchorPane parentContainer;
    @FXML
    private ProgressIndicator loading;

    private ObservableList<PieChart.Data> pieChartData;
    private Calc calc;
    public File directory;
    String[] unit = {"Bytes", "KB", "MB", "GB", "TB", "PB", "ZB", "EB"};
    int units = 0;
    boolean hideSegment = false;
    String[] hiddenPath = new String[500];
    double[] hiddenSize = new double[500];
    int Stelle = 499;
    boolean first = true;

    @FXML
    void initialize() {
        pieChartData = FXCollections.observableArrayList();
        calc = new Calc(pieChartData);
        updataLabads();
        pieChart.setData(pieChartData);
    }

    @FXML
    private void handleBrowse() {
        Stage stage = new Stage();
        final DirectoryChooser dirChooser = new DirectoryChooser();
        directory = dirChooser.showDialog(stage);
        if (directory != null) {
            pathField.setText(directory.toString());
        }
    }

    @FXML
    private void apply() {
        loading.setVisible(true);

        Task<Void> applyTask = new Task<Void>() {

            @Override
            protected Void call() throws Exception {

                Thread.sleep(3000);//sleep for 3 seconds just to show that the progress indicator is working

                directory = Paths.get(pathField.getText()).toFile();
                if (directory != null) {
                    //fx-parts need to be executed by Platform.runLater(...)
                    Platform.runLater(() -> pieChartData.clear());

                    String strings = new String(pathField.getText());
                    calc.calcSubfoldersSize(strings);

                    //again let fx-parts be executed in the fx-application-thread
                    Platform.runLater(() -> updataLabads());
                }

                return null;
            }
        };

        applyTask.setOnSucceeded(e -> loading.setVisible(false));
        applyTask.setOnFailed(e -> loading.setVisible(false));//handle error here...

        new Thread(applyTask, "Apply thread").start();

        //loading.setVisible(false); //done when the task ends
    }

    public void updataLabads() {
        pieChart.getData().forEach(data -> {
            data.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED, e -> {

                for (int i = 0; (data.getPieValue() / (Math.pow(1024, i))) > 1000; i++) {
                    //System.out.println(i);
                    units = i + 1;
                }
                subfolder.setText(data.getName() + ", " + Math.round(data.getPieValue() / (Math.pow(1024, units))) + " " + unit[units]);
                //System.out.println(Math.round(data.getPieValue()/(Math.pow(1024,units))) + " " + unit[units]);
            });
        });
        pieChart.getData().forEach(data -> {
            data.getNode().addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
                if (hideSegment == false) {
                    pathField.setText(pathField.getText() + "\\" + data.getName());
                    apply();
                }
                else if (hideSegment == true) {
                    pieChartData.remove(data);
                    hideSegment = false;
                    if (first == true) {
                        first = false;
                        Stelle = 0;
                    }
                    hiddenPath[Stelle] = data.getName();
                    hiddenSize[Stelle] = data.getPieValue();
                    System.out.println("Hidden Variables have been updatet on Port " + Stelle);
                    Stelle++;
                    pieChart.setData(pieChartData);
                }
            });
        });
    }

    @FXML
    private void up() {
        while (!pathField.getText().substring(pathField.getText().length() - 1).equals("\\")) {
            pathField.setText(pathField.getText().substring(0, pathField.getText().length() - 1));
        }
        pathField.setText(pathField.getText().substring(0, pathField.getText().length() - 1));
        apply();
    }

    @FXML
    public void hide() {
        if (hideSegment == false)
            hideSegment = true;
        else if (hideSegment == true)
            hideSegment = false;
    }

    @FXML
    public void showHidden() {
        System.out.println("Tried to load HiddenVariables on Port " + (Stelle - 1));
        System.out.println(hiddenPath[Stelle - 1] + "   " + hiddenSize[Stelle - 1]);
        if (!hiddenPath[Stelle - 1].equals(null)) {
            for (int i = Stelle; i != 0; i--) {
                pieChartData.add(new PieChart.Data(hiddenPath[Stelle - 1], hiddenSize[Stelle - 1]));
                hiddenPath[Stelle - 1] = "";
                hiddenSize[Stelle - 1] = 0;
                Stelle--;
                pieChart.setData(pieChartData);
                updataLabads();
            }
        }
    }

    @FXML
    public void Home() throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"));
        Scene scene = up.getScene();
        root.translateYProperty().set(scene.getHeight());
        parentContainer.getChildren().add(root);
        Timeline timeline = new Timeline();
        KeyValue kv = new KeyValue(root.translateYProperty(), 0, Interpolator.EASE_BOTH);
        KeyFrame kf = new KeyFrame(Duration.seconds(.5), kv);
        timeline.getKeyFrames().add(kf);
        timeline.play();
        parentContainer.getChildren().remove(parentContainer);
    }

    @FXML
    public void Files() {}

    @FXML
    public void Settings() {}

    @FXML
    public void Close() {
        Platform.exit();
    }
}
person Tobias    schedule 18.07.2019
comment
хммм... updataLabads, похоже, обновляет график сцены, как и pieChartData.clear. Если это так, неправильно вызывать его из другого потока. - person kleopatra; 18.07.2019
comment
@kleopatra вы правы, и поскольку класс calc (я добавлю его к вопросу) (я полагаю, не уверен :) делает что-то подобное, я получаю следующую ошибку: Exception in thread "Apply thread" java.lang.IllegalStateException: Not on FX application thread; currentThread = Apply thread - person Mr.X; 18.07.2019
comment
@ Mr.X Я тестировал пустой класс Calc, так что для меня это сработало. Но ты прав. Это вызовет ошибки. Вам нужно запустить все, что изменяет FX-объекты, в потоке приложения java FX, но расчет должен быть в файле Task. Вы можете использовать Platform.runLater(() -> updateLabads()), чтобы fx-части выполнялись в fx-потоке (также для pieChartData.clear(), ...). - person Tobias; 18.07.2019
comment
Куда мне его вставить? - person Mr.X; 18.07.2019
comment
Извините, но это тоже не работает. Я все еще получаю сообщение об ошибке, что это не в потоке fx (сообщение об ошибке выше) - person Mr.X; 18.07.2019
comment
Когда я пытаюсь это сделать (также после добавления правильного класса Calc), он работает. Попробуйте найти строку, которая вызывает ошибку, и выполните эту строку с runnable в Platform.runLater(Runnable), как в примере кода. Если это не сработает, попробуйте опубликовать второй вопрос... - person Tobias; 18.07.2019
comment
calcSubfolderSize меняет граф сцены.. это бездонная яма без четкого отделения пользовательского интерфейса от расчета пути.. - person kleopatra; 18.07.2019
comment
Как уже упоминалось @kleopatra, вы добавляете новые данные в piChartData в методе Calc.calcSubfoldersSize(String), что (вероятно) вызывает проблемы. Вы должны попытаться добавить все результаты в отдельный список (новый ArrayList<PieChart.Data> в вашем классе Calc и добавить все элементы в этот список в ObservableList<PieChart.Data> pieChartData в конце метода calcSubfoldersSize сразу, используя метод addAll(...) из pieChartData (последнее добавление необходимо сделать с Platform.runLater(...)). - person Tobias; 18.07.2019
comment
Это тоже не работает, но я уверен, что это потому, что я неправильно истолковал ваши инструкции. Может быть, вы могли бы проверить, что я сделал с кодом. Я опубликую это как ответ ниже. - person Mr.X; 18.07.2019
comment
@ Mr.X Я проверил код, который вы разместили в ответе, и отредактировал свой ответ. - person Tobias; 18.07.2019
comment
Не могли бы вы также загрузить код класса Controller? Это все еще не работает для меня. Скорее всего моя вина. - person Mr.X; 18.07.2019
comment
@Mr.X Я ничего не менял, кроме кода, который я разместил. Не могли бы вы отредактировать свой вопрос и добавить объяснение того, как вы запускаете свою программу, чтобы я мог ее протестировать? В противном случае я только предполагаю, в чем проблема. (Какова ваша структура каталогов, что вы добавляете в текстовое поле,...) - person Tobias; 18.07.2019
comment
@Mr.X Думаю, теперь я понял :) Проблема была в том, что в вашем методе add(...) в классе Calc поле pieChartData2 было пустым, поэтому выполнение было прервано NullPointerException (которое почему-то не отображалось в консоли, возможно, потому что он был выполнен в задаче). Я снова обновил свой ответ и добавил полные классы Calc и Controller. Когда я тестирую его, он теперь показывает круговую диаграмму, поэтому я думаю, что на этот раз он действительно может работать;) - person Tobias; 19.07.2019
comment
@Тобиас: ты гений. Теперь это работает. Большое спасибо. Извините, что отнял у вас столько времени. Последний вопрос: вы исправили это, установив pieChartData2 = new ArrayList<PieChart.Data> правильно? - person Mr.X; 19.07.2019
comment
@Mr.X Добро пожаловать :) Да, я исправил это, инициализировав pieChartData2, потому что в противном случае это null, что приводит к NullPointerException при вызове метода add(String, long, int, int). - person Tobias; 19.07.2019
comment
И поскольку NullPointerException был в другом потоке, он не отображался в консоли, верно? Есть ли способ избежать этого? - person Mr.X; 19.07.2019
comment
Да. Вы можете попытаться установить DefaultUncaughtExceptionHandler потока, используя этот метод класса Thread. Вы можете попробовать это Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> throwable.printStackTrace()); (но я не проверял, поэтому не уверен, что это сработает). - person Tobias; 19.07.2019

Я предполагаю, что пользовательский интерфейс зависает во время расчета и, следовательно, не показывает ваш индикатор, поскольку пользовательский интерфейс не может обновляться. В конце, когда расчет закончится, индикатор станет видимым, а затем снова невидимым, потому что расчет завершен (вероятно, это и есть короткая вспышка индикатора).

Решение состоит в том, чтобы поместить ваш расчет в новый Thread, чтобы он мог выполняться параллельно, а поток пользовательского интерфейса не блокировался расчетом.

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

person Nexonus    schedule 18.07.2019