How to return value from a stage before closing it?

前端 未结 4 629
遥遥无期
遥遥无期 2020-11-27 23:26

First of all, sorry for the bad english.

Here is the case:

I have a \"main stage\" where i press a button to open a \"second stage\" where i have a table, th

相关标签:
4条回答
  • 2020-11-28 00:06

    In my main controller I create Stage. Load controller which I can use like any class. And by creating an event I can get data just before closing the window.

    try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(getClass().getResource("/package/mySceneBuilderWindow.fxml"));
            final Pane rootPane = (Pane)loader.load();
            Scene scene =  new Scene(rootPane);
    
            Stage stage = new Stage();
            stage.setTitle("Optional title");
            stage.setScene(scene);
    
            mySceneBuilderWindowController controller = loader.<mySceneBuilderWindowController>getController();
            controller.iCanSendDataToCtrl("String for now"); // sending data or init textFields...
    
            stage.show();
    
            /* set event which is fired on close
                // How to close in the other window... (pressing X is OK too)
                    @FXML private Button fxidSave = new Button(); // global var
                    @FXML private void handleSaveButton() {
                        Stage stage = (Stage) fxidSave.getScene().getWindow();
                        stage.close(); // closes window
                    }
             */
            stage.setOnCloseRequest((EventHandler<WindowEvent>) new EventHandler<WindowEvent>() {
                public void handle(WindowEvent we) {
                    String iCanGetDataBeforeClose = controller.getData();
                    System.out.println(iCanGetDataBeforeClose);
                    // static class can be used aswell -> System.out.println(Context.getMyString());
                }
            });
    
        } catch (IOException e) {
            System.out.println("something wrong with .fxml - name wrong? path wrong? building error?");
        }  
    

    My other mySceneBuilderWindowController methods:

     public void iCanSendDataToCtrl(String giveMe) {
        // do something ex. myTextBox.setText(giveMe);
     }
     public String iCanGetDataBeforeClose() {
        // do something ex. return myTextBox.getText();
     }
    
    0 讨论(0)
  • 2020-11-28 00:19

    Here is a possible example. The structure is the same as in the answer in my comment.

    The second Stage is opened through a "controller" that is stores the data that should be returned even when the Stage is closed and exposes a getter to be used to retrieve the value from the outer world.

    import javafx.application.Application;
    import javafx.stage.Modality;
    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.VBox;
    
    
    public class Main extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            try {
                BorderPane root = new BorderPane();
                Scene scene = new Scene(root,400,400);
    
                Button bSecondStage = new Button("Show second Stage");
                bSecondStage.setOnAction(e -> {
                    WindowController wc = new WindowController();
                    wc.showStage();
                    System.out.println(wc.getData());
                });
    
                root.setCenter(bSecondStage);
    
    
                primaryStage.setScene(scene);
                primaryStage.show();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
        class WindowController {
            private String data;
    
            void showStage() {
                Stage stage = new Stage();
                stage.initModality(Modality.APPLICATION_MODAL);
    
                VBox root = new VBox();
                Scene scene = new Scene(root);
                TextField tf = new TextField();
                Button submit = new Button("Submit");
    
                submit.setOnAction(e -> {
                    data = tf.getText();
                    stage.close();
                });
    
                root.getChildren().addAll(tf, submit);
                stage.setScene(scene);
                stage.showAndWait();
            }
    
            String getData() {
                return data;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 00:24

    You can write your own Stage class with a return statement.

    public class MyStage extends Stage {
       public String showAndReturn(myFXControll controll) {     
          super.showAndWait();
          return controll.getReturn();
       }
    } 
    

    After that you have to define a return function to your controller.

    public class TableFilterControll implements Initializable {
        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {
        }
        public String getReturn() {
            return "I'm a nice return value"; //return what you want controlled by your controller class
        }
    }
    

    Now you can controll your return from the parent controller.

    String retValue=myStage.showAndReturn(childControll);
    
    System.out.println(retValue);
    

    I think this is a good solution for clean code. And you can style your FXML with Screne Builder.

    0 讨论(0)
  • 2020-11-28 00:26

    There is some error in 4baad4's example. If the method in the controller is iCanGetDataBeforeClose, then that's what should be called:

    String someValue = controller.iCanGetDataBeforeClose();
    

    But even that didn't work right for me. I actually got this to work without using setOnCloseRequest at all. In the form controller, I had a method like this:

    public boolean getCompleted() {
        return this.finished;
    }
    

    Then in the form calling it:

    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("myView.fxml"));
    AnchorPane pane = (AnchorPane) loader.load();
    myViewController controller = loader.getController();
    Scene scene = new Scene(pane);
    Stage stage = new Stage();
    stage.setScene(scene);
    stage.showAndWait();
    if (controller.getCompleted()){
        doStuff();
    }
    

    One might think that since the stage had exited that the controller would throw a null reference exception, but it didn't, and it returned the correct response.

    This solution works and is simplest proposed IMHO.

    0 讨论(0)
提交回复
热议问题