0

I'm trying to generate statistical graphs (BarCharts and LineCharts) from the data saved in an sql database using Java. The Data is expected to change from time to time.

I have tried using ObservableLists but am getting error messages.

Below is what I have tried so far; NOTE: This resides in the DatabaseHandler class

public ObservableList<BarChart.Data> getItemGraphStatistics(){
        ObservableList<BarChart.Data> data = FXCollections.observableArrayList();

        String sql = "SELECT itemID, COUNT(*) FROM (SELECT itemID FROM SALES UNION ALL SELECT itemID FROM STOCK) t GROUP BY itemID";
        System.out.println(sql );
        ResultSet rs = handler.execQuery(sql);
        try{

            while(rs.next()){
                String item= rs.getString("itemID");
                int count = rs.getInt(2);

                data.add(new BarChart.Data(item+ "(" + count + ")", count));

            }
        } catch (SQLException ex) {
            Logger.getLogger(DatabaseHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
        return data;

    }

On running the above am getting

java.lang.ClassCastException: javafx.scene.chart.XYChart$Data cannot be cast to javafx.scene.chart.XYChart$Series

When i try to change BarChart.Data to BarChart.Series, I get unable to convert int to observableList error message.

Below is an example of the trial of the above;

import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXRadioButton;
import com.jfoenix.controls.JFXTextField;
import java.net.URL;
import java.util.Calendar;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.ToggleGroup;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import sales.manager.database.DatabaseHandler;

/**
 * FXML Controller class
 *
 * @author Garande
 */
public class PerformanceAnalyzerController implements Initializable {

    @FXML
    private AnchorPane analysisHandler;
    @FXML
    private AnchorPane graphHandler;
    @FXML
    private PieChart piechart;
    @FXML
    private BarChart<?, ?> barchart;
    @FXML
    private LineChart<?, ?> linechart;

    @FXML
    private NumberAxis yBarGraph;
    @FXML
    private CategoryAxis xBarGraph;
    @FXML
    private NumberAxis yLineGraph;
    @FXML
    private CategoryAxis xLineGraph;

    DatabaseHandler handler = DatabaseHandler.getInstance();

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {


    }    

    @FXML
    private void performAnalysisOperation(ActionEvent event) {
        //Performing analysis operation

        barchart.setData(handler.getItemGraphStatistics());
        graphHandler.getChildren().add(barchart);
    }
}
Garande
  • 174
  • 2
  • 13
  • 1
    I don't believe the code you've shown should be throwing that error. Please provide a [mcve] demonstrating the issue. Note an `XYChart` holds an `ObservableList`and each `Series` holds an `ObservableList`. Also, you [shouldn't use raw types](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). – Slaw Apr 14 '19 at 12:16
  • @Slaw I have made changes to the question as requested. I have added an example. – Garande Apr 14 '19 at 12:58

1 Answers1

1

The data property of an XYChart holds an ObservableList<XYChart.Series>. Each XYChart.Series also has a data property, but it holds an ObservableList<XYChart.Data>. The problem is your method returns an ObservableList<XYChart.Data> that you then try to set on XYChart.data—the types don't match. I'm not sure how you're getting a ClassCastException, as your code shouldn't even compile.

You need to wrap your list of data in a series, then add the series to the chart. You should also avoid using raw types. Both Series and Data have type parameters but you don't specify them. Based on the way you're building your Data, your code should look something like (some code omitted for brevity):

public class PerformanceAnalyzerController {

    @FXML private BarChart<String, Number> barChart;

    @FXML
    private void performAnalysisOperation(ActionEvent event) {
        //Performing analysis operation

        ObservableList<XYChart.Data<String, Number>> data = handler.getItemsGraphicsStatisitics();
        XYChart.Series<String, Number> series = new XYChart.Series<>("Series Name", data);

        barchart.getData().setAll(series);
        graphHandler.getChildren().add(barchart);
    }

}

And:

// Use generic types
public ObservableList<XYChart.Data<String, Number>> getItemGraphStatistics(){
    ObservableList<XYChart.Data<String, Number>> data = FXCollections.observableArrayList();

    String sql = "SELECT itemID, COUNT(*) FROM (SELECT itemID FROM SALES UNION ALL SELECT itemID FROM STOCK) t GROUP BY itemID";
    System.out.println(sql );
    ResultSet rs = handler.execQuery(sql);
    try{

        while(rs.next()){
            String item= rs.getString("itemID");
            int count = rs.getInt(2);

            // add diamond operator "<>"
            data.add(new XYChart.Data<>(item+ "(" + count + ")", count));

        }
    } catch (SQLException ex) {
        Logger.getLogger(DatabaseHandler.class.getName()).log(Level.SEVERE, null, ex);
    }
    return data;

}

Note: I replaced uses of BarChart.Data with XYChart.Data, but I don't believe it matters in this case.

Slaw
  • 37,820
  • 8
  • 53
  • 80