In C# I found a method that was pretty sweet that allowed you to get all the descendants and all of THEIR descendants from a specified control.
I\'m looking for a si
This seems to get ALL nodes. (In Kotlin)
fun getAllNodes(root: Parent): ArrayList<Node> {
var nodes = ArrayList<Node>()
fun recurseNodes(node: Node) {
nodes.add(node)
if(node is Parent)
for(child in node.childrenUnmodifiable) {
recurseNodes(child)
}
}
recurseNodes(root)
return nodes
}
Unfortunately this won't get subnodes for most container components. If you try a TabPane
as parent, you'll find no children, but you can find tabs in it with getTabs()
. The same is with SplitPane
and other. So every container will require a specific approach.
You could use node.lookupAll("*")
, but it also doesn't look inside.
The solution could be a "Prototype" pattern - creating a meta class with common interface of getChildren()
method, which is realized in subclasses - one for each type.
Approach example is given here.
public static ArrayList<Node> getAllNodes(Parent root) {
ArrayList<Node> nodes = new ArrayList<Node>();
addAllDescendents(root, nodes);
return nodes;
}
private static void addAllDescendents(Parent parent, ArrayList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
nodes.add(node);
if (node instanceof Parent)
addAllDescendents((Parent)node, nodes);
}
}
I use this,
public class NodeUtils {
public static <T extends Pane> List<Node> paneNodes(T parent) {
return paneNodes(parent, new ArrayList<Node>());
}
private static <T extends Pane> List<Node> paneNodes(T parent, List<Node> nodes) {
for (Node node : parent.getChildren()) {
if (node instanceof Pane) {
paneNodes((Pane) node, nodes);
} else {
nodes.add(node);
}
}
return nodes;
}
}
Usage,
List<Node> nodes = NodeUtils.paneNodes(aVBoxOrAnotherContainer);
This source code uses the references of the existing nodes. It does not clone them.
This works for me:
public class FXUtil {
public static final List<Node> getAllChildren(final Parent parent) {
final List<Node> result = new LinkedList<>();
if (parent != null) {
final List<Node> childrenLvl1 = parent.getChildrenUnmodifiable();
result.addAll(childrenLvl1);
final List<Node> childrenLvl2 =
childrenLvl1.stream()
.filter(c -> c instanceof Parent)
.map(c -> (Parent) c)
.map(FXUtil::getAllChildren)
.flatMap(List::stream)
.collect(Collectors.toList());
result.addAll(childrenLvl2);
}
return result;
}
}
I'd like to add to Hans' answer, that you have to check if parent is a SplitPane
. Because SplitPane
s have an empty list using getUnmodifiableChildren()
, you'll have to use getItems()
instead. (I do not know if there are other parents that do not provide their children via getUnmodifiableChildren()
. SplitPane
was the first I found...)