I want to fill a Pane varPane
with variable content. The implementation looks similar to this
Pane varPane = new Pane();
// ..
someProperty.addListener(( obsv, oldV, newV) -> {
varPane.getChildren().clear(); // Remove old Property Pane Content
Pane propPane = getNewPane(newV); // Get new content
varPane.getChildren().add(propPane); // add Content
});
The Pane is generated like:
public Pane getNewPane(Object newV){
Pane myPane = new Pane();
// Add dummy Content
myPane.getChildren().add(new Label(newV.toString()))
// Here I need some listener
// somthing like [not working]:
myPane.setOnClosed( System.out.println("Pane closed: " + newV.toString() );
return myPane;
}
As indicated above, I need to perform some cleanup after the pane is not used anymore. However I couldn't find to correct way to implement such a listener.
The listener shall be triggered if:
varPane
is changed and the old Pane is not visible anymore, ORvarPane
is destroyed (e.g. on Platform.exit()
)I could require that on these events an function is called for the cleanup. However I think it would be safer, if the pane detects such events on its own.
First note that varPane.getChildren().removeAll()
doesn't do what you think. You need
varPane.getChildren().clear();
You can check if the pane's parentProperty()
changes to null:
myPane.parentProperty().addListener((obs, oldParent, newParent) -> {
if (newParent == null) {
System.out.println("Pane closed: " + newV);
}
});
Checking if the window containing the pane is hidden (closed) is considerably harder. You can create the following chain of listeners (basically listening to the pane's sceneProperty()
in order to listen to the scene's windowProperty()
in order to listener to the window's showingProperty()
):
ChangeListener<Boolean> showingListener = (obs, wasShowing, isNowShowing) -> {
if (! isNowShowing) {
System.out.println("Window containing "+newV+" hidden");
}
};
ChangeListener<Window> windowListener = (obs, oldWin, newWin) -> {
if (oldWin != null) {
oldWin.showingProperty().removeListener(showingListener);
}
if (newWin != null) {
newWin.showingProperty().addListener(showingListener);
}
};
ChangeListener<Scene> sceneListener = (obs, oldScene, newScene) -> {
if (oldScene != null) {
oldScene.windowProperty().removeListener(windowListener);
if (oldScene.getWindow() != null) {
oldScene.getWindow().showingProperty().removeListener(showingListener);
}
}
if (newScene != null) {
newScene.windowProperty().addListener(windowListener);
if (newScene.getWindow() != null) {
newScene.getWindow().showingProperty().addListener(showingListener);
}
}
};
myPane.sceneProperty().addListener(sceneListener);
You may prefer to use a bindings framework, such as the one that is part of ReactFX. Using ReactFX, you can cover both cases with
EventStreams.changesOf(Val
.flatMap(myPane.sceneProperty(), Scene::windowProperty)
.flatMap(Window::showingProperty)
.orElseConst(false))
.filter(c -> ! c.getNewValue())
.observe(v -> System.out.println("Pane closed: "+newV));