Passando i parametri JavaFX FXML


195

Come posso passare i parametri a una finestra secondaria in javafx? C'è un modo per comunicare con il controller corrispondente?

Ad esempio: l'utente sceglie un cliente da a TableViewe viene aperta una nuova finestra, che mostra le informazioni del cliente.

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

newStagesarebbe la nuova finestra. Il problema è che non riesco a trovare un modo per dire al controller dove cercare le informazioni del cliente (passando l'id come parametro).

Qualche idea?


Controllare per vedere se questo funziona anche: stackoverflow.com/questions/14370183/...
Dynelight

@Alvaro: hai preso la tua soluzione? puoi passare il parametro? da un controller a un altro file controller?
Java Man

3
Sì. jewelsea ha fornito una spiegazione a livello di libro. Ecco perché ho accettato la sua risposta
Alvaro il

Risposte:


277

Approccio raccomandato

Questa risposta elenca diversi meccanismi per il passaggio dei parametri ai controller FXML.

Per le piccole applicazioni consiglio vivamente di passare i parametri direttamente dal chiamante al controller: è semplice, diretto e non richiede framework aggiuntivi.

Per applicazioni più grandi e complicate, varrebbe la pena indagare se si desidera utilizzare i meccanismi di iniezione di dipendenza o bus di eventi all'interno dell'applicazione.

Passare i parametri direttamente dal chiamante al controller

Passare i dati personalizzati a un controller FXML recuperando il controller dall'istanza del caricatore FXML e chiamando un metodo sul controller per inizializzarlo con i valori dei dati richiesti.

Qualcosa come il seguente codice:

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 nuovo FXMLLoader è costruito come mostrato nel codice di esempio ie new FXMLLoader(location). La posizione è un URL e puoi generare tale URL da una risorsa FXML:

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

Fare attenzione a NON utilizzare una funzione di caricamento statico su FXMLLoader, altrimenti non sarà possibile ottenere il controller dall'istanza del caricatore.

Le stesse istanze di FXMLLoader non sanno mai nulla sugli oggetti di dominio. Non passi direttamente oggetti di dominio specifici dell'applicazione nel costruttore FXMLLoader, invece:

  1. Costruisci un FXMLLoader basato sul markup fxml in una posizione specificata
  2. Ottieni un controller dall'istanza FXMLLoader.
  3. Richiamare i metodi sul controller recuperato per fornire al controller riferimenti agli oggetti del dominio.

Questo blog (da un altro scrittore) fornisce un supplente, ma simile, ad esempio .

Impostazione di un controller sul FXMLLoader

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

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

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

È possibile costruire un nuovo controller nel codice, passando tutti i parametri desiderati dal chiamante al costruttore del controller. Dopo aver creato un controller, è possibile impostarlo su un'istanza FXMLLoader prima di richiamare il metodo load() dell'istanza .

Per impostare un controller su un caricatore (in JavaFX 2.x) NON PUOI fx:controllernemmeno definire un attributo nel tuo file fxml.

A causa della limitazione della fx:controllerdefinizione in FXML, personalmente preferisco ottenere il controller da FXMLLoader piuttosto che impostare il controller in FXMLLoader.

Avere il controller recuperare i parametri da un metodo statico esterno

Questo metodo è esemplificato dalla risposta di Sergey a Javafx 2.0 How-to Application.getParameters () in un file Controller.java .

Usa iniezione di dipendenza

FXMLLoader supporta i sistemi di iniezione di dipendenza come Guice, Spring o Java EE CDI consentendo di impostare una fabbrica di controller personalizzati su FXMLLoader. Ciò fornisce un callback che è possibile utilizzare per creare l'istanza del controller con valori dipendenti iniettati dal rispettivo sistema di iniezione delle dipendenze.

Un esempio di iniezione di dipendenza da controller e applicazione JavaFX con Spring è fornito nella risposta a:

Un approccio di iniezione di dipendenza davvero piacevole e pulito è esemplificato dal framework afterburner.fx con un'applicazione air-hack di esempio che lo utilizza. afterburner.fx si affida a JEE6 javax.inject per eseguire l'iniezione di dipendenza.

Usa un bus eventi

Greg Brown, il creatore e implementatore della specifica FXML originale, suggerisce spesso di prendere in considerazione l'uso di un bus di eventi, come Guava EventBus , per la comunicazione tra controller istanziati FXML e altre logiche applicative.

EventBus è un'API di pubblicazione / sottoscrizione semplice ma potente con annotazioni che consente ai POJO di comunicare tra loro ovunque in una JVM senza dover fare riferimento l'uno all'altro.

Domande e risposte di follow-up

sul primo metodo, perché restituisci Stage? Il metodo può essere nullo anche perché stai già dando il comando show (); appena prima della fase di ritorno ;. Come si pianifica l'utilizzo restituendo lo stage

È una soluzione funzionale a un problema. Uno stage viene restituito dalla showCustomerDialogfunzione in modo che un riferimento ad esso possa essere memorizzato da una classe esterna che potrebbe voler fare qualcosa, come nascondere lo stage in base a un clic del pulsante nella finestra principale, in un secondo momento. Una soluzione alternativa orientata agli oggetti potrebbe incapsulare la funzionalità e il riferimento dello stage all'interno di un oggetto CustomerDialog o far estendere lo stage a CustomerDialog. Un esempio completo di un'interfaccia orientata agli oggetti a una finestra di dialogo personalizzata che incapsula FXML, i controller e i dati del modello va oltre lo scopo di questa risposta, ma può rendere utile un post sul blog per chiunque sia incline a crearne uno.


Informazioni aggiuntive fornite dall'utente StackOverflow chiamato @dzim

Esempio di Spring Boot Dependency Injection

Alla domanda su come farlo "The Spring Boot Way", c'è stata una discussione su JavaFX 2, a cui ho risposto nel permalink allegato. L'approccio è ancora valido e testato a marzo 2016, su Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


A volte, potresti voler restituire i risultati al chiamante, nel qual caso puoi controllare la risposta alla domanda correlata:


I costruttori di FXMLLoader accettano solo gli URL come parametri. Qual è il modo corretto di creare un'istanza di FXMLLoader?
Alvaro,

1
il sito web del bus degli eventi allude agli stati, "Aggiornamento 3/2013: EventBus è diventato stantio ..."
j

1
Il DataFX Controller Frameworks fornisce un supporto di iniezione per i controller FXML
Hendrik Ebbers

2
Aggiunta ulteriore sezione Domande e risposte per rispondere alle ulteriori domande di @Anarkie
jewelsea

7
per godshake c'è qualcosa di semplice per fare questo piccolo lavoro in JavaFx? è una caratteristica molto comune passare dati nel costruttore e javafx richiede questo inferno di cose tutte insieme solo per inviare un nome o un valore?
Zahan Safallwa,

13

Mi rendo conto che questo è un post molto vecchio e ha già delle ottime risposte, ma volevo creare un semplice MCVE per dimostrare un tale approccio e consentire ai nuovi programmatori un modo per vedere rapidamente il concetto in azione.

In questo esempio, utilizzeremo 5 file:

  1. Main.java - Utilizzato semplicemente per avviare l'applicazione e chiamare il primo controller.
  2. Controller1.java - Il controller per il primo layout FXML.
  3. Controller2.java - Il controller per il secondo layout FXML.
  4. Layout1.fxml - Il layout FXML per la prima scena.
  5. Layout2.fxml - Il layout FXML per la seconda scena.

Tutti i file sono elencati nella loro interezza nella parte inferiore di questo post.

L'obiettivo: Per dimostrare il passaggio di valori da Controller1a Controller2e viceversa.

Il flusso del programma:

  • La prima scena contiene a TextField, a Buttone a Label. Quando si Buttonfa clic su, la seconda finestra viene caricata e visualizzata, incluso il testo inserito in TextField.
  • All'interno della seconda scena, ci sono anche a TextField, a Buttone a Label. Il Labelvisualizzerà il testo inserito nel TextFieldsulla prima scena.
  • Inserendo il testo nella seconda scena TextFielde facendo clic su di essa Button, la prima scena Labelviene aggiornata per mostrare il testo inserito.

Questa è una dimostrazione molto semplice e potrebbe sicuramente rappresentare un miglioramento, ma dovrebbe chiarire il concetto.

Il codice stesso è anche commentato con alcuni dettagli di ciò che sta accadendo e come.

IL CODICE

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
È possibile impostare il controller nel file FXML? Perché rimuovere la linea: loader.setController(this)e l'aggiunta del controller nel file FXML provoca l'arresto anomalo dell'applicazione
Halfacht

1
Non se FXML è caricato dall'interno del controller stesso. Se si carica FXML dalla classe Main, ad esempio, è possibile definire il controller nel file FXML e ottenere un riferimento ad esso utilizzandoloader.getController()
Zephyr

Finalmente sono riuscito a trovare una soluzione, ottimo esempio. L'ho implementato nel mio progetto e ora sto cercando di aprire entrambe le finestre contemporaneamente e renderle prima modali. Purtroppo solo uno si apre. Qualcuno potrebbe aiutarci?
Jabba,

8

La classe javafx.scene.Node ha una coppia di metodi setUserData (Object) e Object getUserData ()

Che è possibile utilizzare per aggiungere le informazioni al nodo.

Quindi, puoi chiamare page.setUserData (informazioni);

E il controller può verificare se le informazioni sono impostate. Inoltre, è possibile utilizzare ObjectProperty per il trasferimento indietro dei dati, se necessario.

Osservare una documentazione qui: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Prima della frase "Nella prima versione, handleButtonAction () è taggato con @FXML per consentire al markup definito nel documento del controller di richiamarlo. Nel secondo esempio, il campo pulsante è annotato per consentire al caricatore di impostarne il valore. Il metodo initialize () è analogamente annotato. "

Pertanto, è necessario associare un controller a un nodo e impostare i dati utente sul nodo.


Stage.getScene () -> Scene.getRoot () -> ricerca ricorsiva con Parent.getChildrenUnmodifiable (). Questo è un modo molto sporco. Se qualcuno potesse suggerire di meglio, sarebbe fantastico.
Alexander Kirov

Sembra Stage.getScene (). GetRoot () è il modo corretto! Grazie
Alvaro,

7

Ecco un esempio per il passaggio di parametri a un documento fxml attraverso lo spazio dei nomi.

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

Definire il valore External Textper la variabile dello spazio dei nomi 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();
    }
}

Va notato che alcuni tasti vengono utilizzati internamente: per esempio FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYe qualsiasi stringa utilizzata come valore per l' fx:idattributo.
fabian,

Grazie a questo, l'altra mia scena è solo un contenitore che mostra il testo precedentemente mostrato sulla mia scena principale. Ora posso avere un fxml che posso riutilizzare in più punti inizializzando il contenuto tramite le variabili Namepace. Non ho dovuto creare nuovi metodi o modificare il mio costruttore o initalizzatori - basta aggiungere una variabile nel mio FXML e aggiungere una riga nel mio codice fxmloader nel controller principale.
SystemsInCode,

4

Funziona ..

Ricorda che la prima volta che stampi il valore che passa otterrai null, puoi usarlo dopo aver caricato Windows, lo stesso per tutto ciò che vuoi codificare per qualsiasi altro componente.

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

Un altro controller

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

1
Questo funziona quando passi i parametri dal primo controller al secondo ma come passare i parametri dal secondo al primo controller, intendo dopo che è stato caricato first.fxml.
Menai Ala Eddine - Aladdin,

@XlintXms visualizza la domanda correlata Parametro FXF JavaFX che passa dal controller A a B e viceversa , che risponde alla domanda aggiuntiva.
jewelsea

2

Devi creare una classe di contesto.

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

Devi solo impostare l'istanza del controller nell'inizializzazione usando

Context.getInstance().setTabRough(this);

e puoi usarlo da tutta la tua applicazione semplicemente usando

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

Ora puoi passare i parametri a qualsiasi controller dall'intera applicazione.


Usiamo questo approccio e funziona benissimo. Mi piace avere accesso ai dati all'interno del costruttore o nel metodo di inizializzazione e non devo impostare i dati nel controller dopo che è stato costruito
Bob

2

Si, puoi.
Devi aggiungere nel primo controller:

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

Quindi nel secondo dichiarare un client, quindi nella parte inferiore del controller:

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

0

Ecco un esempio per l'utilizzo di un controller iniettato da 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;
}

Ecco un'implementazione concreta del caricatore:

public class ConcreteViewLoader extends GuiceFxmlLoader {

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

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

Nota questo esempio carica la vista al centro di BoarderPane che è la radice della scena nello stage. Questo è irrilevante per l'esempio (dettagli di implementazione del mio caso d'uso specifico) ma ho deciso di lasciarlo in quanto alcuni potrebbero trovarlo utile.


-1

Puoi decidere di utilizzare un elenco osservabile pubblico per archiviare dati pubblici o semplicemente creare un metodo di impostazione pubblica per archiviare i dati e recuperarli dal controller corrispondente


-3

Perché rispondere a una domanda di 6 anni?
Uno dei concetti più fondamentali che lavorano con qualsiasi linguaggio di programmazione è come spostarsi da uno (finestra, modulo o pagina) a un altro. Inoltre durante questa navigazione lo sviluppatore spesso desidera passare i dati da uno (finestra, modulo o pagina) e visualizzare o utilizzare i dati passati
Mentre la maggior parte delle risposte qui fornisce esempi eccellenti su come realizzare ciò, abbiamo pensato che avremmo iniziato una tacca o due o tre
Abbiamo detto tre perché navigheremo tra tre (finestra, modulo o pagina) e useremo il concetto di variabili statiche per passare i dati intorno a (finestra, modulo o pagina)
Includeremo anche un codice decisionale mentre noi navighiamo

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

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

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

}

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

}    

}

Di seguito sono riportati tutti i file 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>


4
Mi dispiace, ma pubblicare un centinaio di righe di codice senza alcuna spiegazione di ciò che fa o del perché lo fai nel modo in cui lo fai, non è una risposta molto buona. Inoltre, il codice che hai pubblicato è molto mal organizzato e difficile da seguire.
Zefiro,

1
Non è necessario essere scortesi con l'interrogante. Siamo tutti qui per imparare
Zeyad,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.