当节点变得不可见时使用 ReactFX 调整舞台大小?
Using ReactFX to resize stage when nodes become invisible?
我有一个 JavaFX 仪表板,可以根据复杂的上下文隐藏和显示组件,因此 ReactFX 是一个很好的工具。
我通过遍历每个节点创建了一些嵌套闭包,每个节点都创建了一个 EventStream
visibleProperty()
,然后订阅一个操作来切换 managedProperty()
并调用 sizeToScene()
.虽然我的解决方案有效,但感觉不是很干净。我觉得我应该使用平面图或其他东西。有没有更纯粹的反应方式来实现这个?
gridPane.getChildren().stream().forEach(c -> {
EventStreams.changesOf(c.visibleProperty()).subscribe(b -> {
c.managedProperty().set(b.getNewValue());
primaryStage.sizeToScene();
});
});
我假设您的 gridPane
的 child 列表是固定的,因为在您的代码中您只需迭代一次。
首先,为什么不将每个 child 的 绑定 managedProperty
到它的 visibleProperty
?
gridPane.getChildren().stream().forEach(c -> {
c.managedProperty().bind(c.visibleProperty());
});
要在任何 child 更改其可见性时得到通知,您可以构建并观察单个 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());
由于我们假设 child 列表是固定的,您可以使用稍微简单一些的方法:
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
的解决方案。
编辑: 例如,通过 属性:
过滤 children 的列表
// 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);
由于在 JavaFX 中使用了弱侦听器,您可能需要存储对 visibleChildren
的引用以防止它被垃圾回收。
我有一个 JavaFX 仪表板,可以根据复杂的上下文隐藏和显示组件,因此 ReactFX 是一个很好的工具。
我通过遍历每个节点创建了一些嵌套闭包,每个节点都创建了一个 EventStream
visibleProperty()
,然后订阅一个操作来切换 managedProperty()
并调用 sizeToScene()
.虽然我的解决方案有效,但感觉不是很干净。我觉得我应该使用平面图或其他东西。有没有更纯粹的反应方式来实现这个?
gridPane.getChildren().stream().forEach(c -> {
EventStreams.changesOf(c.visibleProperty()).subscribe(b -> {
c.managedProperty().set(b.getNewValue());
primaryStage.sizeToScene();
});
});
我假设您的 gridPane
的 child 列表是固定的,因为在您的代码中您只需迭代一次。
首先,为什么不将每个 child 的 绑定 managedProperty
到它的 visibleProperty
?
gridPane.getChildren().stream().forEach(c -> {
c.managedProperty().bind(c.visibleProperty());
});
要在任何 child 更改其可见性时得到通知,您可以构建并观察单个 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());
由于我们假设 child 列表是固定的,您可以使用稍微简单一些的方法:
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);
由于在 JavaFX 中使用了弱侦听器,您可能需要存储对 visibleChildren
的引用以防止它被垃圾回收。