12

I need a way to close a Stage from within itself by clicking a Button.

I have a main class from which I create the main stage with a scene. I use FXML for that.

public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("Builder.fxml"));
    stage.setTitle("Ring of Power - Builder");
    stage.setScene(new Scene(root));
    stage.setMinHeight(600.0);
    stage.setMinWidth(800.0);
    stage.setHeight(600);
    stage.setWidth(800);
    stage.centerOnScreen();
    stage.show();
}

Now in the main window that appears I have all the control items and menus and stuff, made through FXML and appropriate control class. That's the part where I decided to include the About info in the Help menu. So I have an event going on when the menu Help - About is activated, like this:

@FXML
private void menuHelpAbout(ActionEvent event) throws IOException{
    Parent root2 = FXMLLoader.load(getClass().getResource("AboutBox.fxml"));
    Stage aboutBox=new Stage();
    aboutBox.setScene(new Scene(root2));
    aboutBox.centerOnScreen();
    aboutBox.setTitle("About Box");
    aboutBox.setResizable(false);
    aboutBox.initModality(Modality.APPLICATION_MODAL); 
    aboutBox.show();
}

As seen the About Box window is created via FXML with a controller. I want to add a Button to close the new stage from within the controller.

The only way I found myself to be able to do this, was to define a public static Stage aboutBox; inside the Builder.java class and reference to that one from within the AboutBox.java in method that handles the action event on the closing button. But somehow it doesn't feel exactly clean and right. Is there any better way?

qwerty
  • 810
  • 1
  • 9
  • 26
Meg
  • 123
  • 1
  • 1
  • 5

2 Answers2

27

You can derive the stage to be closed from the event passed to the event handler.

new EventHandler<ActionEvent>() {
  @Override public void handle(ActionEvent actionEvent) {
    // take some action
    ...
    // close the dialog.
    Node  source = (Node)  actionEvent.getSource(); 
    Stage stage  = (Stage) source.getScene().getWindow();
    stage.close();
  }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • 8
    Close the stage like this bypasses the onCloseRequest event handler (if there is one). I would add the line stage.getOnCloseRequest().handle(null); right before stage.close(); – beardedlinuxgeek Mar 04 '13 at 18:10
  • 1
    Thank you @beardedlinuxgeek. I had this problem - my window was closing but the event handler I had registered wasn't being called. Your solution fixed the problem. – Minas Mina Jul 15 '14 at 11:06
1

In JavaFX 2.1, you have few choices. The way like in jewelsea's answer or the way what you have done already or modified version of it like

public class AboutBox extends Stage {

    public AboutBox() throws Exception {
        initModality(Modality.APPLICATION_MODAL);
        Button btn = new Button("Close");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent arg0) {
                close();
            }
        });

        // Load content via
        // EITHER

        Parent root = FXMLLoader.load(getClass().getResource("AboutPage.fxml"));
        setScene(new Scene(VBoxBuilder.create().children(root, btn).build()));

        // OR

        Scene aboutScene = new Scene(VBoxBuilder.create().children(new Text("About me"), btn).alignment(Pos.CENTER).padding(new Insets(10)).build());
        setScene(aboutScene);

        // If your about page is not so complex. no need FXML so its Controller class too.
    }
}

with usage like

new AboutBox().show();

in menu item action event handler.

Uluk Biy
  • 48,655
  • 13
  • 146
  • 153
  • Actually have a bit difficulty with the solution. It seems it doesn't like the first version with the FXML. – Meg Jul 21 '12 at 14:36
  • The problem seems to be fact that you call the class AboutBox.java which itself is supposed to be controll class for the AboutBox.fxml Unless that was the reason why you wrote AboutPage.fxml – Meg Jul 21 '12 at 17:45
  • @Meg. Updated the answer. AboutBox.java is not the controller of AboutBox.fxml or AboutPage.fxml either. – Uluk Biy Jul 21 '12 at 19:53
  • So if I get it right, I will end up with 3 files then. AboutBox which is class extending Stage (also containing the creation of the closing button, because it would need to work the way jewelsea wrote - to close the stage from the controller class?). And that AboutBox class will use AboutPage.fxml which uses eg. AboutPage.java to controll it? – Meg Jul 21 '12 at 21:15
  • @Meg. About jewelsea's answer: you can set that mouse event handler to any button's action and this button will close the stage it belongs to. This button can be in primary stage or in any controller class added to the stage. About my answer: if you have AboutPage.fxml file then yes you will end up with 3 files, otherwise only 1 AboutBox.java file. – Uluk Biy Jul 22 '12 at 02:01