Passando parâmetros JavaFX FXML

194

Como posso passar parâmetros para uma janela secundária em javafx? Existe uma maneira de se comunicar com o controlador correspondente?

Por exemplo: O usuário escolhe um cliente de uma TableViewe uma nova janela é aberta, mostrando as informações do 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();
    }
}

newStageseria a nova janela. O problema é que não consigo encontrar uma maneira de informar ao controlador onde procurar as informações do cliente (passando o id como parâmetro).

Alguma ideia?

Alvaro
fonte
Verifique se isso também funciona: stackoverflow.com/questions/14370183/…
Dynelight
@ Alvaro: você conseguiu sua solução? você pode passar parâmetro? de um controlador para outro arquivo de controlador?
Java Man
3
Sim. jewelsea deu uma explicação no nível do livro. É por isso que eu aceitei a sua resposta
Alvaro

Respostas:

276

Abordagem recomendada

Esta resposta enumera diferentes mecanismos para passar parâmetros para controladores FXML.

Para pequenas aplicações, eu recomendo passar parâmetros diretamente do chamador para o controlador - é simples, direto e não requer estruturas extras.

Para aplicativos maiores e mais complicados, vale a pena investigar se você deseja usar os mecanismos de Injeção de Dependência ou Barramento de Eventos em seu aplicativo.

Passando parâmetros diretamente do chamador para o controlador

Passe dados customizados para um controlador FXML, recuperando o controlador da instância do carregador FXML e chamando um método no controlador para inicializá-lo com os valores de dados necessários.

Algo como o seguinte código:

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

Um novo FXMLLoader é construído como mostrado no código de exemplo, ie new FXMLLoader(location). O local é um URL e você pode gerar esse URL a partir de um recurso FXML:

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

Cuidado para NÃO usar uma função de carga estática no FXMLLoader, ou você não poderá obter seu controlador da instância do carregador.

As instâncias FXMLLoader nunca sabem nada sobre objetos de domínio. Você não passa diretamente objetos de domínio específicos do aplicativo para o construtor FXMLLoader; em vez disso, você:

  1. Construa um FXMLLoader com base na marcação fxml em um local especificado
  2. Obtenha um controlador da instância FXMLLoader.
  3. Invoque métodos no controlador recuperado para fornecer ao controlador referências aos objetos de domínio.

Este blog (por outro escritor) fornece uma alternativa, mas semelhante, exemplo .

Configurando um controlador no FXMLLoader

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

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

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

Você pode construir um novo controlador no código, passando os parâmetros desejados do seu chamador para o construtor do controlador. Depois de criar um controlador, você pode configurá-lo em uma instância FXMLLoader antes de chamar o método de load() instância .

Para definir um controlador em um carregador (no JavaFX 2.x), você NÃO PODE definir um fx:controlleratributo no seu arquivo fxml.

Devido à limitação da fx:controllerdefinição no FXML, eu pessoalmente prefiro obter o controlador do FXMLLoader do que configurá-lo no FXMLLoader.

Como o controlador recuperar parâmetros de um método estático externo

Este método é exemplificado pela resposta de Sergey ao Javafx 2.0 How-to Application.getParameters () em um arquivo Controller.java .

Usar injeção de dependência

O FXMLLoader suporta sistemas de injeção de dependência como Guice, Spring ou Java EE CDI, permitindo que você defina uma fábrica de controladores personalizados no FXMLLoader. Isso fornece um retorno de chamada que você pode usar para criar a instância do controlador com valores dependentes injetados pelo respectivo sistema de injeção de dependência.

Um exemplo de injeção de dependência de aplicativo e controlador JavaFX com Spring é fornecido na resposta para:

Uma abordagem realmente agradável e limpa de injeção de dependência é exemplificada pela estrutura afterburner.fx com um exemplo de aplicativo de air-hacks que a utiliza. O afterburner.fx depende do JEE6 javax.inject para executar a injeção de dependência.

Use um barramento de eventos

Greg Brown, o criador e implementador original da especificação FXML, geralmente sugere considerar o uso de um barramento de eventos, como o Guava EventBus , para comunicação entre controladores instanciados FXML e outra lógica de aplicativo.

O EventBus é uma API de publicação / assinatura simples, porém poderosa, com anotações que permite que os POJOs se comuniquem entre si em qualquer lugar da JVM sem precisar se referir.

Perguntas e Respostas de acompanhamento

No primeiro método, por que você retorna o Stage? O método também pode ser nulo porque você já está dando o comando show (); pouco antes do estágio de retorno; Como você planeja o uso retornando o Stage

É uma solução funcional para um problema. Um estágio é retornado da showCustomerDialogfunção para que uma referência a ele possa ser armazenada por uma classe externa que deseje fazer algo, como ocultar o estágio com base em um clique no botão na janela principal, posteriormente. Uma solução alternativa orientada a objeto pode encapsular a funcionalidade e a referência de estágio dentro de um objeto CustomerDialog ou fazer com que um CustomerDialog estenda o Stage. Um exemplo completo de uma interface orientada a objetos para uma caixa de diálogo personalizada que encapsula dados de FXML, controlador e modelo está além do escopo desta resposta, mas pode fazer uma publicação interessante no blog para qualquer pessoa que queira criar uma.


Informações adicionais fornecidas pelo usuário StackOverflow chamado @dzim

Exemplo de injeção de dependência de inicialização de primavera

A questão de como fazê-lo "The Spring Boot Way", houve uma discussão sobre JavaFX 2, que eu respondi no link permanente em anexo. A abordagem ainda é válida e testada em março de 2016, no Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


Às vezes, convém passar os resultados de volta para o chamador, nesse caso, você pode conferir a resposta para a pergunta relacionada:

jewelsea
fonte
Os construtores FXMLLoader usam apenas URLs como parâmetros. Qual é a maneira correta de instanciar o FXMLLoader?
Alvaro
1
o site do barramento de eventos aludiu aos estados: "Atualização 3/2013: o EventBus ficou obsoleto ..."
j será
1
O DataFX Controlador Frameworks fornece algum suporte injeção para controladores FXML: guigarage.com/2013/12/datafx-controller-framework-preview
Hendrik Ebbers
2
Adicionada seção de perguntas e respostas adicionais para responder a outras perguntas de @Anarkie
jewelsea
7
para godshake, existe algo simples para fazer esse pequeno trabalho em JavaFx? é um recurso muito comum para passar dados no construtor e no javafx requer essas coisas todas juntas apenas para enviar um nome ou um valor?
Zahan Safallwa
13

Percebo que este é um post muito antigo e já tem ótimas respostas, mas eu queria fazer um simples MCVE para demonstrar uma dessas abordagens e permitir que os novos codificadores pudessem ver rapidamente o conceito em ação.

Neste exemplo, usaremos 5 arquivos:

  1. Main.java - Simplesmente usado para iniciar o aplicativo e chamar o primeiro controlador.
  2. Controller1.java - O controlador para o primeiro layout FXML.
  3. Controller2.java - O controlador para o segundo layout FXML.
  4. Layout1.fxml - O layout FXML da primeira cena.
  5. Layout2.fxml - O layout FXML da segunda cena.

Todos os arquivos estão listados na íntegra na parte inferior desta postagem.

O Objectivo: Para demonstrar que passa valores de Controller1a Controller2e vice-versa.

O fluxo do programa:

  • A primeira cena contém a TextField, a Buttone a Label. Quando Buttonclica em, a segunda janela é carregada e exibida, incluindo o texto digitado no TextField.
  • Dentro da segunda cena, há também a TextField, a Buttone a Label. O Labelirá exibir o texto inserido no TextFieldna primeira cena.
  • Ao inserir o texto na segunda cena TextFielde clicar nela Button, a primeira cena Labelé atualizada para mostrar o texto inserido.

Esta é uma demonstração muito simples e certamente pode significar alguma melhoria, mas deve tornar o conceito muito claro.

O código em si também é comentado com alguns detalhes do que está acontecendo e como.

O CÓDIGO

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>
Zephyr
fonte
1
É possível definir o controlador no arquivo FXML? Beause remover a linha: loader.setController(this)e adicionar o controlador no arquivo FXML trava o aplicativo
Halfacht 20/18
1
Não se o FXML for carregado de dentro do próprio controlador. Se você carregar o FXML da classe Main, por exemplo, poderá definir o controlador no arquivo FXML e obter uma referência a ele usandoloader.getController()
Zephyr
Finalmente consegui encontrar uma solução, ótimo exemplo. Eu o implementei no meu projeto e agora estou tentando abrir as duas janelas simultaneamente e torná-las modais. Infelizmente, apenas um é aberto. Alguém poderia ajudar com isso?
jabba 5/02
8

A classe javafx.scene.Node possui um par de métodos setUserData (Object) e Object getUserData ()

Que você pode usar para adicionar suas informações ao nó.

Então, você pode chamar page.setUserData (info);

E o controlador pode verificar se as informações estão definidas. Além disso, você pode usar o ObjectProperty para transferência de dados de retrocesso, se necessário.

Observe uma documentação aqui: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Antes da frase "Na primeira versão, o handleButtonAction () é marcado com @FXML para permitir que a marcação definida no documento do controlador a invoque. No segundo exemplo, o campo do botão é anotado para permitir que o carregador defina seu valor. O método initialize () é anotado da mesma forma. "

Portanto, você precisa associar um controlador a um nó e configurar os dados do usuário para o nó.

Alexander Kirov
fonte
Stage.getScene () -> Scene.getRoot () -> pesquisa recursiva com Parent.getChildrenUnmodifiable (). Esta é uma maneira muito suja. Se alguém puder sugerir algo melhor - isso será ótimo.
Alexander Kirov
Parece que Stage.getScene (). GetRoot () é a maneira correta! Graças
Alvaro
7

Aqui está um exemplo para passar parâmetros para um documento fxml através do 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>

Defina o valor External Textpara a variável de espaço para nome 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();
    }
}
user1503636
fonte
Deve-se notar que algumas teclas são usadas internamente: por exemplo FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYe qualquer seqüência usado como valor para o fx:idatributo.
Fabian
Obrigado por isso, minha outra cena é apenas um contêiner que mostra o texto mostrado anteriormente na minha cena principal. Agora eu posso ter um fxml que posso reutilizar em vários locais, inicializando o conteúdo por meio de variáveis ​​do espaço de nome. Não precisei criar novos métodos ou alterar meu construtor ou inicializadores - basta adicionar uma variável no meu FXML e adicionar uma linha ao meu código fxmloader no controlador principal.
SystemsInCode 28/10
4

Isso funciona ..

Lembre-se da primeira vez que imprimir o valor que passa, você será nulo. Você pode usá-lo após o carregamento do Windows, o mesmo para tudo o que você deseja codificar para qualquer outro componente.

Primeiro Controlador

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

Outro controlador

public void initVariable(Long id_usuario){
    this.id_usuario = id_usuario;
    label_usuario_nombre.setText(id_usuario.toString());
}
diego matos - keke
fonte
1
Este trabalho quando você passa o parâmetro do primeiro controlador para o segundo, mas como passar o parâmetro do segundo para o primeiro controlador, quero dizer, depois que o first.fxml foi carregado.
Menai Ala Eddine - Aladdin
@XlintXms veja a pergunta relacionada Parâmetro JavaFX FXML passando do controlador A para B e vice-versa , que aborda sua pergunta adicional.
Jewelsea
2

Você precisa criar uma classe de contexto.

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

Você precisa apenas definir a instância do controlador na inicialização usando

Context.getInstance().setTabRough(this);

e você pode usá-lo em todo o aplicativo usando apenas

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

Agora você pode passar parâmetros para qualquer controlador de todo o aplicativo.

CTN
fonte
Usamos essa abordagem e funciona muito bem. Eu gosto que eu tenho acesso aos dados dentro do construtor ou do método de inicialização e eu não tenho para definir os dados no controlador após ele é construído
Bob
1

Sim você pode.
Você precisa adicionar o primeiro controlador:

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

Em seguida, no segundo, declare um cliente e, em seguida, na parte inferior do seu controlador:

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

Aqui está um exemplo para usar um controlador injetado pelo 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;
}

Aqui está uma implementação concreta do carregador:

public class ConcreteViewLoader extends GuiceFxmlLoader {

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

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

Observe que este exemplo carrega a vista no centro de um BoarderPane que é a raiz da cena no palco. Isso é irrelevante para o exemplo (detalhes de implementação do meu caso de uso específico), mas decidiu deixá-lo como alguns podem achar útil.

jenglert
fonte
-1

Você pode optar por usar uma lista pública observável para armazenar dados públicos ou apenas criar um método setter público para armazenar dados e recuperar do controlador correspondente

Nospaniol Noah
fonte
-3

Por que responder a uma pergunta de 6 anos?
Um dos conceitos mais fundamentais do trabalho com qualquer linguagem de programação é como navegar de um (janela, formulário ou página) para outro. Além disso, ao fazer essa navegação, o desenvolvedor geralmente deseja passar dados de uma (janela, formulário ou página) e exibir ou usar os dados transmitidos.
Embora a maioria das respostas aqui forneça exemplos bons ou excelentes de como fazer isso, pensamos que seria necessário aumentá-los. um ponto ou dois ou três
Dissemos três porque navegaremos entre três (janela, formulário ou página) e usaremos o conceito de variáveis ​​estáticas para passar dados (janela, formulário ou página)
. Também incluiremos algum código de tomada de decisão enquanto nós navegamos

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

Iniciar controlador

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

Controlador Page One

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

}

Controlador da página dois

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

}    

}

Abaixo estão todos os arquivos 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>

Vetor
fonte
3
Sinto muito, mas postar centenas de linhas de código sem nenhuma explicação do que faz ou por que você faz do jeito que faz, não é uma resposta muito boa. Além disso, o código que você postou é muito mal organizado e difícil de seguir.
Zephyr
Não há necessidade de ser rude com a pessoa que pergunta. Estamos todos aqui para aprender
Zeyad