Search code examples
javajavafxmouseeventpie-chart

PieChart (JavaFx) didn't display my Label on Event - JavaFx


I try to create a label on click for my PieChart, but unfortunately my label is never visible.

I found a similar topic on StackOverFlow : Label not showing on mouse event JavaFx But my application is not as simple. I can't add my Label to the list of children because of my architecture.

(You can found a diagram here : https://i.sstatic.net/ZFJaR.png )

Here my code :

PieChartNode.java

    package nodeStatsVision.chartFactory;

    import java.util.ArrayList;
    import javafx.application.Platform;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.EventHandler;
    import javafx.scene.Node;
    import javafx.scene.chart.PieChart;
    import javafx.scene.control.Label;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.paint.Color;
    import nodeStatsVision.beans.ListRepere;
    import nodeStatsVision.beans.OptionsChart;
    import nodeStatsVision.beans.ValueStat;

    /**
     *
     * @author Zombkey.
     */
    public class PieChartNode implements ChartNode {

    private ListRepere categories;
    private ArrayList<ValueStat> values;

    private ObservableList<PieChart.Data> pieChartData; 
    private Node node;

    public PieChartNode(ListRepere categories, ArrayList<ValueStat> values){
            this.categories = categories;
            this.values = values;

            pieChartData = FXCollections.observableArrayList();
            node = new PieChart(pieChartData);

            Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                            formatData();
                    }
            });
    }

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

            for(ValueStat v : values){
                    PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(),v.getDoubleValue());
                    pieChartData.add(dataTemp);

                    dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_CLICKED,
                    new EventHandler<MouseEvent>() {
                            @Override public void handle(MouseEvent e) {
                                    System.out.println("event : "+v.getCategorie().getStringName()+" : "+v.getDoubleValue());

                                    caption.setTranslateX(e.getSceneX());
                                    caption.setTranslateY(e.getSceneY());
                                    caption.setText(String.valueOf(dataTemp.getPieValue()));
                                    caption.setVisible(true);
                                    System.out.println("label "+caption);
                            }
                    });
            }
    }

    @Override
    public Node getNodeGraph() {
            return node;
    }

    @Override
    public void setOptions(OptionsChart optionsChart) {
            //To implemente
    }

    }

Have you a idea about, how add my Label to the scene ?

Thanks !

(Other question, Why the Node of PieChart.Data is on ReadOnly ?)

Zombkey.

PS : Sorry about my english, I'm a French student, I'm still learning :) Ps 2 : First time on StackOverflow, if I did mistake, tell me it !


Solution

  • Ok ! I found a solution for my case !

    Semantically my Label is only for my PieChart. That's why I don't want had it to my SceneGraph. My ChartFactory return a Node, then display it. So my node have to contain the PieChart AND the Label.

    I create a Group with a StackPane. In the StackPane I add my PieChart and my Label. Then my factory return the Group as a Node.

    Drop the code !

        package nodeStatsVision.chartFactory;
    
        import java.util.ArrayList;
        import javafx.application.Platform;
        import javafx.collections.FXCollections;
        import javafx.collections.ObservableList;
        import javafx.event.EventHandler;
        import javafx.scene.Group;
        import javafx.scene.Node;
        import javafx.scene.Parent;
        import javafx.scene.chart.PieChart;
        import javafx.scene.control.Label;
        import javafx.scene.input.MouseEvent;
        import javafx.scene.layout.StackPane;
        import javafx.scene.paint.Color;
        import nodeStatsVision.beans.ListRepere;
        import nodeStatsVision.beans.OptionsChart;
        import nodeStatsVision.beans.ValueStat;
    
        /**
         *
         * @author Zombkey.
         */
        public class PieChartNode implements ChartNode {
    
        private ListRepere categories;
        private ArrayList<ValueStat> values;
    
        private ObservableList<PieChart.Data> pieChartData; 
        private Group group;
        private Node node;
        private final Label caption;
    
        public PieChartNode(ListRepere categories, ArrayList<ValueStat> values){
                this.categories = categories;
                this.values = values;
    
                group = new Group();
                StackPane pane = new StackPane();
                group.getChildren().add(pane);
    
                pieChartData = FXCollections.observableArrayList();
                node = new PieChart(pieChartData);
                pane.getChildren().add(node);
    
                caption = new Label("");
                caption.setVisible(false);
                caption.getStyleClass().addAll("chart-line-symbol", "chart-series-line");
                caption.setStyle("-fx-font-size: 12; -fx-font-weight: bold;");
                caption.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
                pane.getChildren().add(caption);
    
                Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                                formatData();
                        }
                });
        }
    
        private void formatData() {
    
                for(ValueStat v : values){
                        PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(),v.getDoubleValue());
                        pieChartData.add(dataTemp);
    
                        dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED,
                        new EventHandler<MouseEvent>() {
                                @Override public void handle(MouseEvent e) {
                                        caption.setTranslateX(e.getX());
                                        caption.setTranslateY(e.getY());
                                        caption.setText(String.valueOf(dataTemp.getPieValue()));
                                        caption.setVisible(true);
                                }
                        });
                        dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_EXITED,
                        new EventHandler<MouseEvent>() {
                                @Override public void handle(MouseEvent e) {
                                        caption.setVisible(false);
                                }
                        });
                }
        }
    
        @Override
        public Node getNodeGraph() {
                return (Node)group;
        }
    
        @Override
        public void setOptions(OptionsChart optionsChart) {
                //To implemente
        }
    
        }
    

    Thanks @eckig for your answers !