Reputation:
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
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