I'm working on a JavaFX program that can display different grocery items as a BarChart. My code structure uses an initial loading class, GroceryGrapher.java, a controller, GroceryGrapherController.java, and an .fxml file, GroceryGrapher.fxml.
I'm relatively new to JavaFX and I've tried different approaches to creating and displaying my BarChart
. For the most part I've resolved issues and can load the chart with its data and components, but my issue is that the chart won't display / update after the program has started. The BarChart
is part of an AnchorPane
(which all comes under a StackPane
) in my FXML file, and I've tried to update it after initialization since it starts out blank but it remains blank.
The BarChart
is part of the AnchorPane
, which also has a MenuBar
. My goal was to be able to update different parts of the BarChart
via the MenuBar
. When I load the program, the MenuBar
and empty BarChart
are loaded:
This is how I initialize my BarChart
and its data:
public class GroceryGrapherController implements Initializable {
@FXML
private AnchorPane anchorPane = new AnchorPane();
@FXML
private NumberAxis xAxis = new NumberAxis();
@FXML
private CategoryAxis yAxis = new CategoryAxis();
@FXML
private BarChart<Number, String> groceryBarChart;
@FXML
//private Stage stage;
Parent root;
@Override
public void initialize(URL location, ResourceBundle resources) {
groceryBarChart = new BarChart<Number, String>(xAxis, yAxis);
groceryBarChart.setTitle("Horizontal Grocery List");
xAxis.setLabel("Number");
xAxis.setTickLabelRotation(90);
yAxis.setLabel("Grocery Type");
// Populate BarChart
XYChart.Series<Number, String> series1 = new XYChart.Series<>();
series1.setName("Chocolates");
series1.getData().add(new XYChart.Data<Number, String>(25601.34, "Reese"));
series1.getData().add(new XYChart.Data<Number, String>(20148.82, "Cadbury"));
series1.getData().add(new XYChart.Data<Number, String>(10000, "Mars"));
series1.getData().add(new XYChart.Data<Number, String>(35407.15, "Snickers"));
series1.getData().add(new XYChart.Data<Number, String>(12000, "Lindt"));
XYChart.Series<Number, String> series2 = new XYChart.Series<>();
series2.setName("Vegetables");
series2.getData().add(new XYChart.Data<Number, String>(57401.85, "Cabbage"));
series2.getData().add(new XYChart.Data<Number, String>(41941.19, "Lettuce"));
series2.getData().add(new XYChart.Data<Number, String>(45263.37, "Tomato"));
series2.getData().add(new XYChart.Data<Number, String>(117320.16, "Eggplant"));
series2.getData().add(new XYChart.Data<Number, String>(14845.27, "Beetroot"));
XYChart.Series<Number, String> series3 = new XYChart.Series<>();
series3.setName("Drinks");
series3.getData().add(new XYChart.Data<Number, String>(45000.65, "Water"));
series3.getData().add(new XYChart.Data<Number, String>(44835.76, "Coke"));
series3.getData().add(new XYChart.Data<Number, String>(18722.18, "Sprite"));
series3.getData().add(new XYChart.Data<Number, String>(17557.31, "Mountain Dew"));
series3.getData().add(new XYChart.Data<Number, String>(92633.68, "Beer"));
// Need to do this because of a bug with CategoryAxis... manually set categories
yAxis.setCategories(FXCollections.observableArrayList("Reese", "Cadbury", "Mars", "Snickers", "Lindt", "Cabbage", "Lettuce",
"Tomato", "Eggplant", "Beetroot", "Water", "Coke", "Sprite", "Mountain Dew", "Beer"));
groceryBarChart.getData().addAll(series1, series2, series3);
}
Now, I have an item:
In my MenuBar
to load the BarChart
(since it initially appears empty), which utilizes the a method I created, loadGraph
. I've tried different methods to get my updated BarChart
to show up with no major success. My initial idea was to use setScene
in the loadGraph
method to set the scene to the BarChart
, as shown in this example.
Stage stage = (Stage) anchorPane.getScene().getWindow();
stage.setScene(new Scene(groceryBarChart, 800, 600));
While that did work, it naturally replaced the scene to solely consist of the BarChart
, removing my MenuBar
and previous GUI:
I saw this question which had a similar issue (I think) but I wasn't really sure how to apply it to my program. I got this code:
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("GroceryGrapher.fxml"));
root = (Parent) fxmlLoader.load();
GroceryGrapherController ggController = fxmlLoader.getController();
} catch (Exception e) {
e.printStackTrace();
}
I copied over my initialization from the initialize
method to a new method and tried calling it with ggController
but it didn't change anything. I also tried creating a new method, updateData
:
@FXML
private void updateData() {
Platform.runLater(() -> {
groceryBarChart.setTitle("Horizontal Grocery List");
});
}
I tried calling it with ggController
in the loadGraph
method but my BarChart
still didn't change.
I know I'm doing something wrong, but I'm not very familiar with the BarChart
class and JavaFX in too much depth, so I figured I would come here to ask for help. I need to update the existing BarChart
in my GUI so that my data can load without replacing the entire scene, in order for the MenuBar
to remain visible in the scene able to perform functions. How would I go about altering the BarChart
component part of my AnchorPane
, updating the data as necessary, without completely replacing the scene as I did previously?
Thank you very much and sorry if this question is bad or my coding practices are wrong. All feedback would be much appreciated!
EDIT Just in case it might help, here is my FXML code for the BarChart.
<BarChart fx:id="groceryBarChart" layoutY="31.0" prefHeight="566.0" prefWidth="802.0">
<xAxis>
<CategoryAxis fx:id="yAxis" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" fx:id="xAxis" />
</yAxis>
</BarChart>