简体   繁体   中英

JavaFX 2 Window event handling in controllers

So I am trying to handle WINDOW_SHOWN event from my controller with code like this:

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {

    initializeDatePickers();
    System.out.println("payer number in initialize: " + payerNumber);

    URL location = getClass().getResource("/createUser.fxml");
    FXMLLoader loader = new FXMLLoader();

    try {
        Parent root = (Parent) loader.load(location.openStream());
        root.getScene().getWindow().setOnShown(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                System.out.println("ONSHOWN");
            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }

}

But all I've got was endless cycle and program crash. The code below didn't work either, it returns NullPointerException:

@FXML private AnchorPane createUserDialog; //my root pane

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {

    createUserDialog.getScene().getWindow().addEventHandler(WindowEvent.WINDOW_SHOWN, 
      new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent window) {
            System.out.println("ONSHOWN");
        }
    });

}

Implementing WindowEvent interface didn't work at all, don't know why. So, how could I handle this event? And why I've got NullPointerException? In docs said that initialize() calling only after root pane completely processed.

When the initialize() method is being executed, the root pane is completely constructed but is not added to a scene, or a window. (The initialize() method is executed as part of the execution of your FXMLLoader's load() method; check the code where you call that and you will see that you add the root to a scene and place it in a window after that.) So during the execution of intialize(), root.getScene() will return null.

You can use a Binding to check when the window changes and attach a listener to it:

final EventHandler<WindowEvent> shownHandler = new EventHandler<WindowEvent>() {
  @Override
  public void handle(WindowEvent event) {
    System.out.println("Shown");
  }
};
Bindings.<Window>select(createUserDialog.sceneProperty(), "window").addListener(new ChangeListener<Window>() {

    @Override
    public void changed(ObservableValue<? extends Window> observable,
            Window oldValue, Window newValue) {
        if (oldValue != null) {
            oldValue.removeEventHandler(WindowEvent.WINDOW_SHOWN, shownHandler);
        }
        if (newValue != null) {
            newValue.addEventHandler(WindowEvent.WINDOW_SHOWN, shownHandler);
        }
    }

});

This code assumes the root is only ever added to one window; in the unlikely event you're taking the root out of one window and putting it in another during your application life cycle, you would need to remove the listener from the old window. If you need this I'll update the code, but it makes it more complex.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM