简体   繁体   English

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

[英]How do I get all nodes in a parent in JavaFX?

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#中,我找到了一个非常好的方法,它允许你从指定的控件中获取所有后代和所有的后代。

I'm looking for a similar method for JavaFX. 我正在为JavaFX寻找类似的方法。

I saw that the Parent class 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)? 那么如何判断N是父母(或从父母延伸)? 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? 我该怎么做呢?

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

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() . 如果您尝试使用TabPane作为父级,您将找不到子级,但您可以使用getTabs()在其中找到制表符。 The same is with SplitPane and other. SplitPane和其他相同。 So every container will require a specific approach. 所以每个容器都需要特定的方法。

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 . 这里给出方法示例。

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. 它没有克隆它们。

I'd like to add to Hans' answer, that you have to check if parent is a SplitPane . 我想补充Hans的答案,你必须检查父母是否是SplitPane Because SplitPane s have an empty list using getUnmodifiableChildren() , you'll have to use getItems() instead. 因为SplitPane使用getUnmodifiableChildren()有一个空列表,所以你必须使用getItems() (I do not know if there are other parents that do not provide their children via getUnmodifiableChildren() . SplitPane was the first I found...) (我不知道是否有不通过他们的子女提供其他家长getUnmodifiableChildren() SplitPane是第一次,我发现...)

This seems to get ALL nodes. 这似乎得到了所有节点。 (In Kotlin) (在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
}

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM