2012-10-09 15 views
10

Hola busqué en la red durante bastante tiempo, pero no pude encontrar una solución al siguiente problema:Cómo intercambiar pantallas en una aplicación javafx en la clase de controlador?

En javafx tienes 3 archivos básicos; la clase de controlador, el archivo fxml y la clase de aplicación. Ahora quiero reaccionar en el controlador con un botón-clic (que funciona perfectamente bien) y cambiar la pantalla con ese clic (que normalmente hace con stage.setScreen()), pero no tengo referencia al escenario (que puede encontrar en la clase de aplicación).

Aplicación-Muestra:

public class JavaFXApplication4 extends Application { 

@Override 
public void start(Stage stage) throws Exception { 
    Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml")); 

    Scene scene = new Scene(root); 

    stage.setScene(scene); 
    stage.show(); 
} 

/** 
* The main() method is ignored in correctly deployed JavaFX application. 
* main() serves only as fallback in case the application can not be 
* launched through deployment artifacts, e.g., in IDEs with limited FX 
* support. NetBeans ignores main(). 
* 
* @param args the command line arguments 
*/ 
public static void main(String[] args) { 
    launch(args); 
} 
} 

FXML-Muestra:

<?xml version="1.0" encoding="UTF-8"?> 

<?import java.lang.*?> 
<?import java.util.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="320.0" xmlns:fx="http://javafx.com/fxml" fx:controller="javafxapplication4.SampleController"> 
    <children> 
    <Button id="button" fx:id="nextScreen" layoutX="126.0" layoutY="90.0" onAction="#handleButtonAction" text="Next Screen" /> 
    <Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" /> 
    </children> 
</AnchorPane> 

Controlador-Muestra:

public class SampleController implements Initializable { 

@FXML 
private Label label; 

@FXML 
private void handleButtonAction(ActionEvent event) { 
    System.out.println("You clicked me!"); 
    label.setText("Hello World!"); 
    //Here I want to swap the screen! 
} 

@Override 
public void initialize(URL url, ResourceBundle rb) { 
    // TODO 
}  
} 

estaría agradecido por cualquier tipo de ayuda.

Respuesta

18
@FXML 
private void handleButtonAction(ActionEvent event) { 
    System.out.println("You clicked me!"); 
    label.setText("Hello World!"); 
    //Here I want to swap the screen! 

    Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow(); 
    // OR 
    Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow(); 
    // these two of them return the same stage 
    // Swap screen 
    stage.setScene(new Scene(new Pane())); 
} 
+0

Muchas gracias, eso era exactamente lo que estaba buscando :) –

+0

¡Eso fue muy útil! Gracias :) –

0

Encontré esta vieja pregunta al ingresar a Java y tratar de resolver el problema. Como quería que las escenas recuerden el contenido entre los interruptores, no pude usar la respuesta aceptada, porque al cambiar entre las escenas las vuelve a crear (perdiendo su estado anterior).

De todos modos la respuesta aceptada y el answer to the similar question me dieron indicios de cómo cambiar las escenas sin perder sus estados. La idea principal es inyectar una instancia de la escena en otro controlador, de modo que el controlador no necesite crear una instancia de una escena nueva una y otra vez, pero puede usar una instancia ya existente (con su estado).

Así que aquí es la clase principal que crea instancias de las escenas:

public class Main extends Application { 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     // getting loader and a pane for the first scene. 
     // loader will then give a possibility to get related controller 
     FXMLLoader firstPaneLoader = new FXMLLoader(getClass().getResource("firstLayout.fxml")); 
     Parent firstPane = firstPaneLoader.load(); 
     Scene firstScene = new Scene(firstPane, 300, 275); 

     // getting loader and a pane for the second scene 
     FXMLLoader secondPageLoader = new FXMLLoader(getClass().getResource("secondLayout.fxml")); 
     Parent secondPane = secondPageLoader.load(); 
     Scene secondScene = new Scene(secondPane, 300, 275); 

     // injecting second scene into the controller of the first scene 
     FirstController firstPaneController = (FirstController) firstPaneLoader.getController(); 
     firstPaneController.setSecondScene(secondScene); 

     // injecting first scene into the controller of the second scene 
     SecondController secondPaneController = (SecondController) secondPageLoader.getController(); 
     secondPaneController.setFirstScene(firstScene); 

     primaryStage.setTitle("Switching scenes"); 
     primaryStage.setScene(firstScene); 
     primaryStage.show(); 
    } 
} 

Y aquí están los controladores de ambos:

public class FirstController { 

    private Scene secondScene; 

    public void setSecondScene(Scene scene) { 
     secondScene = scene; 
    } 

    public void openSecondScene(ActionEvent actionEvent) { 
     Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow(); 
     primaryStage.setScene(secondScene); 
    } 
} 

Sí, segundo tiene el mismo aspecto (algo de lógica probablemente podría ser compartida , pero el estado actual es suficiente como una prueba de concepto)

public class SecondController { 

    private Scene firstScene; 

    public void setFirstScene(Scene scene) { 
     firstScene = scene; 
    } 

    public void openFirstScene(ActionEvent actionEvent) {  
     Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow(); 
     primaryStage.setScene(firstScene); 
    } 
} 
0

Puede intentar así también.

public void onBtnClick(ActionEvent event) { 
    try { 
     FXMLLoader loader = new FXMLLoader(getClass().getResource("login.fxml")); 
     Stage stage = (Stage) btn.getScene().getWindow(); 
     Scene scene = new Scene(loader.load()); 
     stage.setScene(scene); 
    }catch (IOException io){ 
     io.printStackTrace(); 
    } 

} 
Cuestiones relacionadas