Передача параметров JavaFX FXML

195

Как я могу передать параметры во вторичное окно в javafx? Есть ли способ связи с соответствующим контроллером?

Например: пользователь выбирает клиента из списка, TableViewи открывается новое окно с информацией о клиенте.

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будет новое окно. Проблема в том, что я не могу найти способ сообщить контроллеру, где искать информацию о клиенте (передавая id в качестве параметра).

Любые идеи?

Alvaro
источник
Проверьте, работает ли это тоже: stackoverflow.com/questions/14370183/…
Dynelight
@ Alvaro: вы получили свое решение? вы можете передать параметр? из одного контроллера в другой файл контроллера?
Java Man
3
Да. Jewelsea дал объяснение на уровне книги. Вот почему я принял его ответ
Альваро

Ответы:

277

Рекомендуемый подход

Этот ответ перечисляет различные механизмы для передачи параметров в контроллеры FXML.

Для небольших приложений я настоятельно рекомендую передавать параметры непосредственно от вызывающей стороны к контроллеру - это просто, просто и не требует дополнительных платформ.

Для более крупных и сложных приложений было бы целесообразно выяснить, хотите ли вы использовать в своем приложении механизмы Dependency Injection или Event Bus .

Передача параметров напрямую от вызывающего к контроллеру

Передайте пользовательские данные в контроллер FXML, извлекая контроллер из экземпляра загрузчика FXML и вызывая метод на контроллере, чтобы инициализировать его необходимыми значениями данных.

Что-то вроде следующего кода:

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

Новый FXMLLoader строится , как показано в примере кода , т.е. new FXMLLoader(location). Расположение является URL-адресом, и вы можете создать такой URL-адрес из ресурса FXML:

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

Будьте осторожны, НЕ используйте функцию статической загрузки на FXMLLoader, иначе вы не сможете получить свой контроллер от экземпляра загрузчика.

Сами экземпляры FXMLLoader никогда ничего не знают об объектах домена. Вы непосредственно не передаете специфичные для приложения доменные объекты в конструктор FXMLLoader, вместо этого вы:

  1. Создайте FXMLLoader на основе разметки fxml в указанном месте
  2. Получить контроллер из экземпляра FXMLLoader.
  3. Вызовите методы на полученном контроллере, чтобы предоставить контроллеру ссылки на объекты домена.

Этот блог (другой автор) предоставляет альтернативный, но похожий пример .

Настройка контроллера на FXMLLoader

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

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

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

Вы можете создать новый контроллер в коде, передавая любые параметры из вызывающей программы в конструктор контроллера. Создав контроллер, вы можете установить его на экземпляр FXMLLoader, прежде чем вызывать метод load() экземпляра .

Чтобы установить контроллер на загрузчик (в JavaFX 2.x), вы НЕ МОЖЕТЕ также определить fx:controllerатрибут в вашем файле fxml.

В связи с ограничением fx:controllerопределения в FXML, я лично предпочитаю получать контроллер из FXMLLoader, а не устанавливать контроллер в FXMLLoader.

Наличие контроллера, получающего параметры из внешнего статического метода

Этот метод иллюстрируется ответом Сергея на Javafx 2.0 How-to Application.getParameters () в файле Controller.java .

Использовать инъекцию зависимостей

FXMLLoader поддерживает системы внедрения зависимостей, такие как Guice, Spring или Java EE CDI, позволяя вам установить фабрику пользовательских контроллеров на FXMLLoader. Это обеспечивает обратный вызов, который можно использовать для создания экземпляра контроллера с зависимыми значениями, введенными соответствующей системой внедрения зависимостей.

Пример внедрения приложения и контроллера JavaFX с помощью Spring приведен в ответе на:

Действительно хороший, чистый подход к внедрению зависимостей иллюстрируется фреймворком afterburner.fx с примером приложения air-hacks, которое его использует. afterburner.fx использует Jav6 javax.inject для выполнения внедрения зависимостей.

Используйте шину событий

Грег Браун (Greg Brown), создатель и разработчик оригинальной спецификации FXML, часто предлагает рассмотреть возможность использования шины событий, такой как Guava EventBus , для связи между экземплярами контроллера FXML и другой логикой приложения.

EventBus - это простой, но мощный API публикации / подписки с аннотациями, который позволяет POJO взаимодействовать друг с другом в любом месте JVM без необходимости ссылаться друг на друга.

Последующие вопросы и ответы

на первом методе, почему вы возвращаете этап? Этот метод также может быть аннулирован, потому что вы уже дали команду show (); как раз перед возвращением стадии ;. Как вы планируете использование, возвращая этап

Это функциональное решение проблемы. Этап возвращается из showCustomerDialogфункции, так что ссылка на него может быть сохранена внешним классом, который может захотеть что-то сделать, например скрыть этап на основе нажатия кнопки в главном окне, в более позднее время. Альтернативное объектно-ориентированное решение может инкапсулировать функциональность и ссылку на стадию в объекте CustomerDialog или иметь расширенную стадию CustomerDialog. Полный пример объектно-ориентированного интерфейса с настраиваемым диалоговым окном, инкапсулирующим данные FXML, контроллера и модели, выходит за рамки этого ответа, но может стать достойной записью в блоге для любого, кто хочет его создать.


Дополнительная информация предоставлена ​​пользователем StackOverflow с именем @dzim

Пример для инъекции зависимостей весенней загрузки

На вопрос, как это сделать «The Spring Boot Way», шла дискуссия о JavaFX 2, на которую я ответил в прикрепленной постоянной ссылке. Этот подход все еще действителен и протестирован в марте 2016 года на Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


Иногда вы можете захотеть передать результаты обратно вызывающей стороне, и в этом случае вы можете проверить ответ на соответствующий вопрос:

jewelsea
источник
Конструкторы FXMLLoader принимают в качестве параметров только URL-адреса. Как правильно создать экземпляр FXMLLoader?
Альваро
1
веб-сайт шины событий со ссылкой на состояния «Обновление 3/2013: EventBus устарел ...»
j будет
1
Платформы контроллеров DataFX обеспечивают некоторую поддержку инъекций для контроллеров FXML
Хендрик Эбберс,
2
Добавлен дополнительный раздел вопросов и ответов, чтобы ответить на дальнейшие вопросы @Anarkie
jewelsea
7
для бога, есть ли что-нибудь простое для выполнения этой крошечной работы в JavaFx? Это очень распространенная возможность передавать данные в конструкторе, а javafx требует, чтобы все это вместе отправляло одно имя или одно значение?
Захан Сафалва
13

Я понимаю, что это очень старая статья, и на нее уже есть несколько отличных ответов, но я хотел сделать простой MCVE, чтобы продемонстрировать один из таких подходов и дать возможность новым программистам быстро увидеть концепцию в действии.

В этом примере мы будем использовать 5 файлов:

  1. Main.java - просто используется для запуска приложения и вызова первого контроллера.
  2. Controller1.java - Контроллер для первого макета FXML.
  3. Controller2.java - Контроллер для второго макета FXML.
  4. Layout1.fxml - макет FXML для первой сцены.
  5. Layout2.fxml - макет FXML для второй сцены.

Все файлы перечислены полностью в нижней части этого поста.

Цель: продемонстрировать передачу значений из Controller1в Controller2и наоборот.

Ход программы:

  • Первая сцена содержит a TextField, a Buttonи a Label. Когда Buttonнажата кнопка, загружается и отображается второе окно, включая текст, введенный в TextField.
  • Во второй сцене также есть a TextField, a Buttonи a Label. На Labelэкране отобразится текст, введенный в TextFieldпервой сцене.
  • После ввода текста во второй сцене TextFieldи щелчка по ней Button, первая сцена Labelобновляется, чтобы показать введенный текст.

Это очень простая демонстрация, которая, безусловно, может означать некоторое улучшение, но она должна сделать концепцию очень ясной.

Сам код также прокомментирован с некоторыми деталями того, что происходит и как.

КОД

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
Можно ли установить контроллер в файле FXML? Избегайте удаления строки: loader.setController(this)и добавление контроллера в файл FXML приводит к сбою приложения
Halfacht
1
Нет, если FXML загружен из самого контроллера. Например, если вы загружаете FXML из класса Main, вы можете определить контроллер в файле FXML и получить ссылку на него, используяloader.getController()
Zephyr
Наконец мне удалось найти решение, отличный пример. Я внедрил его в свой проект и теперь пытаюсь открыть оба окна одновременно и сделать первое из них модальным. К сожалению, открывается только один. Может ли кто-нибудь помочь с этим?
Джабба
8

Класс javafx.scene.Node содержит пару методов setUserData (Object) и Object getUserData ().

Который вы могли бы использовать, чтобы добавить свою информацию в узел.

Таким образом, вы можете вызвать page.setUserData (info);

И контроллер может проверить, установлена ​​ли информация. Кроме того, вы можете использовать ObjectProperty для обратной передачи данных, если это необходимо.

Ознакомьтесь с документацией здесь: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html Перед фразой «В первой версии handleButtonAction () помечен как @FXML чтобы позволить разметке, определенной в документе контроллера, вызывать ее. Во втором примере поле кнопки аннотировано, чтобы позволить загрузчику установить его значение. Метод initialize () также аннотирован. "

Итак, вам нужно связать контроллер с узлом и установить пользовательские данные для узла.

Александр Киров
источник
Stage.getScene () -> Scene.getRoot () -> рекурсивный поиск с помощью Parent.getChildrenUnmodifiable (). Это очень грязный способ. Если кто-то может предложить что-то лучше - это будет здорово.
Александр Киров
Кажется, Stage.getScene (). GetRoot () - правильный путь! Спасибо
Альваро
7

Вот пример для передачи параметров в документ fxml через пространство имен.

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

Определите значение External Textдля переменной пространства имен 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
источник
Следует отметить , что некоторые клавиши используются внутри: например FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYи любая строка , которая используется в качестве значения для fx:idатрибута.
Фабиан
Спасибо за это, моя другая сцена - это просто контейнер, который показывает текст, ранее показанный на моей основной сцене. Теперь у меня может быть один fxml, который я могу повторно использовать в нескольких местах, инициализируя содержимое через переменные пространства имен. Мне не нужно было создавать какие-либо новые методы или изменять мой конструктор или инициализаторы - просто добавьте переменную в мой FXML и добавьте одну строку в мой код fxmloader в главном контроллере.
SystemsInCode
4

Это работает ..

Помните, что в первый раз, когда вы печатаете передаваемое значение, вы получаете нулевое значение. Вы можете использовать его после загрузки ваших окон, то же самое для всего, что вы хотите закодировать для любого другого компонента.

Первый Контроллер

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

Другой Контроллер

public void initVariable(Long id_usuario){
    this.id_usuario = id_usuario;
    label_usuario_nombre.setText(id_usuario.toString());
}
Диего Матос - Кеке
источник
1
Это работает, когда вы передаете параметр от первого контроллера ко второму, но как передать параметр от второго к первому контроллеру, я имею в виду после загрузки first.fxml.
Менай Ала Эддин - Аладдин
@XlintXms см. Связанный вопрос Параметр JavaFX FXML, передаваемый из контроллера A в B и обратно , который отвечает на ваш дополнительный вопрос.
Jewelsea
2

Вы должны создать один класс контекста.

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

Вы должны просто установить экземпляр контроллера в инициализации, используя

Context.getInstance().setTabRough(this);

и вы можете использовать его из всего приложения, просто используя

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

Теперь вы можете передать параметр на любой контроллер из всего приложения.

CTN
источник
Мы используем этот подход, и он прекрасно работает. Мне нравится, что у меня есть доступ к данным внутри конструктора или в методе инициализации, и мне не нужно устанавливать данные в контроллере после его создания
Боб
2

Да, ты можешь.
Вам нужно добавить в первый контроллер:

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

Затем во втором объявите клиента, а затем в нижней части вашего контроллера:

public void setclien(Client c) {
    this.client = c;
}
Монтассар Буагина
источник
0

Вот пример использования контроллера, введенного 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;
}

Вот конкретная реализация загрузчика:

public class ConcreteViewLoader extends GuiceFxmlLoader {

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

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

Обратите внимание, что этот пример загружает представление в центр BoarderPane, который является корнем сцены в рабочей области. Это не относится к примеру (подробности реализации моего конкретного варианта использования), но решил оставить его, так как некоторые могут найти его полезным.

jenglert
источник
-1

Вы можете решить использовать общедоступный список наблюдаемых для хранения общедоступных данных или просто создать метод общедоступного сеттера для хранения данных и извлечения из соответствующего контроллера.

Носпаниол Ноа
источник
-3

Зачем отвечать на 6-летний вопрос?
Одна из самых фундаментальных концепций работы с любым языком программирования - как перемещаться от одного (окна, формы или страницы) к другому. Также, выполняя эту навигацию, разработчик часто хочет передавать данные из одного (окна, формы или страницы) и отображать или использовать переданные данные.
В то время как большинство ответов здесь дают хорошие и отличные примеры, как этого добиться, мы думали, что мы их подгоним метка, две или три
Мы сказали три, потому что мы будем перемещаться между тремя (окном, формой или страницей) и будем использовать концепцию статических переменных для передачи данных вокруг (окна, формы или страницы).
Мы также включим некоторый код принятия решений, пока мы ориентируемся

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

Контроллер запуска

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

Контроллер первой страницы

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

}

Контроллер второй страницы

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

}    

}

Ниже приведены все файлы 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
Извините, но публикация сотен строк кода без какого-либо объяснения того, что он делает или почему вы делаете это так, как вы это делаете, не очень хороший ответ. Кроме того, код, который вы разместили, очень плохо организован, и за ним трудно следовать.
Зефир
1
Нет необходимости хамить просящему человеку. Мы все здесь, чтобы учиться
Zeyad