Search code examples
javajavafxlabelmouseeventpie-chart

Why does JavaFX PieChart label not show after after adding Events to each pie slice? (Java 8)


I'm following this tutorial (the section at the bottom called "Processing Mouse Events for a Pie Chart"):

https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/pie-chart.htm

And my code is as follows:

@FXML
public void initialize() {
    pieChart.setTitle("Breakdown of Customers by City");
    pieChart.setLegendSide(Side.LEFT);

    final Task<ObservableList<PieChart.Data>> task = new NumClientsAtLocationTask(new CustomerAccountDaoSelect());
    new Thread(task).start();
    task.setOnSucceeded(ae -> {

        pieChart.setData(task.getValue());

        final Label caption = new Label("");
        caption.setTextFill(Color.DARKORANGE);
        caption.setStyle("-fx-font: 24 arial;");

        for (final PieChart.Data data : pieChart.getData()) {
            data.getNode().addEventHandler(MouseEvent.MOUSE_PRESSED,
                    ae2 -> {
                        caption.setTranslateX(ae2.getSceneX());
                        caption.setTranslateY(ae2.getSceneY());
                        caption.setText(String.valueOf(data.getPieValue()));
                    });
        }
    });

}


class NumClientsAtLocationTask extends Task<ObservableList<PieChart.Data>> {
    private DaoSelect<CustomerAccount> customerAccountDaoSelect;

    NumClientsAtLocationTask(DaoSelect<CustomerAccount> customerAccountDaoSelect) {
        this.customerAccountDaoSelect = customerAccountDaoSelect;
    }

    @Override
    protected ObservableList<PieChart.Data> call() throws Exception {
        List<CustomerAccount> customerAccounts = customerAccountDaoSelect.select(RunListeners.FALSE);

        Map<String, List<CustomerAccount>> customerMap =
                customerAccounts
                        .stream()
                        .collect(Collectors.groupingBy(CustomerAccount::getCity));

        int london = customerMap.get("London").size();
        int phoenix = customerMap.get("Phoenix").size();
        int newYork = customerMap.get("New York").size();

        ObservableList<PieChart.Data> results = FXCollections.observableArrayList(
                new PieChart.Data("London", london),
                new PieChart.Data("Phoenix", phoenix),
                new PieChart.Data("New York", newYork));

        updateValue(results);
        return results;
    }
}

The chart shows fine in its default form, but when I click the mouse on a slice, the label doesn't appear. If I print the label to console, it shows the correct value, it's just not showing up on screen like in the tutorial. Any ideas?


Solution

  • The example/tutorial is pretty poor and omits an important detail. You need to add the Label 'caption' to the Scene first.

    If you were purely using the example code in that tutorial you'd include ((Group) scene.getRoot()).getChildren().add(caption);:

    final Label caption = new Label("");
    ((Group) scene.getRoot()).getChildren().add(caption); // Add me
    caption.setTextFill(Color.DARKORANGE);
    caption.setStyle("-fx-font: 24 arial;");
    
    for (final PieChart.Data data : chart.getData()) {
        data.getNode().addEventHandler(MouseEvent.MOUSE_PRESSED,
                new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent e) {
                        caption.setTranslateX(e.getSceneX());
                        caption.setTranslateY(e.getSceneY());
                        caption.setText(String.valueOf(data.getPieValue()) + "%");
                    }
                });
    }