web-dev-qa-db-fra.com

Chargement du nouveau fxml dans la même scène

J'ai 2 fichiers XML:

  • Mise en page (en-tête, barres de menu et contenu) 
  • Anchorpane (il est supposé être placé dans le contenu de l'autre fichier fxml)

Je voudrais savoir comment puis-je charger le deuxième fichier dans l'espace de contenu à partir de la scène "Maître". Et est-ce une bonne chose de travailler dans javaFX ou est-il préférable de charger une nouvelle scène?

J'essaie de faire quelque chose comme ça, mais ça ne marche pas:

@FXML
private AnchorPane content;

@FXML
private void handleButtonAction(ActionEvent event) {        
    content = (AnchorPane) FXMLLoader.load("Vista2.fxml");
}

Merci pour l'aide.

33
Andre

Pourquoi votre code ne fonctionne pas

Le chargeur crée un nouveau volet d'ancrage, mais vous ne l'ajoutez jamais à un parent du graphe de la scène.

Solution rapide

Au lieu de:

content = (AnchorPane) FXMLLoader.load("Vista2.fxml");

Écrire:

content.getChildren().setAll(FXMLLoader.load("Vista2.fxml"));

Remplacement des enfants de contenu avec votre nouveau Vista. Le contenu lui-même reste dans le graphique de scène. Ainsi, lorsque vous définissez ses enfants, vous les attachez également au graphique de scène en même temps.

Vous devrez peut-être jouer avec les dispositions (par exemple, travailler avec des dispositions à redimensionnement automatique telles que StackPanes plutôt que AnchorPanes) pour obtenir le comportement exact souhaité.

Plutôt que d'adopter simplement la solution miracle, je vous conseillerais de consulter le cadre simple lié ci-dessous, car cela pourrait vous fournir un mécanisme plus général pour obtenir le comportement souhaité.

Référence à la structure de navigation FXML

J'ai créé un petit cadre pour permuter les volets de contenu contrôlé fxml dans et hors d'une partie de la scène principale. 

Le mécanisme du cadre est le même que celui suggéré dans la réponse de kithril. 

  1. Un volet principal du xml externe sert de support pour les volets enfants. 
  2. Le contrôleur principal du fxml externe fournit une méthode publique pouvant être utilisée pour permuter les volets enfants. 
  3. Une classe de navigateur de commodité est initialisée de manière statique avec le contrôleur principal pour la présentation externe. 
  4. Le navigateur fournit une méthode statique publique pour charger un nouveau panneau enfant dans le conteneur principal (en appelant une méthode sur le contrôleur principal).
  5. Les volets enfants sont générés dans le navigateur par leurs chargeurs fxml respectifs. 

Pourquoi un cadre

Le cadre semble exagéré pour répondre à votre question, et peut-être l'est-il. Cependant, j’ai constaté que les deux sujets les plus demandés concernant FXML sont:

  1. Navigation entre les volets générés par FXML (cette question).
  2. Comment transmettre des données entre contrôleurs FXML .

J'ai donc estimé qu'un petit cadre de démonstration était justifié pour ce cas.

Exemple de sortie du cadre

Le premier écran montre la présentation de l'application affichant le premier Vista. Le contenu est un en-tête défini dans la présentation principale de l'application et un volet de contenu interchangeable en couleur aliceblue.

Vista1

Dans l'écran suivant, l'utilisateur a accédé à la deuxième Vista, qui conserve l'en-tête de constante de la présentation principale et remplace le volet enfant d'origine par un nouveau volet de contenu enfant de couleur corail. Le nouvel enfant a été chargé à partir d'un nouveau fichier fxml.

Vista2

Vous cherchez quelque chose de plus substantiel?

Un cadre léger plus étendu et mieux pris en charge que l'exemple de cadre de cette question est afterburner.fx .

Vous cherchez quelque chose d'encore plus simple?

Il suffit de permuter la racine de la scène: Modification des scènes dans JavaFX .

Autres options?

Transitions animées et autres: Basculement entre les volets dans JavaFX

64
jewelsea

Je ne suis pas sûr de son efficacité, mais cela semble aller très bien et de plus, beaucoup plus simple pour les méthodes ci-dessus.

https://www.youtube.com/watch?v=LDVztNtJWOo

Pour autant que j'ai compris ce qui se passe ici, voici ceci (c'est vraiment similaire à ce qui se passe dans la méthode Start () dans la classe d'application):

private void buttonGoToWindow3Action(ActionEvent event) throws IOException{
    Parent window3; //we need to load the layout that we want to swap
    window3 = (StackPane)FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow3"));

    Scene newScene; //then we create a new scene with our new layout
    newScene = new Scene(window3);

    Stage mainWindow; //Here is the magic. We get the reference to main Stage.
    mainWindow = (Stage)  ((Node)event.getSource()).getScene().getWindow();

    mainWindow.setScene(newScene); //here we simply set the new scene
}

Cependant, je ne suis pas un expert de Java et je ne connais pas bien la programmation, il serait donc bon que quelqu'un expérimenté l'évalue.

EDIT: J'ai trouvé une méthode encore plus simple;

Aller à la classe MainApplication et rendre Stage parentWindow statique.

public static Stage parentWindow;
@Override
public void start(Stage stage) throws Exception {
    parentWindow = stage;

    Parent root = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLMainScene.fxml"));

    Scene scene = new Scene(root);

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

Maintenant, vous avez accès à votre scène principale de sorte que n'importe où dans un programme, vous pouvez faire quelque chose comme ça pour changer de scène:

    Parent window1;
    window1 = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow1.fxml"));

    //Scene newSceneWindow1 = new Scene(window1);

    Stage mainStage;
    //mainStage = (Stage)  ((Node)event.getSource()).getScene().getWindow();
    mainStage = MainApplication.parentWindow;
    mainStage.getScene().setRoot(newSceneWindow1); //we dont need to change whole sceene, only set new root.
5
Tomasz Mularczyk

Mon exemple du masque .

En utilisant:

Main.getNavigation().load(View2.URL_FXML).Show();
Main.getNavigation().GoBack();
0
vas7n

Si vous cherchez un moyen de faire en sorte que le bouton appelle le nouveau fichier fxml, cela a fonctionné pour moi.

@FXML
private void mainBClicked(ActionEvent event) throws IOException {
    Stage stage;
    Parent root;
    stage=(Stage) ((Button)(event.getSource())).getScene().getWindow();
    root = FXMLLoader.load(getClass().getResource("MainMenu.fxml"));
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
}
0
Alekya

Dans ce cas, je vous recommande d'utiliser composant personnalisé à la place. Commencez par créer un composant personnalisé pour votre contenu:

class Content2 extends AnchorPane {
    Content() {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Vista2.fxml");
        loader.setRoot(this);
        loader.setController(this);
        loader.load();
    }
}

Remplacez le balisage AnchorPane à la racine de votre fichier Vista2.fxml par fx:root:

<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
    ...
</fx:root>

Ensuite, vous pouvez le faire simplement en utilisant une liaison d’événement personnalisée et une fonction de flèche. Ajoutez une propriété de gestionnaire d’événements à votre classe Content:

private final ObjectProperty<EventHandler<ActionEvent>> propertyOnPreviousButtonClick = new SimpleObjectProperty<EventHandler<ActionEvent>>();

@FXML
private void onPreviousButtonClick(ActionEvent event) {
    propertyOnPreviousButtonClick.get().handle(event)
}

public void setOnPreviousButtonClick(EventHandler<ActionEvent> handler) {
    propertyOnPreviousButtonClick.set(handler);
}

Enfin, liez votre gestionnaire d’événements personnalisé dans votre code Java ou votre fxml:

@FXML
onNextButtonClick() {
    Content2 content2 = new Content2();
    content2.setOnPreviousButtonClick((event) -> {
        Content1 content1 = new Content1();

        layout.getChildren().clear();
        layout.getChildren().add(content1);
    });

    layout.getChildren().clear();
    layout.getChildren().add(content2);    
}

Si vous ne souhaitez pas ajouter du contenu de manière dynamique, il suffit de setVisible() à true ou false

0
Clite Tailor

Je me suis retrouvé coincé dans cela aussi Essayé la plupart des réponses, ce n’était pas ce que je voulais donc j’ai utilisé les idéaux donnés pour faire ceci:

public class Main extends Application {
public static Stage homeStage;
@Override
public void start(Stage primaryStage) throws Exception{
    homeStage = primaryStage;
    Parent root = FXMLLoader.load(getClass().getResource("mainView.fxml"));
    root.getStylesheets().add(getClass().getResource("stylesheet/custom.css").toExternalForm());
    homeStage.setTitle("Classification of Living Organisms");
    homeStage.setScene(new Scene(root, 600, 500));
    homeStage.show();
}


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

c'est ma classe principale. Main.Java avec la fenêtre/page d'atterrissage mainView.fxml . Utilisé un peu de l'idée de @Tomasz, bien que cela me confuse un peu avant de le faire dans ma classe mainController.Java:

public void gotoSubMenu(Event event) {
    Parent window1;
    try {
        window1 = FXMLLoader.load(getClass().getResource("src/displayView.fxml"));
        Stage window1Stage;
        Scene window1Scene = new Scene(window1, 600, 500);
        window1Stage = Main.homeStage;
        window1Stage.setScene(window1Scene);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

a créé une nouvelle fenêtre parente appelée 'window1' qui a chargé le deuxième fichier fxml nommé 'displayView.fxml' dans le répertoire src . créé un objet de la vue principale et défini la scène sur la nouvelle scène créée dont la racine est window1 . J'espère que cela aidera ceux qui entrent dans #JavaFX maintenant.

0
ConnelBLAZE

D'autres peuvent avoir une meilleure solution, mais ma solution a été d'avoir un conteneur simple comme VBox dans le fxml externe, puis de charger le nouveau contenu et de l'ajouter en tant qu'enfant du conteneur. Si vous ne chargez qu'un ou deux formulaires, cela pourrait être la solution. Cependant, pour un cadre plus complet, j'ai trouvé ce billet utile: https://blogs.Oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1 Elle a le code source de son cadre, qui inclut des transitions sophistiquées. Bien qu'il soit conçu pour gérer les scènes de niveau supérieur, il m'a également été facile de s'adapter pour gérer les régions de contenu internes.

0
kithril