当节点在场景中可见时检测

Ker*_*rry 6 javafx javafx-8

我试图找到一种方法来检测(或接收通知)节点已添加到场景并且是可见的.

我正在从主JavaFx线程创建Node对象,并使用它们将它们添加到舞台和场景中Platform.runLater().但是我希望Node对象接收已添加到Scene并且可见的通知,例如我希望触发动画启动.

我似乎无法找到任何属性或方法来添加侦听器来捕获此类事件.有什么建议?

Jam*_*s_D 5

第三方 JavaFX 库ReactFX有一个机制,博客中引用了这个确切的用例。简而言之,你可以做

Val<Boolean> showing = Val.flatMap(node.sceneProperty(), Scene::windowProperty)
    .flatMap(Window::showingProperty);
Run Code Online (Sandbox Code Playgroud)

然后当然

showing.addListener((obs, wasShowing, isNowShowing) -> {
    if (isNowShowing) {
        // node is showing
    } else {
        // node is not showing
    }
});
Run Code Online (Sandbox Code Playgroud)

标准库有这个版本,但是写​​的很烂。(它不是类型安全的,没有编译时检查属性是否存在,如果“链”中的任何属性为空,也会向标准错误发送大量不必要的警告,即使 API 文档表明这是一个支持的用例。)如果你想用标准的 JavaFX 库来做到这一点,你可以这样做

BooleanBinding showing = Bindings.selectBoolean(node.sceneProperty(), "window", "showing");
Run Code Online (Sandbox Code Playgroud)

然后像上面一样使用绑定。

最后,您可以手动完成所有这些工作,但是正确管理侦听器会变得有点难看:

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());
    }
}
Run Code Online (Sandbox Code Playgroud)