Search code examples
javafx-8coordinatesrectanglesgridpane

How to get screen/scene center x,y of Rectangle within a GridPane?


I'm working on a simple board game implementation in JavaFX8.

For the game board, my decision was to use a 10x10 GridPane and fill it's cells with Rectangles in form's initialize method.

private void drawBoard() {
    gridpaneBoard.getChildren().clear();
    for (int y = 0; y < gridpaneBoard.getRowConstraints().size(); y++)
        for (int x = 0; x < gridpaneBoard.getColumnConstraints().size(); x++) {
            Rectangle rect = new Rectangle(55,55);
            rect.setStroke(Color.BLACK);

            Tile tile = GameController.getInstance().getBoard().getTile(x, y);
            if (tile.hasBranch())
                rect.setFill(QuestionDifficulty.values()[tile.getBranch()
                                                         .getQuestion().getQuestion()
                                                         .getLevel()].getColor());
            else
                rect.setFill(Color.WHITE);

            gridpaneBoard.add(rect, x, y);
            gridpaneBoard.add(new Label(String.valueOf(tile.getNumber())), x, y);
        }
}

In order to animate player token movement after dice rolls, I figured I need to know the center x & center y of each tile (to create a path transition from source tile to destination tile).

I've tried all sorts of answers given to other people's questions, but everything returned 0,0 for me.

This is the container hierarchy in this scene:

container hierarchy

This is how the output looks at the moment:

enter image description here

If GridPane is fine for what I'm trying to achieve, how can I get a child's (in this case a rectangle's) screen / scene center x,y?

If GridPane is not fine, can you point me to alternatives and how I can achieve what I want then..

Thank you!


Solution

  • You can simply call getBoundsInParent to get the dimensions of the Node in it's parent.

    The following example is a bit simplified, but it should demonstrate the approach nonetheless:

    @Override
    public void start(Stage primaryStage) {
        GridPane gridpaneBoard = new GridPane();
        for (int y = 0; y < 10; y++) {
            for (int x = 0; x < 10; x++) {
                Rectangle rect = new Rectangle(55, 55);
                rect.setStroke(Color.BLACK);
    
                rect.setFill((x + y) % 2 == 0 ? Color.WHITE : Color.DARKGRAY);
    
                gridpaneBoard.add(rect, x, y);
            }
        }
    
        gridpaneBoard.setOnMouseClicked(evt -> {
            Node target = evt.getPickResult().getIntersectedNode();
    
            if (target != gridpaneBoard) {
                // in your case you'd need to make sure this is not the Label
                Bounds bounds = target.getBoundsInParent();
                System.out.println("bounds = " +bounds);
                System.out.println("centerX = " +(bounds.getMinX() + bounds.getWidth()/2));
                System.out.println("centerY = " +(bounds.getMinY() + bounds.getHeight()/2));
            }
        });
    
        Scene scene = new Scene(gridpaneBoard);
    
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    

    If coordinates different to the GridPane coordinates are required, you could use getBoundsInLocal in combination with localTo... instead:

    Bounds bounds = target.localToScene(target.getBoundsInLocal());
    

    for scene bounds or

    Bounds bounds = target.localToScreen(target.getBoundsInLocal());
    

    for screen bounds.

    Note: This works independent from any properties modifying how GridPane layouts it's children.