17

I want to retrieve the content of one specific cell in a Gridpane. I have put buttons in the cells with the

setConstraints(btt , 0 ,1 ) 

setConstraints(btt , 0 ,2 )

getChildren().add....

In my case the GridPane.getChildren.get(10) is not good. I want to go directly to the cell(4,2) and get its content.

Frederic
  • 2,015
  • 4
  • 20
  • 37
Elias Elias
  • 419
  • 3
  • 6
  • 10

5 Answers5

31

Well I guess if there is no solution to get a specific node from gridpane by is column and row index, I have a function to do that,

private Node getNodeFromGridPane(GridPane gridPane, int col, int row) {
    for (Node node : gridPane.getChildren()) {
        if (GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) {
            return node;
        }
    }
    return null;
}
Shreyas Dave
  • 3,815
  • 3
  • 28
  • 57
  • 5
    It's extremely weird that after all those years java doesn't provide basic functionality and you have to use these kind of inefficiënt workarounds to make basic stuff work. But I guess it's the underlying datastructure that's at the base. – th3penguinwhisperer Apr 07 '18 at 09:02
  • Make sure your constraints are set. Scenebuilder likes to treat 0 as not set and nulls the field. So manually set the constraints in the fxml file. e.g . Also since it's not guaranteed to return a non-null value from getRowIndex/getColumnIndex you should use an Integer object and check for null in the if statement. e.g. if(null != nodeRow && null != nodeCol ... – Olmstov Dec 10 '18 at 20:28
  • Can you please tell me how to implement this for a `label` ? – Mayur Patel Aug 26 '19 at 11:14
9

Assuming you have an 8x8 girdPane where i is the rows and j is the column, you can write:

myGridPane.getChildren().get(i*8+j)

The return type is an object, so you will have to cast it, in my case it's:

(StackPane) (myGridPane.getChildren().get(i*8+j))

Ahmad Tn
  • 360
  • 3
  • 16
  • 3
    This may be true in some cases but children list isn't necessarily maintained in order of row/column and may be altered later with GridPane.setRowIndex() etc... – Adam Jul 19 '17 at 11:34
  • I never used setRowIndex() so I can't say much. This solution worked for me and I believe should get the job done most of the times, when you don't alter the default row/column indexes. – Ahmad Tn Jul 23 '17 at 09:14
  • What happens if there is not a node inside the specific cell in the first place? – ihavenoidea May 22 '18 at 00:09
  • @leandrocoutom I'm not sure what happens. I'm not working with javafx nowadays so I can't really tell. But it answers the question to retrieve **content** from the cell. If you try it out yourself, I'd like to know what happens. Thanks – Ahmad Tn May 23 '18 at 11:09
3

I had some trouble with the presented solution in this question, because the method GridPane.getColumnIndex(Node node) might return null in the first row or colum (when the index is actually 0). Therefore I worked around with the wrapperclass Integer and came to the following solution. Maybe it will help others with the same problem.

private Node getNodeFromGridPane(GridPane gridPane, int col, int row) {
    ObservableList<Node> children = gridPane.getChildren();
    for (Node node : children) {
        Integer columnIndex = GridPane.getColumnIndex(node);
        Integer rowIndex = GridPane.getRowIndex(node);

        if (columnIndex == null)
            columnIndex = 0;
        if (rowIndex == null)
            rowIndex = 0;

        if (columnIndex == col && rowIndex == row) {
            return node;
        }
    }
    return null;
}
F.M.
  • 31
  • 4
2

You can add a list that contains every child of the gridpane and each child's parent must have two integers row and column, therefor you'll just have to go through that list and see if it has the right coordinates ! (You should propably add a new class so you can store those coordinates), here is a minimal example of my solution

import java.util.ArrayList;
import java.util.List;

import javafx.scene.Node;
import javafx.scene.layout.GridPane;

public class SpecialGridPane extends GridPane {
    List<NodeParent> list = new ArrayList<>();

    public void addChild(int row, int column, Node node) {
        list.add(new NodeParent(row, column, node));
        setConstraints(node, column, row);
        getChildren().add(node);
    }

    public Node getChild(int row, int column) {
        for (NodeParent node : list) {
            if (node.getRow() == row && node.getColumn() == column)
                return node.getNode();
        }
        return null;
    }
}

class NodeParent {
    private int row;
    private int column;
    private Node node;

    public NodeParent(int row, int column, Node node) {
        this.row = row;
        this.column = column;
        this.node = node;
    }

    public int getRow() {
        return row;
    }

    public int getColumn() {
        return column;
    }

    public Node getNode() {
        return node;
    }
}
BHA Bilel
  • 331
  • 5
  • 14
1

As said in a duplicate, you may have performance issues with the selected answer (getNodeFromGridPane)

Here would be the way to overcome that : https://stackoverflow.com/a/65386693/11284920 But, to sum it up :

1. have a double dimensional array :

private Node[][] gridPaneArray = null;

2. Call a method like so during the initialization of your view :

    private void initializeGridPaneArray()
    {
       this.gridPaneArray = new Node[this.gridModel.getLines() [this.gridModel.getColumns()];
       for(Node node : this.mainPane.getChildren())
       {
          this.gridPaneArray[GridPane.getRowIndex(node)][GridPane.getColumnIndex(node)] = node;
       }
    }

3. Get your node

Node n = this.gridPaneArray[x][y]; // and cast it to any type you want/need
Dorian Naaji
  • 116
  • 1
  • 6