web-dev-qa-db-fra.com

Comment échanger des écrans dans une application javafx de la classe du contrôleur?

Hey, j'ai cherché sur le net pendant un certain temps, mais je n'ai pas trouvé de solution au problème suivant:

Dans javafx, vous avez 3 fichiers de base; la classe controller, le fichier fxml et la classe d'application. Maintenant, je souhaite réagir dans le contrôleur à un clic sur un bouton (ce qui fonctionne parfaitement) et modifier l'écran en conséquence peut trouver dans la classe d'application).

Exemple d'application:

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

Échantillon FXML:

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

Contrôleur-Échantillon:

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

Je serais reconnaissant pour toute sorte d'aide.

15
B Y E
@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()));
}
26
Uluk Biy

J'ai trouvé cette vieille question en entrant dans Java et en essayant de résoudre la même chose. Puisque je voulais que les scènes se souviennent du contenu entre les commutateurs, je ne pouvais pas utiliser la réponse acceptée, car lors de la commutation entre les scènes, cela les instanciait à nouveau (en perdant leur état précédent).

Quoi qu'il en soit, la réponse acceptée et la réponse à la question similaire m'ont permis de comprendre comment changer de scène sans perdre leur état. L'idée principale est d'injecter une instance de la scène dans un autre contrôleur, afin que celui-ci n'ait pas besoin d'instancier une scène neuve à maintes reprises, mais qu'il puisse utiliser une instance déjà existante (avec son état).

Voici donc la classe principale qui instancie les scènes:

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

Et voici les deux contrôleurs:

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

oui, le deuxième a le même aspect (une certaine logique pourrait probablement être partagée, mais l'état actuel est suffisant comme preuve de concept)

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);
    }
}
10
WallTearer

Vous pouvez essayer comme ça aussi.

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

}
2
Abdul.Moqueet