第三方 JavaFX 库ReactFX https://github.com/TomasMikula/ReactFX有一个机制,这个确切的用例在blog http://tomasmikula.github.io/blog/2015/02/10/val-a-better-observablevalue.html。简而言之,你可以做
Val<Boolean> showing = Val.flatMap(node.sceneProperty(), Scene::windowProperty)
.flatMap(Window::showingProperty);
然后当然
showing.addListener((obs, wasShowing, isNowShowing) -> {
if (isNowShowing) {
// node is showing
} else {
// node is not showing
}
});
标准库有一个这样的版本,但写得非常糟糕。 (它不是类型安全的,没有编译时检查属性是否存在,并且如果“链”中的任何属性为空,也会将许多不必要的警告传递给标准错误,即使 API 文档表明这是一个支持的用例。)如果您想使用标准 JavaFX 库来执行此操作,您可以这样做
BooleanBinding showing = Bindings.selectBoolean(node.sceneProperty(), "window", "showing");
然后以与上面相同的方式使用绑定。
最后,您可以手动完成所有这些操作,但正确管理侦听器会有点难看:
BooleanProperty showing = new SimpleBooleanProperty();
ChangeListener<Window> windowListener = (obs, oldWindow, newWindow) -> {
showing.unbind();
if (newWindow != null) {
showing.bind(newWindow.showingProperty());
} else {
showing.set(false);
}
};
ChangeListener sceneListener = (obs, oldScene, newScene) -> {
showing.unbind();
if (oldScene != null) {
oldScene.windowProperty().removeListener(windowListener);
}
if (newScene == null) {
showing.set(false);
} else {
newScene.windowProperty().addListener(windowListener);
if (newScene.getWindow() == null) {
showing.set(false);
} else {
showing.bind(newScene.getWindow().showingProperty());
}
}
};
node.sceneProperty().addListener(sceneListener);
if (node.getScene() == null) {
showing.set(false);
} else {
node.getScene().windowProperty().add(windowListener);
if (node.getScene().getWindow() == null) {
showing.set(false);
} else {
showing.bind(node.getScene().getWindow().showingProperty());
}
}