2

My JavaFX application calculates the folder sizes of every folder one level under another folder. My problem is that when I hit the apply button, which starts the calculation in another class, I want an indeterminate progress-indicator to show the user that the app is working right now and hasn't hung itself up. By default, the progress-indicator is set to invisible and is just set to visible during the calculation. Unfortunately, it doesn't show up when I call it. I'm not sure, but when the calculation is finished and the data from it is set to a JavaFX.Pie-Chart, I might have caught a glimpse of the indicator.

I've already tried to set the Indicator to visible by default and simply cover it up with a new Rectangle, but this didn't work either.

Controller:

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 document:

<?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>


Calc class:

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;
    }
}

EDIT:

Main Class:

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);
    }
}

Controller Class:

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 class is available in @Tobias answer. When I run the project, I simply launch the Main class

Mr.X
  • 97
  • 1
  • 12

2 Answers2

3

I would guess, that the UI hangs during the calculation and therefore not showing your indicator as the UI can't update. At the end, when the calculation finished, the indicator will be set to visible and then invisible again, because the calculation finished (that is probably what the short flash of the indidcator is).

The solution is to put your calculation in a new Thread, so it can run in parallel and the UI Thread is not blocked by the calculation.

Take a look at this answer for example to see how you can create a new thread.

Nexonus
  • 706
  • 6
  • 26
2

The problem is, that the execution of the apply method blocks the FX-Thread, so the progress indicator can't be displayed.

So the execution needs to be done in another Thread (or a Task) to make the progress indicator visible. Then when the Task has succeeded you can set the visibility of the progress indicator to false again. (Also a problem is that the apply method is just to fast, so the indicator doesn't show up. I added a sleep of 10 seconds to show it's working)

A solution would be to change your apply() method like this:

@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
}

EDIT:

In order to answer your question in the comments:

If you change the class Calc like this it should work (marked the edits with comments):

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;
    }
}

In the updated Controller class that you showed in your answer, I think is another problem in this part:

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

Even if the method-call calc.calcSubfoldersSize(strings) is working, the next call of Platform.runLater(() -> initialize()); will reset the results that were found. So you should delete the last line Platform.runLater(() -> initialize());

For completeness here is the full Controller class that worked for me:

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();
    }
}
Tobias
  • 2,547
  • 3
  • 14
  • 29
  • hmmm ... updataLabads seems to update the scenegraph as does pieChartData.clear. If so, it's wrong to call it from another thread. – kleopatra Jul 18 '19 at 11:19
  • @kleopatra you're right and since the calc class(I'm gonna add it to the question) (I assume, not sure:) does something similar, I get following error: ```Exception in thread "Apply thread" java.lang.IllegalStateException: Not on FX application thread; currentThread = Apply thread ``` – Mr.X Jul 18 '19 at 11:33
  • @Mr.X I tested with an empty class `Calc` so for me this was working. But you're right. This will cause errors. You need to run everything that changes the FX-objects in the java FX application thread, but the calculation needs to be in the `Task`. You can use `Platform.runLater(() -> updateLabads())` to let the fx-parts be executed in the fx-thread (also for pieChartData.clear(), ...). – Tobias Jul 18 '19 at 11:38
  • Where do I have to insert it? – Mr.X Jul 18 '19 at 11:42
  • I'm sorry but this doesn't work either. I still get the Error that it's not on the fx Thread (Error message above) – Mr.X Jul 18 '19 at 11:48
  • When I try it (also after adding the correct `Calc` class) it's working. Try to find the line that causes the error and execute this line with the runnable in `Platform.runLater(Runnable)` like in the example code. If this doesn't work maybe try to post a second question... – Tobias Jul 18 '19 at 11:56
  • calcSubfolderSize changes the scenegraph .. it's a bottomless pit without separating the ui cleanly from the path calculation .. – kleopatra Jul 18 '19 at 12:01
  • Like @kleopatra mentioned, you are adding new data to `piChartData` in the method `Calc.calcSubfoldersSize(String)`, which (probably) causes the problems. You should try to add all the results to a seperate list (a new `ArrayList` in your `Calc` class and add all the elements in this list into the `ObservableList pieChartData` at the end of the method `calcSubfoldersSize` at once using the `addAll(...)` method of `pieChartData` (the last adding needs to be done with `Platform.runLater(...)`). – Tobias Jul 18 '19 at 12:15
  • This doesn't work either, but I'm sure it's because I've misinterpreted your instructions. Maybe you could check what I've done to the code. I'm gonna post it as an answer below. – Mr.X Jul 18 '19 at 17:55
  • @Mr.X I checked the code you posted in the answer and edited my answer. – Tobias Jul 18 '19 at 19:02
  • Could you please upload your Code of the ```Controller``` Class as well? It still doesn't work for me. Most probably my fault. – Mr.X Jul 18 '19 at 19:24
  • @Mr.X I didn't change anything apart from the code I posted. Could you edit your question and add an explenation how you run your program so I can test it? Otherwise I'm only guessing what is the problem. (What is your directory structure, what do you add in the text field, ...) – Tobias Jul 18 '19 at 19:43
  • @Mr.X I think I figured it out now :) The problem was, that in your method `add(...)` in the `Calc` class the field `pieChartData2` was null, so the execution got interrupted by a NullPointerException (which somehow wasn't shown in the console, probably because it was executed in a task). I updated my answer again and added the full classes `Calc` and `Controller`. When I test it it now shows the PieChart, so I think this time it could realy be working ;) – Tobias Jul 19 '19 at 07:06
  • @Tobias :You're a genious. It works now. Thank you so much. I'm sorry for consuming so much of your time. Last question: You fixed this by setting ```pieChartData2 = new ArrayList``` right? – Mr.X Jul 19 '19 at 12:31
  • @Mr.X Your welcome :) Yes I fixed it by initializing `pieChartData2`, because otherwhise it is `null`, which leads to a `NullPointerException` when you call the method `add(String, long, int, int)`. – Tobias Jul 19 '19 at 12:33
  • And because the ```NullPointerException``` was in another Thread it didn't show up in the console, right? Is there a way to avoid this? – Mr.X Jul 19 '19 at 12:42
  • Yes. You can try to set the `DefaultUncaughtExceptionHandler` of the thread using [this mehtod of the class Thread](https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)). You can try this `Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> throwable.printStackTrace());` (but I didn't test it so I'm not sure if it will work). – Tobias Jul 19 '19 at 12:57