如何在关闭阶段之前从阶段中获得 return 值?

How to return value from a stage before closing it?

我有一个“主阶段”,我按下按钮打开“第二阶段”,我有一个 table,用户选择 table 中的一项并单击“asignar”按钮(只是一个确认按钮),一旦点击,它必须return在table中选择的项目的代码到主阶段并关闭第二阶段。

这是重要的代码。

我有一个 INT 变量,它必须取一个函数的值:

codigo = controller.setVista(this, usuario, password);

“setVista”函数是这样的:

public int setVista(ListHorarios vista, String usuario, String password) {
this.vista = vista;
this.usuario = usuario;
this.password = password;
this.inicializarTabla();
this.actualizarTabla(0, "%");
   
btnSeleccionar.setOnAction(e -> {
    asignarSeleccion();
    Stage stage = (Stage) btnSeleccionar.getScene().getWindow(); 
    stage.close();
});
    return codigo_horario;
}

像这样的“asignarSeleccion”:

private void asignarSeleccion() {
    final HorarioTableModelo aux_horario = getTablaSeleccionada();
    posicion = datos.indexOf(aux_horario);
    if (aux_horario != null) {
        codigo_horario = aux_horario.getCodigo();
    }
}

我的问题是我无法在阶段关闭前将“codigo_horario”值放入第一个变量“codigo”中,我缺少什么?

这是一个可能的例子。结构同in the answer in my comment.

第二个 Stage 通过 "controller" 打开,它存储即使 Stage 关闭也应返回的数据,并公开 getter用于从外部世界检索值。

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

您可以使用 return 语句编写自己的舞台 class。

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

之后你必须为你的控制器定义一个return函数。

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
    }
}

现在您可以从父控制器控制您的 return。

String retValue=myStage.showAndReturn(childControll);

System.out.println(retValue);

我认为这是一个干净代码的好解决方案。您还可以使用 Screen Builder 设计 FXML 样式。

在我的主控制器中,我创建了 Stage。我可以像任何 class 一样使用的负载控制器。通过创建一个事件,我可以在关闭 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?");
    }  

我的其他 mySceneBuilderWindowController 方法:

 public void iCanSendDataToCtrl(String giveMe) {
    // do something ex. myTextBox.setText(giveMe);
 }
 public String iCanGetDataBeforeClose() {
    // do something ex. return myTextBox.getText();
 }

4baad4 的示例中存在一些错误。如果controller中的方法是iCanGetDataBeforeClose,那么应该这样调用:

String someValue = controller.iCanGetDataBeforeClose();

但即使这样也不适合我。我实际上根本没有使用 setOnCloseRequest 就让它工作了。在表单控制器中,我有一个这样的方法:

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

然后在表单中调用它:

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

有人可能会认为,由于阶段已经退出,控制器会抛出空引用异常,但它没有,它返回了正确的响应。

这个解决方案有效,并且是最简单的恕我直言。