Параметри передачі JavaFX FXML


194

Як я можу передати параметри до вторинного вікна в javafx? Чи існує спосіб зв’язку з відповідним контролером?

Наприклад: Користувач вибирає клієнта з a 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було б нове вікно. Проблема полягає в тому, що я не можу знайти спосіб сказати контролеру, де шукати інформацію клієнта (передавши ідентифікатор як параметр).

Будь-які ідеї?


Перевірте , щоб побачити , якщо це теж працює: stackoverflow.com/questions/14370183 / ...
Dynelight

@Alvaro: ти отримав своє рішення? Ви можете передати параметр? від одного контролера до іншого файлу контролера?
Java Man

3
Так. Jewsea дав пояснення на рівні книги. Тому я прийняв його відповідь
Альваро

Відповіді:


276

Рекомендований підхід

Ця відповідь перераховує різні механізми передачі параметрів FXML-контролерам.

Для невеликих програм я дуже рекомендую передавати параметри безпосередньо від абонента до контролера - це просто, просто та не вимагає додаткових кадрів.

Для великих, складніших додатків варто вивчити, чи ви хочете використовувати механізми введення залежності або шини подій у вашій програмі.

Передача параметрів безпосередньо від абонента до контролера

Передайте власні дані контролеру 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 покладається на JEE6 javax.inject для виконання ін'єкції залежності.

Використовуйте автобус подій

Грег Браун, оригінальний творець специфікації FXML та реалізатор, часто пропонує розглянути можливість використання шини подій, наприклад Guava EventBus , для зв'язку між контролерами FXML, що інстанціюються, та іншою логікою програми.

EventBus - це простий, але потужний API публікації / підписки з анотаціями, який дозволяє POJO спілкуватися між собою в будь-якому місці JVM, не звертаючись один до одного.

Подальші запитання та запитання

на першому методі, чому ви повертаєте етап? Цей метод може бути недійсним, оскільки ви вже даєте команду show (); безпосередньо перед етапом повернення ;. Як планувати використання, повертаючи Етап

Це функціональне рішення проблеми. Етап повертається з showCustomerDialogфункції, так що посилання на нього може зберігатися зовнішнім класом, який, можливо, захоче щось зробити, наприклад приховати етап на основі натискання кнопки в головному вікні, пізніше. Альтернативне, об'єктно-орієнтоване рішення може інкапсулювати функціональність та посилання на етапи всередині об'єкта CustomerDialog або мати етап Extension CustomerDialog. Повний приклад об'єктно-орієнтованого інтерфейсу до спеціального діалогового вікна, що інкапсулює дані FXML, контролера та моделі, виходить за рамки цієї відповіді, але може зробити корисну публікацію в блозі для тих, хто схильний її створити.


Додаткова інформація, надана користувачем StackOverflow на ім'я @dzim

Приклад вприскування залежної залежності завантаження

Питання про те, як це зробити "Весняний завантажувальний шлях", відбулося обговорення JavaFX 2, яке я озвучив у доданій постійній посилання. Підхід досі діє та перевірений у березні 2016 року на Spring Boot v1.3.3.RELEASE: https://stackoverflow.com/a/36310391/1281217


Іноді, можливо, ви захочете повернути результати тому, хто телефонує, і в цьому випадку ви можете перевірити відповідь на відповідне запитання:


Конструктори FXMLLoader приймають лише URL-адреси як параметри. Який правильний спосіб інстанціювати FXMLLoader?
Альваро

1
веб-сайт автобусу події натякає на "Оновлення 3/2013: EventBus став устареним ..."
j буде

1
Рамки контролерів DataFX надають деяку підтримку ін'єкцій для контролерів FXML
Хендрік Ебберс

2
Додано додатковий розділ запитань та відповідей, щоб відповісти на подальші питання @Anarkie
jewelsea

7
для Godshake чи є щось просте для виконання цієї крихітної роботи в JavaFx? дуже поширена особливість передачі даних у конструкторі та javafx вимагає цього пекла всього разом лише для того, щоб надіслати одне ім’я чи одне значення?
Zahan Safallwa

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

Нарешті мені вдалося знайти рішення, чудовий приклад. Я реалізував це у своєму проекті, і зараз я намагаюся зробити обидва вікна одночасно відкритими та зробити перший з них модальним. На жаль, відкривається лише одна. Хтось може допомогти в цьому?
jabba

8

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

Який ви могли використовувати, щоб додати свою інформацію до Вузла.

Отже, ви можете зателефонувати на сторінку.setUserData (інформація);

І контролер може перевірити, чи встановлена ​​інформація. Також ви можете використовувати 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();
    }
}

Слід зазначити , що деякі клавіші використовуються всередині: наприклад FXMLLoader.CONTROLLER_KEYWORD, FXMLLoader.LOCATION_KEY, FXMLLoader.RESOURCES_KEYі будь-який рядок , яка використовується в якості значення для fx:idатрибута.
fabian

Дякую за це, моя інша сцена - це просто контейнер, який показує текст, показаний раніше на моїй головній сцені. Тепер у мене може бути один fxml, який я можу повторно використовувати в декількох місцях, ініціалізуючи вміст за допомогою змінних простору імен. Мені не доводилося створювати будь-яких нових методів або змінювати конструктор або інвалідатори - просто додайте змінну в мій FXML і додайте один рядок у мій код fxmloader в головному контролері.
SystemsInCode

4

Це РОБОТИ ..

Пам'ятайте, що при першому надрукуванні прохідного значення ви отримаєте нульове значення. Ви можете використовувати його після завантаження Windows, однаково для всього, що ви хочете кодувати для будь-якого іншого компонента.

Перший контролер

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

Тепер ви можете передавати параметр будь-якому контролеру з усієї програми.


Ми використовуємо такий підхід, і він чудово працює. Мені подобається, що у мене є доступ до даних всередині конструктора або методу ініціалізації, і мені не потрібно встановлювати дані в контролері після його побудови
Боб

1

Так, ти можеш.
Вам потрібно додати в перший контролер:

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, що є коренем сцени на сцені. Це не має значення для прикладу (деталі реалізації мого конкретного випадку використання), але вирішено залишити його, оскільки деякі можуть вважати його корисним.


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

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

}

Сторінка Контролер

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>


3
Вибачте, але опублікувати сто рядків коду без будь-якого пояснення, що це робить або чому ви робите це так, як ви це робите, не дуже хороша відповідь. Крім того, код, який ви опублікували, дуже погано організований і його важко дотримуватися.
Зефір

Не потрібно бути грубим запитувальній особі. Ми всі тут, щоб дізнатися
Зеяд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.