user5182503
user5182503

Reputation:

Is it possible to create dynamic Bindings.OR in JavaFX?

Lets consider the following situation. There is a Pane parentPane and there are Pane firstChildPane, secondChildPane, thirdChildPane .... Child panes are added to parent pane. How can I make parentPane be visible only in that case if any of child pane is visible taking into consideration that child panes can be added and removed dynamically without any limit and in any order. Of course childPane visible state can be also changed any time. Is it possible to create dynamic Bindings.OR in order I could add/remove child visible property to/from it dynamically? If yes, then how? If not, then what solutions are used in such cases?

Upvotes: 2

Views: 843

Answers (1)

James_D
James_D

Reputation: 209438

You can try something along the following lines:

// list that fires updates if any members change visibility:
ObservableList<Node> children = 
    FXCollections.observableArrayList(n -> new Observable[] {n.visibleProperty()});
// make the new list always contain the same elements as the pane's child list:
Bindings.bindContent(children, parentPane.getChildren());
// filter for visible nodes:
ObservableList<Node> visibleChildren = children.filter(Node::isVisible);
// and now see if it's empty:
BooleanBinding someVisibleChildren = Bindings.isNotEmpty(visibleChildren);
// finally:
parentPane.visibleProperty().bind(someVisibleChildren);

Another approach is to create your own BooleanBinding directly:

Pane parentPane = ... ;

BooleanBinding someVisibleChildren = new BooleanBinding() {


    {
        parentPane.getChildren().forEach(n -> bind(n.visibleProperty()));

        parentPane.getChildren().addListener((Change<? extends Node> c) -> {
            while (c.next()) {
               c.getAddedSubList().forEach(n -> bind(n.visibleProperty()));
               c.getRemoved().forEach(n -> unbind(n.visibleProperty())) ;
            }
        });

        bind(parentPane.getChildren());
    }

    @Override
    public boolean computeValue() {
        return parentPane.getChildren().stream()
            .filter(Node::isVisible)
            .findAny()
            .isPresent();
    }
}

parentPane.visibleProperty().bind(someVisibleChildren);

Upvotes: 3

Related Questions