Использование ReactFX для изменения размера стадии, когда узлы становятся невидимыми?

У меня есть панель управления JavaFX, которая скрывает и показывает компоненты, основанные на сложных контекстах, поэтому ReactFX - отличная утилита для этого.

Я создал несколько вложенных замыканий, просматривая каждый узел, создавая EventStream от каждогоvisibleProperty()и затем подписать операцию для переключения managedProperty() и позвонить sizeToScene(), Хотя мое решение работает, оно не очень чистое. Я чувствую, что должен использовать плоскую карту или что-то в этом роде. Есть ли более чисто реактивный способ реализовать это?

    gridPane.getChildren().stream().forEach(c -> {
         EventStreams.changesOf(c.visibleProperty()).subscribe(b -> {
             c.managedProperty().set(b.getNewValue());
             primaryStage.sizeToScene();
         });
    });

1 ответ

Решение

Я буду считать, что список детей вашего gridPane исправлено, так как в вашем коде вы просто перебираете его один раз.

Во-первых, почему бы не связать managedProperty каждого ребенка своему visibleProperty?

gridPane.getChildren().stream().forEach(c -> {
    c.managedProperty().bind(c.visibleProperty());
});

Чтобы получать уведомления, когда любой ребенок меняет свою видимость, вы можете построить и наблюдать EventStream:

LiveList.map(gridPane.getChildren(), c -> EventStreams.valuesOf(c.visibleProperty()))
        .reduce((es1, es2) -> EventStreams.merge(es1, es2))
        .orElseConst(EventStreams.never()) // for the case of no children
        .values().flatMap(Function.identity())
        .subscribe(b -> primaryStage.sizeToScene());

Поскольку мы предполагаем, что список дочерних элементов фиксирован, вы можете сделать что-то более простое:

gridPane.getChildren().stream().map(c -> EventStreams.valuesOf(c.visibleProperty()))
        .reduce((es1, es2) -> EventStreams.merge(es1, es2))
        .orElse(EventStreams.never()) // for the case of no children
        .subscribe(b -> primaryStage.sizeToScene());

Учитывая все сказанное, я хотел бы найти решение, которое не вмешивается в managedProperty,
РЕДАКТИРОВАТЬ: Например, отфильтровать список детей по их видимому свойству:

// your (fixed) list of children
List<Node> children0 = ...;

// list of children that triggers list changes when children change their visibility
ObservableList<Node> children = FXCollections.observableList(
        children0, ch -> new Observable[]{ ch.visibleProperty() });

// children filtered by visibility
ObservableList<Node> visibleChildren = children.filtered(Node::isVisible);

// bind GridPane's children to visible children
Bindings.bindContent(gridPane.getChildren(), visibleChildren);

Вам может понадобиться сохранить ссылку на visibleChildren чтобы предотвратить его сборку мусора из-за использования слабых слушателей в JavaFX.

Другие вопросы по тегам