如何在 JavaFX 中获取父节点中的所有节点?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24986776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 16:12:37  来源:igfitidea点击:

How do I get all nodes in a parent in JavaFX?

javarecursionjavafxjavafx-8

提问by Will

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.

在 C# 中,我发现了一种非常棒的方法,它允许您从指定的控件中获取所有后代和所有 THEIR 后代。

I'm looking for a similar method for JavaFX.

我正在为 JavaFX 寻找类似的方法。

I saw that the Parentclass is what I want to work with since it is the class from which all Node classes that bear children are derived.

我看到这个Parent类是我想要使用的类,因为它是所有带有子节点的 Node 类的派生类。

This is what I have so far (and I haven't really found anything on google with searches like "JavaFX get all nodes from a scene"):

这就是我到目前为止所拥有的(而且我还没有在谷歌上真正找到任何类似“JavaFX 从场景中获取所有节点”的搜索):

public static ArrayList<Node> GetAllNodes(Parent root){
    ArrayList<Node> Descendents = new ArrayList<>();
    root.getChildrenUnmodifiable().stream().forEach(N -> {
        if (!Descendents.contains(N)) Descendents.add(N);
        if (N.getClass() == Parent.class) Descendents.addAll(
            GetAllNodes((Parent)N)
        );
    });
}

So how do I tell if N is a parent (or extended from a parent)? Am I doing that right? It doesn't seem to be working... It's grabbing all the nodes from the root (parent) node but not from the nodes with children in them. I feel like this is something that's probably got an answer to it but I'm just asking the question... wrong. How do I go about doing this?

那么我如何判断 N 是否是父级(或从父级扩展而来)?我这样做对吗?它似乎没有工作......它从根(父)节点中获取所有节点,而不是从其中包含子节点的节点中获取。我觉得这可能是有答案的,但我只是在问这个问题……错了。我该怎么做?

采纳答案by Hans Brende

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);
    }
}

回答by Helkaruthion

I'd like to add to Hans' answer, that you have to check if parent is a SplitPane. Because SplitPanes 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(). SplitPanewas the first I found...)

我想补充一下 Hans 的回答,您必须检查 parent 是否为SplitPane. 因为SplitPanes 有一个使用 的空列表getUnmodifiableChildren(),所以您必须改为使用getItems()。(我不知道是否有其他父母不通过getUnmodifiableChildren().SplitPane是我发现的第一个......)

回答by Zon

Unfortunately this won't get subnodes for most container components. If you try a TabPaneas parent, you'll find no children, but you can find tabs in it with getTabs(). The same is with SplitPaneand other. So every container will require a specific approach.

不幸的是,对于大多数容器组件,这不会获得子节点。如果您尝试将 aTabPane作为父项,您将找不到子项,但您可以在其中找到带有getTabs(). 与SplitPane和其他相同。因此,每个容器都需要特定的方法。

You could use node.lookupAll("*"), but it also doesn't look inside.

您可以使用node.lookupAll("*"),但它也看不到内部。

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.

解决方案可能是“原型”模式——创建一个具有通用getChildren()方法接口的元类,它在子类中实现——每个类型一个。

Approach example is given here.

方法示例在此处给出。

回答by George Siggouroglou

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.

此源代码使用现有节点的引用。它不会克隆它们。

回答by Red wine

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
}

回答by Marcel Wieczorek

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;
    }

}