Passage des paramètres JavaFX FXML


194

Comment passer des paramètres à une fenêtre secondaire dans javafx? Existe-t-il un moyen de communiquer avec le contrôleur correspondant?

Par exemple: L'utilisateur choisit un client dans un TableViewet une nouvelle fenêtre s'ouvre, affichant les informations du client.

Stage newStage = new Stage();
try 
{
    AnchorPane page = (AnchorPane) FXMLLoader.load(HectorGestion.class.getResource(fxmlResource));
    Scene scene = new Scene(page);
    newStage.setScene(scene);
    newStage.setTitle(windowTitle);
    newStage.setResizable(isResizable);
    if(showRightAway) 
    {
        newStage.show();
    }
}

newStageserait la nouvelle fenêtre. Le problème est que je ne trouve pas de moyen de dire au contrôleur où chercher les informations du client (en passant l'id comme paramètre).

Des idées?


Vérifiez si cela fonctionne aussi: stackoverflow.com/questions/14370183/…
Dynelight

@Alvaro: avez-vous obtenu votre solution? pouvez-vous passer le paramètre? d'un contrôleur à un autre fichier de contrôleur?
Java Man

3
Oui. jewelsea a donné une explication au niveau du livre. C'est pourquoi j'ai accepté sa réponse
Alvaro

Réponses:


276

Approche recommandée

Cette réponse énumère différents mécanismes pour transmettre des paramètres aux contrôleurs FXML.

Pour les petites applications, je recommande fortement de passer des paramètres directement de l'appelant au contrôleur - c'est simple, direct et ne nécessite aucun cadre supplémentaire.

Pour les applications plus grandes et plus complexes, il serait utile de rechercher si vous souhaitez utiliser les mécanismes d' injection de dépendance ou de bus d'événements dans votre application.

Passage direct des paramètres de l'appelant au contrôleur

Passez des données personnalisées à un contrôleur FXML en récupérant le contrôleur à partir de l'instance de chargeur FXML et en appelant une méthode sur le contrôleur pour l'initialiser avec les valeurs de données requises.

Quelque chose comme le code suivant:

public Stage showCustomerDialog(Customer customer) {
  FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
      "customerDialog.fxml"
    )
  );

  Stage stage = new Stage(StageStyle.DECORATED);
  stage.setScene(
    new Scene(
      (Pane) loader.load()
    )
  );

  CustomerDialogController controller = 
    loader.<CustomerDialogController>getController();
  controller.initData(customer);

  stage.show();

  return stage;
}

...

class CustomerDialogController {
  @FXML private Label customerName;
  void initialize() {}
  void initData(Customer customer) {
    customerName.setText(customer.getName());
  }
}

Un nouveau FXMLLoader est construit comme indiqué dans l'exemple de code ie new FXMLLoader(location). L'emplacement est une URL et vous pouvez générer une telle URL à partir d'une ressource FXML en:

new FXMLLoader(getClass().getResource("sample.fxml"));

Faites attention de NE PAS utiliser de fonction de chargement statique sur le FXMLLoader, sinon vous ne pourrez pas obtenir votre contrôleur à partir de votre instance de chargeur.

Les instances FXMLLoader elles-mêmes ne savent jamais rien des objets de domaine. Vous ne passez pas directement des objets de domaine spécifiques à l'application dans le constructeur FXMLLoader, mais vous:

  1. Construire un FXMLLoader basé sur le balisage fxml à un emplacement spécifié
  2. Obtenez un contrôleur à partir de l'instance FXMLLoader.
  3. Appelez des méthodes sur le contrôleur récupéré pour fournir au contrôleur des références aux objets de domaine.

Ce blog (par un autre auteur) fournit un autre, mais similaire, par exemple .

Configuration d'un contrôleur sur FXMLLoader

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

FXMLLoader loader = new FXMLLoader(
    getClass().getResource(
        "customerDialog.fxml"
    )
);
loader.setController(dialogController);

Pane mainPane = (Pane) loader.load();

Vous pouvez construire un nouveau contrôleur dans le code, en transmettant tous les paramètres de votre appelant au constructeur du contrôleur. Une fois que vous avez construit un contrôleur, vous pouvez le définir sur une instance FXMLLoader avant d'appeler la méthode d' load() instance .

Pour définir un contrôleur sur un chargeur (dans JavaFX 2.x), vous NE POUVEZ PAS également définir un fx:controllerattribut dans votre fichier fxml.

En raison de la limitation de la fx:controllerdéfinition dans FXML, je préfère personnellement obtenir le contrôleur du FXMLLoader plutôt que de le configurer dans le FXMLLoader.

Demander au contrôleur d'extraire les paramètres d'une méthode statique externe

Cette méthode est illustrée par la réponse de Sergey à Javafx 2.0 How-to Application.getParameters () dans un fichier Controller.java .

Utiliser l'injection de dépendance

FXMLLoader prend en charge les systèmes d'injection de dépendances comme Guice, Spring ou Java EE CDI en vous permettant de définir une fabrique de contrôleurs personnalisée sur FXMLLoader. Cela fournit un rappel que vous pouvez utiliser pour créer l'instance de contrôleur avec des valeurs dépendantes injectées par le système d'injection de dépendance respectif.

Un exemple d'injection JavaFX d'application et de dépendance de contrôleur avec Spring est fourni dans la réponse à:

Une approche d'injection de dépendances vraiment agréable et propre est illustrée par le framework afterburner.fx avec un exemple d'application air-hacks qui l'utilise. afterburner.fx s'appuie sur JEE6 javax.inject pour effectuer l'injection de dépendance.

Utiliser un bus d'événements

Greg Brown, le créateur et implémenteur d'origine de la spécification FXML, suggère souvent d'envisager l'utilisation d'un bus d'événements, tel que le Guava EventBus , pour la communication entre les contrôleurs instanciés FXML et d'autres logiques d'application.

L'EventBus est une API de publication / abonnement simple mais puissante avec des annotations qui permet aux POJO de communiquer entre eux n'importe où dans une machine virtuelle Java sans avoir à se référer les uns aux autres.

Questions et réponses sur le suivi

sur la première méthode, pourquoi renvoyez-vous Stage? La méthode peut également être annulée car vous donnez déjà la commande show (); juste avant l'étape de retour;. Comment planifiez-vous l'utilisation en renvoyant la scène

Il s'agit d'une solution fonctionnelle à un problème. Une étape est renvoyée par la showCustomerDialogfonction afin qu'une référence à celle-ci puisse être stockée par une classe externe qui souhaitera peut-être faire quelque chose, comme masquer l'étape en fonction d'un clic sur le bouton dans la fenêtre principale, ultérieurement. Une autre solution orientée objet pourrait encapsuler la fonctionnalité et la référence d'étape à l'intérieur d'un objet CustomerDialog ou avoir une étape d'extension CustomerDialog. Un exemple complet d'interface orientée objet vers une boîte de dialogue personnalisée encapsulant des données FXML, de contrôleur et de modèle dépasse le cadre de cette réponse, mais peut constituer un article de blog intéressant pour quiconque est enclin à en créer un.


Informations supplémentaires fournies par l'utilisateur StackOverflow nommé @dzim

Exemple pour l'injection de dépendance de démarrage de Spring

La question de savoir comment le faire "The Spring Boot Way", il y avait une discussion sur JavaFX 2, que j'ai répondu dans le permalien ci-joint. L'approche est toujours valide et testée en mars 2016, sur Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


Parfois, vous souhaiterez peut-être transmettre les résultats à l'appelant, auquel cas vous pouvez consulter la réponse à la question connexe:


Les constructeurs FXMLLoader prennent uniquement les URL comme paramètres. Quelle est la bonne façon d'instancier FXMLLoader?
Alvaro

1
le site Web du bus d'événement a fait allusion aux états, "Mise à jour 3/2013: L'EventBus est devenu obsolète ..."
j le

1
Les DataFX Controller Frameworks fournissent une prise en charge de l'injection pour les contrôleurs FXML
Hendrik Ebbers

2
Ajout d'une section Q&R supplémentaire pour répondre aux autres questions de @Anarkie
jewelsea

7
pour godshake, y a-t-il quelque chose de simple pour faire ce petit travail en JavaFx? est-ce une fonctionnalité très courante pour transmettre des données dans le constructeur et javafx nécessite cet enfer de choses tous ensemble juste pour envoyer un nom ou une valeur?
Zahan Safallwa

13

Je me rends compte que c'est un article très ancien et qu'il contient déjà d'excellentes réponses, mais je voulais faire un simple MCVE pour démontrer une telle approche et permettre aux nouveaux codeurs de voir rapidement le concept en action.

Dans cet exemple, nous utiliserons 5 fichiers:

  1. Main.java - Simplement utilisé pour démarrer l'application et appeler le premier contrôleur.
  2. Controller1.java - Le contrôleur pour la première disposition FXML.
  3. Controller2.java - Le contrôleur pour la deuxième disposition FXML.
  4. Layout1.fxml - La disposition FXML pour la première scène.
  5. Layout2.fxml - La disposition FXML pour la deuxième scène.

Tous les fichiers sont répertoriés dans leur intégralité au bas de cet article.

L'objectif: Pour démontrer les valeurs de passage Controller1à Controller2et vice - versa.

Le déroulement du programme:

  • La première scène contient a TextField, a Buttonet a Label. Lorsque vous Buttoncliquez sur, la deuxième fenêtre est chargée et affichée, y compris le texte entré dans leTextField .
  • Dans la deuxième scène, il y a aussi un TextField, un Buttonet un Label. Le Labelaffiche le texte saisi dans leTextField la première scène.
  • Lors de la saisie de texte dans la deuxième scène TextFieldet en cliquant sur son Button, la première scène Labelest mise à jour pour afficher le texte saisi.

Il s'agit d'une démonstration très simple et pourrait certainement représenter une certaine amélioration, mais devrait rendre le concept très clair.

Le code lui-même est également commenté avec quelques détails sur ce qui se passe et comment.

LE CODE

Main.java:

import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        // Create the first controller, which loads Layout1.fxml within its own constructor
        Controller1 controller1 = new Controller1();

        // Show the new stage
        controller1.showStage();

    }
}

Controller1.java:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller1 {

    // Holds this controller's Stage
    private final Stage thisStage;

    // Define the nodes from the Layout1.fxml file. This allows them to be referenced within the controller
    @FXML
    private TextField txtToSecondController;
    @FXML
    private Button btnOpenLayout2;
    @FXML
    private Label lblFromController2;

    public Controller1() {

        // Create the new stage
        thisStage = new Stage();

        // Load the FXML file
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout1.fxml"));

            // Set this class as the controller
            loader.setController(this);

            // Load the scene
            thisStage.setScene(new Scene(loader.load()));

            // Setup the window/stage
            thisStage.setTitle("Passing Controllers Example - Layout1");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Show the stage that was loaded in the constructor
     */
    public void showStage() {
        thisStage.showAndWait();
    }

    /**
     * The initialize() method allows you set setup your scene, adding actions, configuring nodes, etc.
     */
    @FXML
    private void initialize() {

        // Add an action for the "Open Layout2" button
        btnOpenLayout2.setOnAction(event -> openLayout2());
    }

    /**
     * Performs the action of loading and showing Layout2
     */
    private void openLayout2() {

        // Create the second controller, which loads its own FXML file. We pass a reference to this controller
        // using the keyword [this]; that allows the second controller to access the methods contained in here.
        Controller2 controller2 = new Controller2(this);

        // Show the new stage/window
        controller2.showStage();

    }

    /**
     * Returns the text entered into txtToSecondController. This allows other controllers/classes to view that data.
     */
    public String getEnteredText() {
        return txtToSecondController.getText();
    }

    /**
     * Allows other controllers to set the text of this layout's Label
     */
    public void setTextFromController2(String text) {
        lblFromController2.setText(text);
    }
}

Controller2.java:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;

public class Controller2 {

    // Holds this controller's Stage
    private Stage thisStage;

    // Will hold a reference to the first controller, allowing us to access the methods found there.
    private final Controller1 controller1;

    // Add references to the controls in Layout2.fxml
    @FXML
    private Label lblFromController1;
    @FXML
    private TextField txtToFirstController;
    @FXML
    private Button btnSetLayout1Text;

    public Controller2(Controller1 controller1) {
        // We received the first controller, now let's make it usable throughout this controller.
        this.controller1 = controller1;

        // Create the new stage
        thisStage = new Stage();

        // Load the FXML file
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout2.fxml"));

            // Set this class as the controller
            loader.setController(this);

            // Load the scene
            thisStage.setScene(new Scene(loader.load()));

            // Setup the window/stage
            thisStage.setTitle("Passing Controllers Example - Layout2");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Show the stage that was loaded in the constructor
     */
    public void showStage() {
        thisStage.showAndWait();
    }

    @FXML
    private void initialize() {

        // Set the label to whatever the text entered on Layout1 is
        lblFromController1.setText(controller1.getEnteredText());

        // Set the action for the button
        btnSetLayout1Text.setOnAction(event -> setTextOnLayout1());
    }

    /**
     * Calls the "setTextFromController2()" method on the first controller to update its Label
     */
    private void setTextOnLayout1() {
        controller1.setTextFromController2(txtToFirstController.getText());
    }

}

Layout1.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" spacing="10.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-weight: bold;" text="This is Layout1!"/>
        <HBox alignment="CENTER_LEFT" spacing="10.0">
            <Label text="Enter Text:"/>
            <TextField fx:id="txtToSecondController"/>
            <Button fx:id="btnOpenLayout2" mnemonicParsing="false" text="Open Layout2"/>
        </HBox>
        <VBox alignment="CENTER">
            <Label text="Text From Controller2:"/>
            <Label fx:id="lblFromController2" text="Nothing Yet!"/>
        </VBox>
    </VBox>
</AnchorPane>

Layout2.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
    <VBox alignment="CENTER" spacing="10.0">
        <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
        </padding>
        <Label style="-fx-font-weight: bold;" text="Welcome to Layout 2!"/>
        <VBox alignment="CENTER">
            <Label text="Text From Controller1:"/>
            <Label fx:id="lblFromController1" text="Nothing Yet!"/>
        </VBox>
        <HBox alignment="CENTER_LEFT" spacing="10.0">
            <Label text="Enter Text:"/>
            <TextField fx:id="txtToFirstController"/>
            <Button fx:id="btnSetLayout1Text" mnemonicParsing="false" text="Set Text on Layout1"/>
        </HBox>
    </VBox>
</AnchorPane>

1
Est-il possible de placer le contrôleur dans le fichier FXML? Beause supprimant la ligne: loader.setController(this)et l'ajout du contrôleur dans le fichier FXML plante l'application
Halfacht

1
Pas si le FXML est chargé depuis le contrôleur lui-même. Si vous chargez le FXML à partir de la classe Main, par exemple, vous pouvez définir le contrôleur dans le fichier FXML et obtenir une référence à celui-ci en utilisantloader.getController()
Zephyr

Enfin, j'ai réussi à trouver une solution, un excellent exemple. Je l'ai implémenté dans mon projet et maintenant j'essaie d'ouvrir les deux fenêtres simultanément et de les rendre modales en premier. Malheureusement, un seul s'ouvre. Quelqu'un pourrait-il l'aider?
jabba

8

La classe javafx.scene.Node a une paire de méthodes setUserData (Object) et Object getUserData ()

Que vous pourriez utiliser pour ajouter vos informations au nœud.

Vous pouvez donc appeler page.setUserData (info);

Et le contrôleur peut vérifier si les informations sont définies. En outre, vous pouvez utiliser ObjectProperty pour le transfert de données en amont, si nécessaire.

Observez une documentation ici: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Avant la phrase "Dans la première version, le handleButtonAction () est marqué avec @FXML pour autoriser le balisage défini dans le document du contrôleur à l'invoquer. Dans le deuxième exemple, le champ du bouton est annoté pour permettre au chargeur de définir sa valeur. La méthode initialize () est également annotée. "

Vous devez donc associer un contrôleur à un nœud et définir des données utilisateur sur le nœud.


Stage.getScene () -> Scene.getRoot () -> recherche récursive avec Parent.getChildrenUnmodifiable (). C'est très sale. Si quelqu'un pouvait suggérer mieux, ce serait génial.
Alexander Kirov

Il semble que Stage.getScene (). GetRoot () soit la bonne façon! Merci
Alvaro

7

Voici un exemple pour passer des paramètres à un document fxml via un espace de noms.

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/null" xmlns:fx="http://javafx.com/fxml/1">
    <BorderPane>
        <center>
            <Label text="$labelText"/>
        </center>
    </BorderPane>
</VBox>

Définissez la valeur External Textde la variable d'espace de noms labelText:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class NamespaceParameterExampleApplication extends Application {

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

    @Override
    public void start(Stage primaryStage) throws IOException {
        final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("namespace-parameter-example.fxml"));

        fxmlLoader.getNamespace()
                  .put("labelText", "External Text");

        final Parent root = fxmlLoader.load();

        primaryStage.setTitle("Namespace Parameter Example");
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }
}

Il convient de noter que certaines touches sont utilisées en interne: par exemple FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYet toute chaîne utilisée comme valeur de l' fx:idattribut.
fabian

Merci pour cela, mon autre scène est juste un conteneur qui montre le texte précédemment affiché sur ma scène principale. Maintenant, je peux avoir un fxml que je peux réutiliser à plusieurs endroits en initialisant le contenu via des variables d'espace de nom. Je n'ai pas eu à créer de nouvelles méthodes ou à modifier mon constructeur ou mes initalisers - il suffit d'ajouter une variable dans mon FXML et d'ajouter une ligne dans mon code fxmloader dans le contrôleur principal.
SystemsInCode

4

Cela marche ..

Rappelez-vous que la première fois que vous imprimez la valeur de passage, vous obtiendrez null, vous pouvez l'utiliser après le chargement de vos fenêtres, de même pour tout ce que vous voulez coder pour tout autre composant.

Premier contrôleur

try {
    Stage st = new Stage();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/inty360/free/form/MainOnline.fxml"));

    Parent sceneMain = loader.load();

    MainOnlineController controller = loader.<MainOnlineController>getController();
    controller.initVariable(99L);

    Scene scene = new Scene(sceneMain);
    st.setScene(scene);
    st.setMaximized(true);
    st.setTitle("My App");
    st.show();
} catch (IOException ex) {
    Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, null, ex);
}

Un autre contrôleur

public void initVariable(Long id_usuario){
    this.id_usuario = id_usuario;
    label_usuario_nombre.setText(id_usuario.toString());
}

1
Cela fonctionne lorsque vous passez des paramètres du premier contrôleur au second, mais comment passer des paramètres du deuxième au premier contrôleur, je veux dire après le chargement de first.fxml.
Menai Ala Eddine - Aladdin

@XlintXms voir la question connexe Paramètre JavaFX FXML passant du contrôleur A à B et inversement , qui répond à votre question supplémentaire.
jewelsea

2

Vous devez créer une classe de contexte.

public class Context {
    private final static Context instance = new Context();
    public static Context getInstance() {
        return instance;
    }

    private Connection con;
    public void setConnection(Connection con)
    {
        this.con=con;
    }
    public Connection getConnection() {
        return con;
    }

    private TabRoughController tabRough;
    public void setTabRough(TabRoughController tabRough) {
        this.tabRough=tabRough;
    }

    public TabRoughController getTabRough() {
        return tabRough;
    }
}

Vous devez simplement définir l'instance du contrôleur lors de l'initialisation en utilisant

Context.getInstance().setTabRough(this);

et vous pouvez l'utiliser à partir de votre application entière en utilisant simplement

TabRoughController cont=Context.getInstance().getTabRough();

Vous pouvez maintenant transmettre des paramètres à n'importe quel contrôleur à partir de l'application entière.


Nous utilisons cette approche et cela fonctionne très bien. J'aime avoir accès aux données à l'intérieur du constructeur ou dans la méthode d'initialisation et je n'ai pas à définir les données dans le contrôleur après sa construction
Bob

1

Oui, vous pouvez.
Vous devez ajouter le premier contrôleur:

YourController controller = loader.getController();     
controller.setclient(client);

Puis dans le second déclarez un client, puis en bas de votre contrôleur:

public void setclien(Client c) {
    this.client = c;
}

0

Voici un exemple d'utilisation d'un contrôleur injecté par Guice.

/**
 * Loads a FXML file and injects its controller from the given Guice {@code Provider}
 */
public abstract class GuiceFxmlLoader {

   public GuiceFxmlLoader(Stage stage, Provider<?> provider) {
      mStage = Objects.requireNonNull(stage);
      mProvider = Objects.requireNonNull(provider);
   }

   /**
    * @return the FXML file name
    */
   public abstract String getFileName();

   /**
    * Load FXML, set its controller with given {@code Provider}, and add it to {@code Stage}.
    */
   public void loadView() {
      try {
         FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource(getFileName()));
         loader.setControllerFactory(p -> mProvider.get());
         Node view = loader.load();
         setViewInStage(view);
      }
      catch (IOException ex) {
         LOGGER.error("Failed to load FXML: " + getFileName(), ex);
      }
   }

   private void setViewInStage(Node view) {
      BorderPane pane = (BorderPane)mStage.getScene().getRoot();
      pane.setCenter(view);
   }

   private static final Logger LOGGER = Logger.getLogger(GuiceFxmlLoader.class);

   private final Stage mStage;
   private final Provider<?> mProvider;
}

Voici une implémentation concrète du chargeur:

public class ConcreteViewLoader extends GuiceFxmlLoader {

   @Inject
   public ConcreteViewLoader(Stage stage, Provider<MyController> provider) {
      super(stage, provider);
   }

   @Override
   public String getFileName() {
      return "my_view.fxml";
   }
}

Notez que cet exemple charge la vue au centre d'un BoarderPane qui est la racine de la scène dans la scène. Ceci n'est pas pertinent pour l'exemple (détail d'implémentation de mon cas d'utilisation spécifique) mais a décidé de le laisser car certains pourraient le trouver utile.


-1

Vous pouvez décider d'utiliser une liste publique observable pour stocker des données publiques, ou simplement créer une méthode de définition publique pour stocker les données et les récupérer à partir du contrôleur correspondant


-3

Pourquoi répondre à une question de 6 ans?
L'un des concepts les plus fondamentaux de tout langage de programmation est de savoir comment naviguer d'un (fenêtre, formulaire ou page) à un autre. De plus, lors de cette navigation, le développeur souhaite souvent transmettre des données à partir d'une (fenêtre, formulaire ou page) et afficher ou utiliser les données transmises.Bien
que la plupart des réponses ici fournissent des exemples bons à excellents comment accomplir cela, nous pensions que nous allions le faire un cran ou deux ou trois
Nous avons dit trois parce que nous naviguerons entre trois (fenêtre, formulaire ou page) et utiliserons le concept de variables statiques pour transmettre des données autour de (fenêtre, formulaire ou page)
Nous inclurons également un code de prise de décision tout en nous naviguons

public class Start extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        // This is MAIN Class which runs first
        Parent root = FXMLLoader.load(getClass().getResource("start.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setResizable(false);// This sets the value for all stages
        stage.setTitle("Start Page"); 
        stage.show();
        stage.sizeToScene();
    }

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

Démarrer le contrôleur

public class startController implements Initializable {

@FXML Pane startPane,pageonePane;
@FXML Button btnPageOne;
@FXML TextField txtStartValue;
public Stage stage;
public static int intSETonStartController;
String strSETonStartController;

@FXML
private void toPageOne() throws IOException{

    strSETonStartController = txtStartValue.getText().trim();


        // yourString != null && yourString.trim().length() > 0
        // int L = testText.length();
        // if(L == 0){
        // System.out.println("LENGTH IS "+L);
        // return;
        // }
        /* if (testText.matches("[1-2]") && !testText.matches("^\\s*$")) 
           Second Match is regex for White Space NOT TESTED !
        */

        String testText = txtStartValue.getText().trim();
        // NOTICE IF YOU REMOVE THE * CHARACTER FROM "[1-2]*"
        // NO NEED TO CHECK LENGTH it also permited 12 or 11 as valid entry 
        // =================================================================
        if (testText.matches("[1-2]")) {
            intSETonStartController = Integer.parseInt(strSETonStartController);
        }else{
            txtStartValue.setText("Enter 1 OR 2");
            return;
        }

        System.out.println("You Entered = "+intSETonStartController);
        stage = (Stage)startPane.getScene().getWindow();// pane you are ON
        pageonePane = FXMLLoader.load(getClass().getResource("pageone.fxml"));// pane you are GOING TO
        Scene scene = new Scene(pageonePane);// pane you are GOING TO
        stage.setScene(scene);
        stage.setTitle("Page One"); 
        stage.show();
        stage.sizeToScene();
        stage.centerOnScreen();  
}

private void doGET(){
    // Why this testing ?
    // strSENTbackFROMPageoneController is null because it is set on Pageone
    // =====================================================================
    txtStartValue.setText(strSENTbackFROMPageoneController);
    if(intSETonStartController == 1){
      txtStartValue.setText(str);  
    }
    System.out.println("== doGET WAS RUN ==");
    if(txtStartValue.getText() == null){
       txtStartValue.setText("");   
    }
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    // This Method runs every time startController is LOADED
     doGET();
}    
}

Page One Controller

public class PageoneController implements Initializable {

@FXML Pane startPane,pageonePane,pagetwoPane;
@FXML Button btnOne,btnTwo;
@FXML TextField txtPageOneValue;
public static String strSENTbackFROMPageoneController;
public Stage stage;

    @FXML
private void onBTNONE() throws IOException{

        stage = (Stage)pageonePane.getScene().getWindow();// pane you are ON
        pagetwoPane = FXMLLoader.load(getClass().getResource("pagetwo.fxml"));// pane you are GOING TO
        Scene scene = new Scene(pagetwoPane);// pane you are GOING TO
        stage.setScene(scene);
        stage.setTitle("Page Two"); 
        stage.show();
        stage.sizeToScene();
        stage.centerOnScreen();
}

@FXML
private void onBTNTWO() throws IOException{
    if(intSETonStartController == 2){
        Alert alert = new Alert(AlertType.CONFIRMATION);
        alert.setTitle("Alert");
        alert.setHeaderText("YES to change Text Sent Back");
        alert.setResizable(false);
        alert.setContentText("Select YES to send 'Alert YES Pressed' Text Back\n"
                + "\nSelect CANCEL send no Text Back\r");// NOTE this is a Carriage return\r
        ButtonType buttonTypeYes = new ButtonType("YES");
        ButtonType buttonTypeCancel = new ButtonType("CANCEL", ButtonData.CANCEL_CLOSE);

        alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeCancel);

        Optional<ButtonType> result = alert.showAndWait();
        if (result.get() == buttonTypeYes){
            txtPageOneValue.setText("Alert YES Pressed");
        } else {
            System.out.println("canceled");
            txtPageOneValue.setText("");
            onBack();// Optional
        }
    }
}

@FXML
private void onBack() throws IOException{

    strSENTbackFROMPageoneController = txtPageOneValue.getText();
    System.out.println("Text Returned = "+strSENTbackFROMPageoneController);
    stage = (Stage)pageonePane.getScene().getWindow();
    startPane = FXMLLoader.load(getClass().getResource("start.fxml")); 
    Scene scene = new Scene(startPane);
    stage.setScene(scene);
    stage.setTitle("Start Page"); 
    stage.show();
    stage.sizeToScene();
    stage.centerOnScreen(); 
}

private void doTEST(){
    String fromSTART = String.valueOf(intSETonStartController);
    txtPageOneValue.setText("SENT  "+fromSTART);
    if(intSETonStartController == 1){
       btnOne.setVisible(true);
       btnTwo.setVisible(false);
       System.out.println("INTEGER Value Entered = "+intSETonStartController);  
    }else{
       btnOne.setVisible(false);
       btnTwo.setVisible(true);
       System.out.println("INTEGER Value Entered = "+intSETonStartController); 
    }  
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    doTEST();
}    

}

Page deux contrôleur

public class PagetwoController implements Initializable {

@FXML Pane startPane,pagetwoPane;
public Stage stage;
public static String str;

@FXML
private void toStart() throws IOException{

    str = "You ON Page Two";
    stage = (Stage)pagetwoPane.getScene().getWindow();// pane you are ON
    startPane = FXMLLoader.load(getClass().getResource("start.fxml"));// pane you are GOING TO
    Scene scene = new Scene(startPane);// pane you are GOING TO
    stage.setScene(scene);
    stage.setTitle("Start Page"); 
    stage.show();
    stage.sizeToScene();
    stage.centerOnScreen();  
}

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

}    

}

Voici tous les fichiers FXML

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="pagetwoPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="atwopage.PagetwoController">
   <children>
      <Button layoutX="227.0" layoutY="62.0" mnemonicParsing="false" onAction="#toStart" text="To Start Page">
         <font>
            <Font name="System Bold" size="18.0" />
         </font>
      </Button>
   </children>
</AnchorPane>

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="startPane" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="atwopage.startController">
   <children>
      <Label focusTraversable="false" layoutX="115.0" layoutY="47.0" text="This is the Start Pane">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <Button fx:id="btnPageOne" focusTraversable="false" layoutX="137.0" layoutY="100.0" mnemonicParsing="false" onAction="#toPageOne" text="To Page One">
         <font>
            <Font size="18.0" />
         </font>
      </Button>
      <Label focusTraversable="false" layoutX="26.0" layoutY="150.0" text="Enter 1 OR 2">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <TextField fx:id="txtStartValue" layoutX="137.0" layoutY="148.0" prefHeight="28.0" prefWidth="150.0" />
   </children>
</AnchorPane>

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" fx:id="pageonePane" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="atwopage.PageoneController">
   <children>
      <Label focusTraversable="false" layoutX="111.0" layoutY="35.0" text="This is Page One Pane">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <Button focusTraversable="false" layoutX="167.0" layoutY="97.0" mnemonicParsing="false" onAction="#onBack" text="BACK">
         <font>
            <Font size="18.0" />
         </font></Button>
      <Button fx:id="btnOne" focusTraversable="false" layoutX="19.0" layoutY="97.0" mnemonicParsing="false" onAction="#onBTNONE" text="Button One" visible="false">
         <font>
            <Font size="18.0" />
         </font>
      </Button>
      <Button fx:id="btnTwo" focusTraversable="false" layoutX="267.0" layoutY="97.0" mnemonicParsing="false" onAction="#onBTNTWO" text="Button Two">
         <font>
            <Font size="18.0" />
         </font>
      </Button>
      <Label focusTraversable="false" layoutX="19.0" layoutY="152.0" text="Send Anything BACK">
         <font>
            <Font size="18.0" />
         </font>
      </Label>
      <TextField fx:id="txtPageOneValue" layoutX="195.0" layoutY="150.0" prefHeight="28.0" prefWidth="150.0" />
   </children>
</AnchorPane>


3
Je suis désolé, mais publier une centaine de lignes de code sans aucune explication de ce qu'il fait ou pourquoi vous le faites comme vous le faites, n'est pas une très bonne réponse. De plus, le code que vous avez publié est très mal organisé et difficile à suivre.
Zephyr

Il n'est pas nécessaire d'être impoli envers la personne qui demande. Nous sommes tous ici pour apprendre
Zeyad
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.