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が親である(または親から拡張された)かどうかはどのようにしてわかりますか?私はそうしていますか?動作していないようです...すべてのノードをルート(親)ノードから取得していますが、子を含むノードからは取得していません。これはおそらく答えがあると思いますが、質問をしています...間違っています。これを行うにはどうすればよいですか?
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);
}
}
私はこれを使います
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);
このソースコードは、既存のノードの参照を使用します。それらのクローンは作成しません。
これは私にとってはうまくいきます:
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;
}
}
これはすべてのノードを取得するようです。 (コトリン)
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
}
Hansの回答に追加します。親がSplitPane
かどうかを確認する必要があります。 SplitPane
sにはgetUnmodifiableChildren()
を使用した空のリストがあるため、代わりにgetItems()
を使用する必要があります。 (getUnmodifiableChildren()
を介して子を提供しない他の親がいるかどうかはわかりません。SplitPane
が最初に見つかった...)
残念ながら、これはほとんどのコンテナーコンポーネントのサブノードを取得しません。 TabPane
を親として試すと、子は見つかりませんが、getTabs()
を使用してタブを見つけることができます。同じことはSplitPane
やその他の場合にも当てはまります。したがって、すべてのコンテナには特定のアプローチが必要です。
node.lookupAll("*")
を使用することもできますが、内部を見ることもできません。
解決策は、「プロトタイプ」パターン-getChildren()
メソッドの共通インターフェースを持つメタクラスを作成することであり、サブクラスで実現されます-タイプごとに1つ。
アプローチ例を示します here 。