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

时间:2017-02-04 15:39:22

标签: javafx javafx-8

我正在尝试找到一种检测(或接收通知)节点已添加到场景并且可见的方法。

我在主JavaFx线程中创建Node对象,并使用import pprint r17 = requests.get('https://matchbook.com/bpapi/rest/events/?sport-ids=15&?after=1486157894&?before=14862442917&') data = r17.json() for event in data['events']: print(event['name']) pprint.pprint(event['meta-tags'], indent=4) print('sorted:') # change k['id'] to k['name'] if you need to sort dict's by name pprint.pprint(sorted(event['meta-tags'], key=lambda k: k['id']), indent=4) 将它们添加到舞台和场景中。但是我希望Node对象接收已添加到Scene并且可见的通知,例如我希望触发动画启动。

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

2 个答案:

答案 0 :(得分:4)

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

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());
    }
}

答案 1 :(得分:0)

您可以向要添加新节点的容器节点的children属性添加侦听器。

grid.getChildren().addListener((ListChangeListener<? super Node>)  change -> {
   System.out.println(change.getList().get(0).getTypeSelector());
});

change.getList().get(0)返回添加到网格对象的第一个节点。

在詹姆斯的评论之后,我已经抬起头了,是的,也可以从节点的角度来看。您可以在节点上侦听parentProeprty的更改。以下代码段显示了执行此操作的方法。

Button b = new Button("Test");
b.parentProperty().addListener((observable, oldValue, newValue) ->        {
    System.out.println("added to a container " + newValue);
});

answerPane.getChildren().add(b);