web-dev-qa-db-ger.com

Übergabe der Parameter JavaFX FXML

Wie kann ich Parameter an ein sekundäres Fenster in Javafx übergeben? Gibt es eine Möglichkeit, mit der entsprechenden Steuerung zu kommunizieren?

Beispiel: Der Benutzer wählt einen Kunden aus einer TableView aus und ein neues Fenster wird geöffnet, in dem die Informationen des Kunden angezeigt werden.

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

newStage wäre das neue Fenster. Das Problem ist, ich finde keine Möglichkeit, dem Controller mitzuteilen, wo er nach Informationen des Kunden suchen muss (durch Übergeben der ID als Parameter).

Irgendwelche Ideen?

162
Alvaro

Empfohlener Ansatz

In dieser Antwort werden verschiedene Mechanismen zum Übergeben von Parametern an FXML-Controller aufgelistet.

Für kleine Anwendungen empfehle ich dringend, Parameter direkt vom Aufrufer an die Steuerung zu übergeben. Dies ist einfach, unkompliziert und erfordert keine zusätzlichen Rahmenbedingungen. 

Für größere, kompliziertere Anwendungen wäre es sinnvoll zu untersuchen, ob Sie in Ihrer Anwendung Abhängigkeitsinjektions oder Ereignisbus - Mechanismen verwenden möchten.

Parameter direkt vom Anrufer an die Steuerung übergeben

Übergeben Sie benutzerdefinierte Daten an einen FXML-Controller, indem Sie den Controller von der FXML-Loader-Instanz abrufen und eine Methode auf dem Controller aufrufen, um sie mit den erforderlichen Datenwerten zu initialisieren.

Etwas wie der folgende Code:

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

Ein neuer FXMLLoader ist wie im Beispielcode gezeigt aufgebaut, d. H. new FXMLLoader(location). Der Speicherort ist eine URL. Sie können eine solche URL aus einer FXML-Ressource generieren, indem Sie:

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

Verwenden Sie KEINE statische Ladefunktion für den FXMLLoader. Andernfalls können Sie Ihren Controller nicht von Ihrer Loader-Instanz abrufen.

FXMLLoader-Instanzen selbst wissen nie etwas über Domänenobjekte. Sie übergeben anwendungsspezifische Domänenobjekte nicht direkt an den FXMLLoader-Konstruktor. Stattdessen führen Sie Folgendes aus:

  1. Konstruieren Sie einen FXMLLoader basierend auf einem fxml-Markup an einem angegebenen Ort
  2. Rufen Sie einen Controller von der FXMLLoader-Instanz ab.
  3. Rufen Sie Methoden auf dem abgerufenen Controller auf, um dem Controller Referenzen auf die Domänenobjekte bereitzustellen.

Dieses Blog (von einem anderen Autor) bietet ein alternatives, aber ähnliches Beispiel .

Controller am FXMLLoader einstellen

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

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

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

Sie können einen neuen Controller im Code erstellen und beliebige Parameter Ihres Aufrufers an den Controller-Konstruktor übergeben. Nachdem Sie einen Controller erstellt haben, können Sie ihn in eine FXMLLoader-Instanz vor setzen, in der Sie die load()Instanz-Methode aufrufen.

Um einen Controller auf einem Loader (in JavaFX 2.x) festzulegen, KÖNNEN Sie NICHT ein fx:controller-Attribut in Ihrer fxml-Datei definieren.

Aufgrund der Einschränkung der fx:controller-Definition in FXML ziehe ich es persönlich vor, den Controller vom FXMLLoader zu bekommen, anstatt den Controller im FXMLLoader zu installieren.

Der Controller muss Parameter von einer externen statischen Methode abrufen

Diese Methode wird durch die Antwort von Sergej auf Javafx 2.0 How-to Application.getParameters () in einer Controller.Java-Datei veranschaulicht.

Abhängigkeitsinjektion verwenden

FXMLLoader unterstützt Abhängigkeitseinspritzsysteme wie Guice, Spring oder Java EE CDI, indem Sie eine benutzerdefinierte Controller-Factory für den FXMLLoader festlegen. Dies bietet einen Rückruf, mit dem Sie die Controller-Instanz mit abhängigen Werten erstellen können, die vom jeweiligen Abhängigkeitseinspritzsystem eingefügt werden. Es gibt ein Beispiel für die Integration von FXML mit dem Spring-Abhängigkeits-Injektionssystem (Leider ist der Link deaktiviert und der Inhalt ist verschwunden. Wenn jemand ein ähnliches Beispiel kennt, bearbeiten Sie bitte diese Frage, um darauf zu verweisen), obwohl es ein bisschen ist Die Verwendung der neuen, in JavaFX 2.2 zur Verfügung gestellten Funktionen der benutzerdefinierten Controllerfabrik ist umso unübersichtlicher.

Eine wirklich schöne, saubere Abhängigkeitseinspritzung wird durch das afterburner.fx-Framework mit einer Sample Air-Hacks-Anwendung - veranschaulicht, das/es verwendet. afterburner.fx setzt zur Durchführung der Abhängigkeitsinjektion auf JEE6/- javax.inject .

Event-Bus verwenden

Greg Brown, der ursprüngliche Ersteller und Implementierer der FXML-Spezifikation, empfiehlt häufig die Verwendung eines Ereignisbusses für die Kommunikation zwischen FXML-instanziierten Controllern und anderer Anwendungslogik.

Der EventBus ist eine einfache, aber leistungsstarke Publish/Subscribe-API mit Anmerkungen, die es POJOs ermöglicht, an einer beliebigen Stelle in einer JVM miteinander zu kommunizieren, ohne auf einander Bezug nehmen zu müssen. 

Follow-up-Fragen und Antworten

warum kehren Sie bei der ersten Methode zurück? Die Methode kann auch ungültig sein, da Sie bereits den Befehl show () gegeben haben. kurz vor der Rückkehrphase ;. Wie planen Sie die Nutzung, indem Sie die Bühne zurückgeben?

Es ist eine funktionale Lösung für ein Problem. Eine Stufe wird von der showCustomerDialog-Funktion zurückgegeben, sodass eine Referenz darauf von einer externen Klasse gespeichert werden kann, die möglicherweise etwas tun möchte, z. B. die Stufe basierend auf einem Klicken der Schaltflächen im Hauptfenster zu einem späteren Zeitpunkt ausblenden. Eine alternative, objektorientierte Lösung könnte die Funktionalität und die Stufenreferenz in einem CustomerDialog-Objekt einkapseln oder die Stufe eines KundenDialogs erweitern. Ein vollständiges Beispiel für eine objektorientierte Schnittstelle zu einem benutzerdefinierten Dialogfeld, in dem FXML-, Controller- und Modelldaten enthalten sind, würde den Rahmen dieser Antwort sprengen, kann jedoch für jeden, der dazu neigt, einen zu erstellen, einen lohnenden Blogpost machen.Zusätzliche Informationen, die vom StackOverflow-Benutzer mit dem Namen @dzim bereitgestellt werden.


Beispiel für Spring Boot Dependency Injection

Bei der Frage nach dem "The Spring Boot Way" gab es eine Diskussion über JavaFX 2, die ich im angefügten Permalink ..__ beantwortete. Der Ansatz ist noch gültig und wurde im März 2016 auf Spring Boot v1.3.3 getestet .RELEASE: https://stackoverflow.com/a/36310391/1281217

Manchmal möchten Sie möglicherweise die Ergebnisse an den Anrufer zurückgeben. In diesem Fall können Sie die Antwort auf die zugehörige Frage überprüfen:


JavaFX FXML Parameterübergabe von Controller A nach B und zurück

233
jewelsea

die Klasse javafx.scene.Node verfügt über ein Methodenpaar setUserData (Object) und Object getUserData ()

Damit könnten Sie Ihre Informationen zum Knoten hinzufügen.

Sie können also page.setUserData (info) aufrufen.

Der Controller kann überprüfen, ob Informationen eingestellt sind. Bei Bedarf können Sie auch ObjectProperty für die Datenübertragung vorwärts verwenden.

Eine Dokumentation finden Sie hier: http://docs.Oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Vor dem Satz "In der ersten Version Das handleButtonAction () ist mit @FXML gekennzeichnet, damit Markup im Dokument des Controllers aufgerufen werden kann. Im zweiten Beispiel wird das Schaltflächenfeld mit Anmerkungen versehen, damit der Loader seinen Wert festlegen kann. Die Methode initialize () wird ebenfalls mit Anmerkungen versehen. "

Sie müssen also einen Controller einem Knoten zuordnen und dem Knoten Benutzerdaten zuweisen.

8
Alexander Kirov

Hier ist ein Beispiel für die Übergabe von Parametern an ein fxml-Dokument über den Namespace.

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

Definieren Sie den Wert External Text für die Namensraumvariable 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();
    }
}
7
user1503636

Mir ist klar, dass dies ein sehr alter Beitrag ist und bereits einige großartige Antworten enthält. Ich wollte jedoch einen einfachen MCVE erstellen, um einen solchen Ansatz zu demonstrieren und neuen Codierern eine Möglichkeit zu geben, das Konzept schnell in Aktion zu sehen.

In diesem Beispiel verwenden wir 5 Dateien:

  1. Main.Java - Wird einfach zum Starten der Anwendung und zum Aufrufen des ersten Controllers verwendet.
  2. Controller1.Java - Der Controller für das erste FXML-Layout.
  3. Controller2.Java - Der Controller für das zweite FXML-Layout.
  4. Layout1.fxml - Das FXML-Layout für die erste Szene.
  5. Layout2.fxml - Das FXML-Layout für die zweite Szene.

Alle Dateien sind vollständig in diesem Beitrag aufgelistet.

Das Ziel: Demonstration der Übergabe von Werten von Controller1 an Controller2 und umgekehrt.

Der Programmablauf:

  • Die erste Szene enthält eine TextField, eine Button und eine Label. Wenn Sie auf Button klicken, wird das zweite Fenster geladen und angezeigt, einschließlich des in TextField eingegebenen Textes.
  • In der zweiten Szene gibt es auch eine TextField, eine Button und eine Label. Die Variable Label zeigt den in der Variable TextField eingegebenen Text der ersten Szene an.
  • Beim Eingeben von Text in die TextField der zweiten Szene und Klicken auf ihre Button wird die Label der ersten Szene aktualisiert, um den eingegebenen Text anzuzeigen.

Dies ist eine sehr einfache Demonstration und könnte sicherlich für einige Verbesserungen stehen, sollte aber das Konzept sehr klar machen.

Der Code selbst wird auch mit einigen Details dazu erklärt, was passiert und wie.

DER 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>
7
Zephyr

Das funktioniert ..

Denken Sie daran, dass Sie beim ersten Ausdruck des übergebenen Werts den Wert null erhalten, Sie können ihn nach dem Laden Ihres Fensters verwenden. Gleiches gilt für alles, was Sie für andere Komponenten codieren möchten.

Erster Controller

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

Ein weiterer Controller

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

    }
3

Sie müssen eine Kontextklasse erstellen.

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

Sie müssen nur die Instanz des Controllers mit initialisieren

Context.getInstance().setTabRough(this);

und Sie können es von Ihrer gesamten Anwendung verwenden, einfach mit

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

Jetzt können Sie Parameter von der gesamten Anwendung an jeden Controller übergeben.

2
CTN

Ich habe eine viel einfachere Methode, eine Instanz der Klasse mit der Initialize-Methode zu erstellen. Ich suchte mehrere Tage im Internet, bis ich diese wirklich einfache Methode fand. 

Deklarieren Sie eine Instanz Ihrer Klasse:

// Die für die Instanz der Hauptklasse verwendete Variable einrichten

private static FXMLController instance;

Deklarieren Sie Ihre Klasse wie folgt:

public class FXMLController implements Initializable {

Richten Sie eine Methode in Ihrer Klasse wie folgt ein:

public void mainController() {
    instance = this;
}

Rufen Sie dann die Methode in der Initialisierungsmethode auf:

@Override // this method is ran when first showing the main window
public void initialize(URL location, ResourceBundle resources) {
     // initialize the instance of this class so it can be shared across controllers
     mainController();
}
1
Jeremy

Ja, Sie können den ersten Controller hinzufügen 

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

dann im zweiten deklarieren sie einen client dann am ende ihres controller:

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

Hier ist ein Beispiel für die Verwendung eines von Guice eingespeisten Controllers.

/**
 * 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;
}

Hier ist eine konkrete Implementierung des Laders:

public class ConcreteViewLoader extends GuiceFxmlLoader {

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

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

Beachten Sie, dass dieses Beispiel die Ansicht in die Mitte eines BoarderPane lädt, das der Wurzel der Szene auf der Bühne ist. Dies ist für das Beispiel (Implementierungsdetail meines speziellen Anwendungsfalls) irrelevant, entschied sich jedoch, es zu belassen, da einige es nützlich finden könnten.

0
jenglert

Sie können sich entscheiden, eine öffentliche beobachtbare Liste zum Speichern öffentlicher Daten zu verwenden, oder Sie erstellen einfach eine öffentliche Setter-Methode, um Daten zu speichern und vom entsprechenden Controller abzurufen

0
Nospaniol Noah

Warum eine 6 Jahre alte Frage beantworten?
Eines der grundlegendsten Konzepte für die Arbeit mit einer Programmiersprache ist die Navigation von einem (Fenster, Formular oder Seite) zum anderen. Auch während dieser Navigation möchte der Entwickler häufig Daten von einem (Fenster, Formular oder Seite) übergeben und die übergebenen Daten anzeigen oder verwenden
Während die meisten Antworten hier gute bis exzellente Beispiele dafür liefern, dachten wir, wir würden es noch ein oder zwei oder drei Schritte weiter bringen
Wir sagten drei, weil wir zwischen drei (Fenster, Formular oder Seite) navigieren und das Konzept der statischen Variablen verwenden, um Daten im (Fenster, Formular oder Seite) zu übertragen.
Während der Navigation werden wir auch Code für die Entscheidungsfindung einfügen

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

Starten Sie den Controller

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

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

}

Seite Zwei Controller

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) {

}    

}

Nachfolgend finden Sie alle FXML-Dateien

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