it-swarm.com.ru

Как получить все узлы сцены в JavaFX?

В C # я нашел довольно приятный метод, который позволил вам получить всех потомков и всех ИХ потомков из указанного элемента управления.

Я ищу аналогичный метод для JavaFX.

Я видел, что класс Parent - это то, с чем я хочу работать, так как это класс, из которого получены все классы Node, которые имеют дочерние классы.

Это то, что я до сих пор (и я действительно не нашел ничего в Google с поиском, как "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)
        );
    });
}

Итак, как мне узнать, является ли N родительским (или расширенным от родительского)? Я делаю это правильно? Кажется, он не работает ... Он захватывает все узлы из корневого (родительского) узла, но не из узлов с дочерними элементами в них. Я чувствую, что это то, на что, вероятно, есть ответ, но я просто задаю вопрос ... неправильно. Как мне это сделать?

9
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);
    }
}
15
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
George Siggouroglou

К сожалению, для большинства компонентов контейнера это не даст подузлов. Если вы попробуете TabPane в качестве родителя, вы не найдете дочерних элементов, но вы можете найти в нем вкладки с помощью getTabs(). То же самое с SplitPane и другим. Таким образом, каждый контейнер потребует особого подхода.

Вы можете использовать node.lookupAll("*"), но она также не заглядывает внутрь.

Решением может быть шаблон «Прототип» - создание мета-класса с общим интерфейсом метода getChildren(), который реализуется в подклассах - по одному для каждого типа.

Пример подхода приведен здесь .

1
Zon

Это работает для меня:

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
Marcel Wieczorek

Это, кажется, получить все узлы . (В 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
}
0
Red wine

Я хотел бы добавить к ответу Ганса, что вы должны проверить, является ли parent SplitPane. Поскольку у SplitPanes есть пустой список с использованием getUnmodifiableChildren(), вам придется использовать вместо него getItems(). (Я не знаю, есть ли другие родители, которые не предоставляют своих детей через getUnmodifiableChildren(). SplitPane был первым, кого я нашел ...)

0
Helkaruthion