There are two main situations you might want to get the identity of a node in a procedurally-generated grid.
- Your user clicks on something in your grid, or the grid itself.
- Your user specifies where in the grid they’re looking (maybe they input coordinates) and you need to find the node they want.
A Node can be retrieved from a GridPane based on its row and column coordinates by manual iteration, invoking getColumnIndex() and getRowIndex() on each node to retrieve its position. A more performance-friendly solution is to maintain an index of node positions against which coordinates are checked.
With small grids, manually iterating through the nodes is convenient and can be efficient enough that users don’t notice. With larger grids containing thousands of nodes, hashing can significantly improve application performance.
What you’ll get from this article
Interacting with nodes in a grid layout involves either accessing objects from their coordinates, or retrieving the coordinates themselves from the objects.
Both require different solutions, so I’ll work through them one at a time. In the second case, I’ll look at various solutions that depend on how performance-intensive your application might be.
How to get the position of a node in a Gridpane
The row and column positions of a node in a GridPane layout can be retrieved by invoking the GridPane static methods getColumnIndex()
and getRowIndex()
, passing in the node you want to query. Where the row or column have not been set, these methods will return a null value.
int row = GridPane.getRowIndex(node); int column = GridPane.getColumnIndex(node);
Warning: This isn’t necessarily common knowledge, but if you haven’t manually set the row and column, the static methods getColumnIndex()
and getRowIndex()
will return null, which is why I use the primitive int type here rather than Integer
.
The GridPane
layout will interpret a null value as being in the first (zero-indexed) row and column, which is how it’s supposed to work. That’s also how the functions above will interpret the result.
If you’re starting this search as a result of a node being clicked, and you haven’t set custom handlers for each object (sometimes this is more concise), you can access the node by invoking getTarget() on the Event and casting it to a Node.
EventHandler<ActionEvent> buttonEventHandler(){ return event -> { Node node = (Node) event.getTarget(); int row = GridPane.getRowIndex(node); int column = GridPane.getColumnIndex(node); }; }
How to get a Node from a GridPane using its row and column coordinates
If you have situation where your user (or code) specifies the coordinates, you may need to retrieve the node that is located at those coordinates. You can do this by performing a brute force search on the nodes, or by maintaining an index.
The complexity of your application will probably determine whether indexing is necessary. In fact, I’d say if you have a grid that’s smaller than 50 x 50, users with even a slow computer won’t notice the difference. Nonetheless, I’ll go through how I would do both.
1. Brute Force Search
The simplest way to search through a grid of nodes is to manually iterate over that grid. For each node, checking whether it has the coordinates you’re looking for, and returning a node if found.

Node getNodeByCoordinate(Integer row, Integer column) { for (Node node : gridLayout.getChildren()) { if(GridPane.getColumnIndex(node) == row && GridPane.getColumnIndex(node) == column){ return node; } } return null; }
Note: I’ve used Integer
rather than int here. If a coordinate hasn’t been set, the GridPane’s static getter method will return null. Obviously, it is probably more performance-friendly to not set row and column indices to zero, because that’s the default. In these cases, you would want to be able to search for null values.
Obviously there’s a basic assumption that all of your nodes have different coordinates. If not, gather matching nodes in a list, and return the list rather than returning the first object.
List<Node> getNodesByCoordinate(Integer row, Integer column) { List<Node> matchingNodes = new ArrayList<>(); for (Node node : gridLayout.getChildren()) { if(GridPane.getColumnIndex(node) == row && GridPane.getColumnIndex(node) == column){ matchingNodes.add(node); } } return matchingNodes; }
Now rather than returning null, if you don’t find anything you’ll just get an empty list.
Depending on how many objects you have, this search might take more time than you’re willing to make your user wait. If that’s the case, you might want to consider indexing your nodes so you can search them more thoroughly.
That sounds scary, I know. But there’s no magic sauce behind indexing. All indexing does is replace a bloaty search through Node
objects with something that the compiler is much more optimised for. In this case, I’ll would suggest replacing it with a search through integers.
2. Fetching nodes efficiently using hashing
If you have a densely-populated, larger GridPane
, and I’m talking thousands of nodes, it can be challenging to search through all of those nodes quickly. Especially if you’re doing it frequently.
Of course, if you have a sparsely-populated large grid, brute-forcing the search may be manageable for the user’s CPU. It just depends on the total number of nodes you’re iterating over.
If you do have a lot of nodes, I’d recommend hashing their coordinates, and storing them in a Map
. This enables you to efficiently retrieve a node without iterating through the bloated Node
objects themselves.

If you’re not familiar with hashing, the idea is that you distil complex information – like coordinates – into a single number. Obviously, the way you produce your hash should be:
- Complicated enough that you won’t get two hashes from the same coordinates (that would defeat the point), but
- Simple enough to minimise the amount of calculation you need to do upfront
To completely avoid duplicate coordinates, these are the hash calculations I would recommend for grids of various sizes:
Grid Size | Hash Formula |
---|---|
10 x 10 | 7 * row + 11 * column |
100 x 100 | 103 * row + 97 * column |
1000 x 1000(a) | 1001 * row + 997 * column |
You can store this information yourself, or you can extend the GridPane
object and implement your own getNode(int x, int y)
function. Either way, as you set the coordinates of the node, you will want to store the hash in a map:
for (int i = 0; i < 999; i++) { for (int j = 0; j < 999; j++) { Node gridNode = new Rectangle(5, 5); GridPane.setConstraints(gridNode, i, j); coordinateLookUp.put(i * rMultiplier + j * cMultiplier, gridNode); } }
This is basically a very simple index. Now, instead of searching through node objects, Java will search through integers (and in a map, rather than a list) which is much more efficient.
To look up a node in this grid, you just need to query the map.
private Node getNodeByCoordinate(int row, int column){ return coordinateLookUp.get(row * rMult + column * cMult); }
If you have a sparsely-populated grid, and you don’t know whether there will be a node at that location, feel free to add in a null-check in your own implementation.
Conclusions
Navigating a grid layout can be much simpler than it seems. Both from the perspective of retrieving coordinates from nodes, and the other way around.
To retrieve the coordinates from a node, you just need to invoke the GridPane static methods getColumnIndex()
and getRowIndex()
. Just be aware that in cases where the row or column hasn’t been set, these methods will return null.
When calculating the layout, a GridPane assumes null indicates a zero: that is, the first row or column. But, it’s important to understand so you can search for null, if you need to.
The majority of the time, when you need to find a node by its coordinates, the simplest and most convenient solution is to iterate through the nodes and check whether their coordinate matches the one you’re looking for. That being said, for large, heavily-populated grids, this can lead to your use interface hanging, frustrating users.
In those (generally few) situations, I’d suggest hashing your nodes’ coordinates to improve the speed of searching.