Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get node bounds according to its specific ancestor in JavaFX 8?

Tags:

java

javafx

I have added a chart in AnchorPane, and I want to get the bounds of its plot (chart-plot, I have marked it with cyan color), so that I could add some texts on top of it, but I should know its exact bounds according to its ancestor(s). If I do it manually, I may fail when the paddings' size of the nodes will be changed when resizing etc.

import javafx.application.Application;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        NumberAxis numberAxis = new NumberAxis();
        LineChart chart = new LineChart(numberAxis, new NumberAxis());
        chart.getYAxis().setSide(Side.RIGHT);
        Node chartPlotArea = chart.lookup(".chart-plot-background");
        chartPlotArea.setStyle("-fx-background-color: cyan");
        AnchorPane anchorPane = new AnchorPane(chart);
        AnchorPane.setTopAnchor(chart, 0.0);
        AnchorPane.setRightAnchor(chart, 0.0);
        AnchorPane.setBottomAnchor(chart, 0.0);
        AnchorPane.setLeftAnchor(chart, 0.0);

        Scene scene = new Scene(anchorPane);
        primaryStage.setScene(scene);
        primaryStage.setMaximized(true);
        primaryStage.show();
    }
}

enter image description here

So the question is how to get bounds of a node or chart-plot in my case according to its ancestor no matter how many are there?

like image 896
Velaniv Jr Avatar asked Oct 18 '18 09:10

Velaniv Jr


People also ask

Can a node be placed in a scene JavaFX?

Each JavaFX Node (subclass) instance can only be added to the JavaFX scene graph once. In other words, each Node instance can only appear in one place in the scene graph. If you try to add the same Node instance, or Node subclass instance, to the scene graph more than once, JavaFX will throw an exception!

What does getChildren return in JavaFX?

getChildren. Gets the list of children of this Parent .

What is an AnchorPane in JavaFX?

AnchorPane class is a part of JavaFX. AnchorPane allows the edges of child nodes to be anchored to an offset from the anchor pane's edges. If the anchor pane has a border and/or padding set, the offsets will be measured from the inside edge of those insets. AnchorPane inherits Pane class.

Is ImageView a leaf node?

Leaf nodes are classes such as Rectangle , Text , ImageView , MediaView , or other such leaf classes which cannot have children. Only a single node within each scene graph tree will have no parent, which is referred to as the "root" node.


1 Answers

You already found Chart-Plot background node, and to get it coordinates according to its ancestor you need to simply call

chartPlotArea.getBoundsInParent();

and if there is more than one ancestor between them you can get char-plot bounds in AnchorPane coordinates system like this

Bounds bounds =
            anchorPane.sceneToLocal(chartPlotArea.localToScene(chartPlotArea.getBoundsInLocal()));

A little trick here, is that they will be 0s until you show stage and let javaFX layout nodes, so you need to update it afte .show() method, so result may look like this:

 NumberAxis numberAxis = new NumberAxis();
    LineChart chart = new LineChart(numberAxis, new NumberAxis());
    chart.getYAxis().setSide(Side.RIGHT);
    Node chartPlotArea = chart.lookup(".chart-plot-background");
    chartPlotArea.setStyle("-fx-background-color: cyan");

    Text text = new Text();
    text.setText("Text");


    AnchorPane anchorPane = new AnchorPane();
    AnchorPane.setTopAnchor(chart, 0.0);
    AnchorPane.setRightAnchor(chart, 0.0);
    AnchorPane.setBottomAnchor(chart, 0.0);
    AnchorPane.setLeftAnchor(chart, 0.0);


    anchorPane.getChildren().addAll(chart, text);

    Scene scene = new Scene(anchorPane);
    primaryStage.setScene(scene);
    primaryStage.setMaximized(true);


    primaryStage.show();

        Bounds bounds =
            anchorPane.sceneToLocal(chartPlotArea.localToScene(chartPlotArea.getBoundsInLocal()));

    double textRelativeX = (bounds.getMinX() + bounds.getMaxX()) / 2 - text.getLayoutBounds().getWidth() / 2;
    double textRelativeY = bounds.getMinY() - text.getLayoutBounds().getHeight() / 2;

    AnchorPane.setLeftAnchor(text, textRelativeX);
    AnchorPane.setTopAnchor(text, textRelativeY);

And remember, that if you want coordinates change when resizing you can bind this to chart or chartPlotArea bound/width changes, something like this

  chart.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
        double textRelativeXz = (newValue.getMinX() + newValue.getMaxX()) / 2 - text.getLayoutBounds().getWidth() / 2;
        double textRelativeYz = newValue.getMinY() - text.getLayoutBounds().getHeight() / 3;

        AnchorPane.setLeftAnchor(text, textRelativeXz);
        AnchorPane.setTopAnchor(text, textRelativeYz);
    });

EDIT: if you have more than one ancestor you can do like this to receive char-plot bounds in anchorPane coordinate system

     Bounds bounds =
            anchorPane.sceneToLocal(chartPlotArea.localToScene(chartPlotArea.getBoundsInLocal()));   

this will work even if there more than one ancestor between them

like image 79
Alex G. Avatar answered Oct 22 '22 23:10

Alex G.