How do I get node boundaries based on a specific ancestor in JavaFX 8?
I added a chart in anchorpane. I want to get the boundary of its chart (chart chart, I mark it with cyan), so that I can add some text on it, but I should know its exact boundary according to its ancestor If I do it manually, I may fail to change the fill size of the node 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(); } }
So the question is how to get the boundaries of nodes or charts according to its ancestors in my case, no matter how many?
Solution
You have found the chart plot background node and simply call it to get the coordinates according to its ancestors' needs
chartPlotArea.getBoundsInParent();
If there are multiple ancestors between them, you can get the char plot boundary in a coordinate system such as anchorpane
Bounds bounds = anchorPane.sceneToLocal(chartPlotArea.localToScene(chartPlotArea.getBoundsInLocal()));
A trick here is that they will be 0 until you display the stage and let JavaFX layout the nodes, so you need to The show () method is updated after it, so the results may be as follows:
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);
Remember, if you want to change the coordinates when resizing, you can bind them to the chart or chartplotarea binding / width change, such things
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 this to receive the char plot boundary in the anchor pane coordinate system
Bounds bounds = anchorPane.sceneToLocal(chartPlotArea.localToScene(chartPlotArea.getBoundsInLocal()));
This works even if there are multiple ancestors between them