I'm trying to write a simple program including a javafx PieChart. The purpose of the program is that I want to show the size of every subfolder in a directory in a PieChart. Problem:
I want to simply display some data from another class in a PieChart. I transfer the data through an object of the controller class in the calc class and the other way around using matching parameters in each class. But instead of applying the data nothing happens. If I just feed some Data directly into the PieChartData List everything is working fine.
I've already tried to apply the data via endless ways but this just gave me a NullPointerError or an InvocationTargetException.
Controller:
package sample;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import java.io.File;
import java.nio.file.Path;
public class Controller {
Calc calc = new Calc();
@FXML
public PieChart pieChart;
public Button browse;
public Button apply;
public TextField pathField;
String[] locs = new String[1000];
double[] sizes = new double[1000];
int count = 0;
ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
public void handleBrowse(){
pathField.setText("C:\\Users\\user\\Desktop\\Test");
}
public void apply(){
System.out.println(pathField.getText());
String strings = new String(pathField.getText());
calc.main(strings);
System.out.println("2");
pieChart.setData(pieChartData);
}
public void setData(String loc, long size, int i, int aim){
pieChartData.add(new PieChart.Data(loc,size));
System.out.println("1");
}
}
//alt+Enter = Import
Calc:
package sample;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Calc {
public int totalFolder=0;
public int totalFile=0;
public static int counter = 0;
public void main(String args) {
File nativeFile = new File(args);
File file = new File(nativeFile.toString());
String[] files = file.list();
Path path;
Main main = new Main();
if(file.isDirectory()) {
for(int i=0; i<=files.length-1; i++) {
path = Paths.get(files[i]);
file = path.toFile();
System.out.println(file + " (source: Main.java)");
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();
}
System.out.println("");
for(int i=0; i!=counter; i++) {
}
for(int i = 0; i+1 <= paths.length; i++) {
try {
Calc size = new Calc();
long fileSizeByte = size.getFileSize(new File(nativeFile.toString() + "\\" + paths[i]));
System.out.println("Folder Size of " + paths[i] + " is: " + fileSizeByte / 1073741824 + " GB" + " or " + fileSizeByte + " bytes");
add(paths[i],fileSizeByte,i,paths.length);
} catch (Exception e) {
System.out.println("failure");
e.printStackTrace();
}
}
}
}
public void add(String loc, long size, int i, int aim){
Controller controller = new Controller();
controller.setData(loc,size,i,aim);
}
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;
}
}
sample.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.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<PieChart fx:id="pieChart" layoutX="348.0" layoutY="50.0" prefHeight="500.0" prefWidth="500.0" title="Subfolders" />
<Separator layoutX="316.0" layoutY="-18.0" orientation="VERTICAL" prefHeight="633.0" prefWidth="0.0" />
<TextField fx:id="pathField" focusTraversable="false" layoutX="31.0" layoutY="115.0" prefHeight="26.0" prefWidth="188.0" promptText="Type Path or" />
<Button fx:id="browse" layoutX="222.0" layoutY="115.0" mnemonicParsing="false" onAction="#handleBrowse" prefHeight="26.0" prefWidth="65.0" text="Browse" />
<Label layoutX="116.0" layoutY="41.0" text="Options">
<font>
<Font size="27.0" />
</font>
</Label>
<Button fx:id="apply" layoutX="31.0" layoutY="159.0" mnemonicParsing="false" onAction="#apply" prefHeight="55.0" prefWidth="256.0" text="Apply" />
</children>
</AnchorPane>
I expect the code to display the double fileSizeByte and the String path from the controller class.
When the .fxml
file is loaded, an instance of Controller
is constructed.
The main issue with the solution posted is that by
public void add(String loc, long size, int i, int aim){
Controller controller = new Controller();
controller.setData(loc,size,i,aim);
}
you actually setData
to a new Cotroller
instance, and not the one use by he controller.
A better solution would be to let Calc
have a reference of the ObservableList
you want to update with the calculation results:
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;
//added a constructor to receive a reference of the Observable list
public Calc(ObservableList<PieChart.Data> pieChartData) {
this.pieChartData = pieChartData;
}
/*
* This method is copied from the original method called main.
* The use of the name main is confusing.
* The calculation done in this method has some issues, but it is not relevant
* to the question asked.
*/
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;
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) {
System.out.println("failure");
e.printStackTrace();
}
}
}
}
//let add update the observable list
public void add(String loc, long size, int i, int aim){
pieChartData.add(new PieChart.Data(loc,size));
}
//no change in other methods
}
And use Calc
in the controller like so:
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.PieChart;
import javafx.scene.control.TextField;
public class Controller {
@FXML
private PieChart pieChart;
@FXML
private TextField pathField;
private ObservableList<PieChart.Data> pieChartData;
private Calc calc;
@FXML
void initialize(){
pieChartData = FXCollections.observableArrayList();
calc = new Calc( pieChartData);
pieChart.setData(pieChartData);
}
@FXML
private void handleBrowse(){
pathField.setText("C:/Users/user/Desktop/Test");
}
@FXML
private void apply(){
String strings = new String(pathField.getText());
calc.calcSubfoldersSize(strings);
}
}