web-dev-qa-db-ja.com

JavaFXで親のすべてのノードを取得するにはどうすればよいですか?

C#で、指定されたコントロールからすべての子孫とすべての子孫を取得できる、かなり甘いメソッドを見つけました。

JavaFXに似たメソッドを探しています。

Parentクラスは、すべてのNodeクラスを持つ、子を持つクラスであるから派生したクラスであるため、私が扱いたいものであることがわかりました。

これは私がこれまで持ってきたものです(そして「JavaFXがシーンからすべてのノードを取得する」のような検索でGoogleで実際に何も見つけていません):

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

では、Nが親である(または親から拡張された)かどうかはどのようにしてわかりますか?私はそうしていますか?動作していないようです...すべてのノードをルート(親)ノードから取得していますが、子を含むノードからは取得していません。これはおそらく答えがあると思いますが、質問をしています...間違っています。これを行うにはどうすればよいですか?

12
Will
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);
    }
}
17
Hans Brende

私はこれを使います

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

使用法、

List<Node> nodes = NodeUtils.paneNodes(aVBoxOrAnotherContainer);

このソースコードは、既存のノードの参照を使用します。それらのクローンは作成しません。

1

これは私にとってはうまくいきます:

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

}
0

これはすべてのノードを取得するようです。 (コトリン)

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
}
0
Red wine

Hansの回答に追加します。親がSplitPaneかどうかを確認する必要があります。 SplitPanesにはgetUnmodifiableChildren()を使用した空のリストがあるため、代わりにgetItems()を使用する必要があります。 (getUnmodifiableChildren()を介して子を提供しない他の親がいるかどうかはわかりません。SplitPaneが最初に見つかった...)

0
Helkaruthion

残念ながら、これはほとんどのコンテナーコンポーネントのサブノードを取得しません。 TabPaneを親として試すと、子は見つかりませんが、getTabs()を使用してタブを見つけることができます。同じことはSplitPaneやその他の場合にも当てはまります。したがって、すべてのコンテナには特定のアプローチが必要です。

node.lookupAll("*")を使用することもできますが、内部を見ることもできません。

解決策は、「プロトタイプ」パターン-getChildren()メソッドの共通インターフェースを持つメタクラスを作成することであり、サブクラスで実現されます-タイプごとに1つ。

アプローチ例を示します here

0
Zon