4

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.stack.imgur.com/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 !

Community
  • 1
  • 1
Zombkey
  • 335
  • 2
  • 14

3 Answers3

4

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 !

Zombkey
  • 335
  • 2
  • 14
2

You could use Tooltip to display a value:

for (final PieChart.Data temp : pieChart.getData()) {
    Tooltip tooltip = new Tooltip(String.valueOf(temp.getPieValue()));
    Tooltip.install(temp.getNode(), tooltip);
}
Ugnius Malūkas
  • 2,649
  • 7
  • 29
  • 42
droppy
  • 21
  • 3
1

You create and style your Label named caption but never add it to the SceneGraph.

Somewhere it has to be added to a Parent element, otherwise it will not get displayed.

Your PieChart gets added to a parent element, otherwise it will not be displayed. The same way goes for all other JavaFX Nodes.


As to your second question, read the JavaDocs:

Readonly access to the node that represents the pie slice. You can use this to add mouse event listeners etc.

eckig
  • 10,964
  • 4
  • 38
  • 52
  • Thanks for answer ! For a XYChart (like AreaChart), I used this example : http://stackoverflow.com/questions/14615590/javafx-linechart-hover-values (Jewelsea's answer). That's work well, because I can do a `setNode(popup)`. With a PieChart I can't, I have to add to the scene my "popup". But with my architecture ( http://i.stack.imgur.com/ZFJaR.png ), I can't had it to the scene... Because of my factory... Is it a other solution ? (like add the `Label` to Node Graph ?) – Zombkey Apr 15 '15 at 13:37
  • 1
    Well, we can not (and SO is not the right place for that) write the code for you. I pointed you in the right direction: You will have to create a mechanism to add these custom `Label`s into the SceneGraph ;-) – eckig Apr 15 '15 at 19:40