javafx - ¿Cómo devolver el valor de una etapa antes de cerrarla?
return-value stage (3)
Antes que nada, perdón por el mal inglés.
Aquí está el caso:
Tengo una "etapa principal" donde presiono un botón para abrir una "segunda etapa" donde tengo una tabla, el usuario selecciona un elemento de la tabla y hace clic en el botón "asignar" (que es solo un botón de confirmación), una vez que se hace clic, debe devolver el código del elemento seleccionado en la tabla a la etapa principal y cerrar la segunda etapa.
Aquí está el código que importa.
Tengo una variable INT que debe tomar el valor de una función:
codigo = controller.setVista(this, usuario, password);
La función "setVista" es así:
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;
}
Y la "asignaciónSeleccion" así:
private void asignarSeleccion() {
final HorarioTableModelo aux_horario = getTablaSeleccionada();
posicion = datos.indexOf(aux_horario);
if (aux_horario != null) {
codigo_horario = aux_horario.getCodigo();
}
}
Mi problema es que no puedo obtener el valor "codigo_horario" en la primera variable "codigo" antes de que cierre la etapa, ¿qué me falta?
Aquí hay un posible ejemplo. La estructura es la misma que en la respuesta en mi comentario .
La segunda
Stage
se abre a través de un "controlador" que almacena los datos que deben devolverse incluso cuando la
Stage
está cerrada y expone un captador que se utilizará para recuperar el valor del mundo exterior.
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;
}
}
}
En mi controlador principal creo Stage. Controlador de carga que puedo usar como cualquier clase. Y al crear un evento puedo obtener datos justo antes de cerrar la ventana.
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?");
}
Mis otros métodos mySceneBuilderWindowController:
public void iCanSendDataToCtrl(String giveMe) {
// do something ex. myTextBox.setText(giveMe);
}
public String iCanGetDataBeforeClose() {
// do something ex. return myTextBox.getText();
}
Puede escribir su propia clase Stage con una declaración de devolución.
public class MyStage extends Stage {
public String showAndReturn(myFXControll controll) {
super.showAndWait();
return controll.getReturn();
}
}
Después de eso, debe definir una función de retorno a su controlador.
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
}
}
Ahora puede controlar su retorno desde el controlador principal.
String retValue=myStage.showAndReturn(childControll);
System.out.println(retValue);
Creo que esta es una buena solución para un código limpio. Y puede diseñar su FXML con Screne Builder.