传递参数 JavaFX FXML

Passing Parameters JavaFX FXML

提问人:Alvaro 提问时间:1/7/2013 最后编辑:randersAlvaro 更新时间:10/20/2021 访问量:229215

问:

如何在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 作为参数传递)。

有什么想法吗?

javafx 参数 依赖 fxml

评论

0赞 Dynelight 1/21/2013
检查这是否也有效:stackoverflow.com/questions/14370183/...
0赞 Java Man 3/7/2014
@Alvaro:你得到解决方案了吗?你能传递参数吗?从一个控制器到另一个控制器文件?
3赞 Alvaro 3/7/2014
是的。Jewelsea给出了书本级别的解释。这就是我接受他的回答的原因

答:

7赞 Alexander Kirov 1/7/2013 #1

javafx.scene.Node 类有一对方法 setUserData(对象) 和 对象 getUserData()

您可以使用它来将您的信息添加到节点。

因此,您可以调用 page.setUserData(info);

控制器可以检查是否设置了信息。此外,如果需要,可以使用 ObjectProperty 进行前向后数据传输。

请看这里的文档: http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html 在短语“在第一个版本中,handleButtonAction()”之前用@FXML标记,以允许控制器文档中定义的标记调用它。在第二个示例中,对按钮字段进行了注释,以允许加载程序设置其值。initialize() 方法也有类似的注释。

因此,您需要将控制器与节点关联,并为节点设置用户数据。

评论

0赞 Alexander Kirov 1/7/2013
Stage.getScene() -> Scene.getRoot() -使用 Parent.getChildrenUnmodifiable() >递归搜索。这是非常肮脏的方式。如果有人能提出更好的建议,那就太好了。
0赞 Alvaro 1/7/2013
看来 Stage.getScene().getRoot() 是正确的方法!谢谢
305赞 jewelsea 1/7/2013 #2

使用 MVC

此答案的大部分内容都侧重于直接调用,以将参数从调用类传递到控制器。

相反,如果要分离调用方和控制器,并使用更通用的体系结构,该体系结构涉及具有可设置和可侦听属性的模型类,以实现控制器间通信,请参阅以下基本概述:

推荐的方法

此答案列举了将参数传递给 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(loader.load())
  );

  CustomerDialogController controller = loader.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,即 .位置是一个 URL,您可以通过以下方式从 FXML 资源生成此类 URL:new FXMLLoader(location)

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

请注意不要在 FXMLLoader 上使用静态加载函数,否则您将无法从 loader 实例中获取控制器。

FXMLLoader 实例本身从来不知道有关域对象的任何信息。您不直接将特定于应用程序的域对象传递到 FXMLLoader 构造函数中,而是:

  1. 在指定位置基于fxml标记构造FXMLLoader
  2. 从 FXMLLoader 实例获取控制器。
  3. 在检索到的控制器上调用方法,为控制器提供对域对象的引用。

这篇博客(由另一位作者撰写)提供了一个替代但类似的示例

在 FXMLLoader 上设置控制器

CustomerDialogController dialogController = 
    new CustomerDialogController(param1, param2);

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

Pane mainPane = loader.load();

可以在代码中构造新的控制器,将调用方所需的任何参数传递到控制器构造函数中。构造控制器后,可以在调用实例方法之前在 FXMLLoader 实例上设置它。load()

要在加载器上设置控制器(在 JavaFX 2.x 中),还不能在 fxml 文件中定义 fx:controller 属性。

由于 FXML 中定义的限制,我个人更喜欢从 FXMLLoader 获取控制器,而不是将控制器设置到 FXMLLoader 中。fx:controller

让控制器从外部静态方法检索参数

Sergey 在 Controller.java 文件中对 Javafx 2.0 How-to Application.getParameters() 的回答举例说明了此方法。

使用依赖注入

FXMLLoader 支持依赖注入系统,如 Guice、Spring 或 Java EE CDI,允许您在 FXMLLoader 上设置自定义控制器工厂。这提供了一个回调,您可以使用该回调来创建控制器实例,该实例具有由相应的依赖注入系统注入的依赖值。

在以下答案中提供了使用 Spring 进行 JavaFX 应用程序和控制器依赖注入的示例:

afterburner.fx 框架是一个非常好的、干净的依赖注入方法的例子,它有一个使用它的示例 air-hacks 应用程序。afterburner.fx 依赖于 JEE6 javax.inject 来执行依赖注入。

使用事件总线

Greg Brown 是最初的 FXML 规范创建者和实现者,他经常建议考虑使用事件总线(如 Guava EventBus)来 FXML 实例化控制器和其他应用程序逻辑之间的通信。

EventBus 是一个简单但功能强大的发布/订阅 API,带有注释,允许 POJO 在 JVM 中的任何位置相互通信,而无需相互引用。

后续问答

在第一种方法上,为什么要返回 Stage?该方法也可以是无效的,因为您已经给出了命令 show();就在返回阶段之前;如何通过返回舞台来规划使用情况

它是问题的功能性解决方案。从函数返回一个阶段,以便外部类可以存储对它的引用,该外部类可能希望在以后执行某些操作,例如根据主窗口中的按钮单击隐藏阶段。另一种面向对象的解决方案可以将功能和阶段引用封装在 CustomerDialog 对象中,或者让 CustomerDialog 扩展阶段。封装 FXML、控制器和模型数据的自定义对话框的面向对象接口的完整示例超出了本答案的范围,但对于任何倾向于创建博客的人来说,都可以成为一篇有价值的博客文章。showCustomerDialog


名为 @dzim 的 StackOverflow 用户提供的其他信息

Spring Boot 依赖注入示例

关于如何做到这一点的问题 “Spring Boot Way”,有一个关于 JavaFX 2 的讨论,我在随附的永久链接中进行了讨论。 该方法仍然有效,并于 2016 年 3 月在 Spring Boot v1.3.3.RELEASE 上进行了测试:https://stackoverflow.com/a/36310391/1281217


有时,您可能希望将结果传回调用方,在这种情况下,您可以查看相关问题的答案:

评论

0赞 Alvaro 1/8/2013
FXMLLoader 构造函数仅将 URL 作为参数。实例化 FXMLLoader 的正确方法是什么?
1赞 j will 12/6/2013
Event Bus 网站暗示,“2013 年 3 月更新:EventBus 已过时......”
1赞 Hendrik Ebbers 3/5/2014
DataFX 控制器框架为 FXML 控制器提供了一些注入支持: guigarage.com/2013/12/datafx-controller-framework-preview
2赞 jewelsea 12/30/2015
添加了额外的问答部分,以解决@Anarkie的进一步问题
12赞 Zahan Safallwa 4/24/2017
对于godshake来说,在JavaFx中做这个小工作有什么简单的事情吗?在构造函数中传递数据是一个非常常见的特性,而 JavaFX 需要所有这些地狱般的东西,只是为了发送一个名称或一个值?
1赞 jenglert 11/20/2015 #3

下面是使用 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 的中心,BoarderPane 是舞台中场景的根。这与示例(我的特定用例的实现细节)无关,但决定将其保留,因为有些人可能会发现它很有用。

11赞 user1503636 1/12/2016 #4

下面是通过命名空间将参数传递给 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 TextlabelText

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

评论

0赞 fabian 2/2/2016
应该注意的是,一些键在内部使用:例如,,以及用作属性值的任何字符串。FXMLLoader.CONTROLLER_KEYWORDFXMLLoader.LOCATION_KEYFXMLLoader.RESOURCES_KEYfx:id
0赞 SystemsInCode 10/29/2018
谢谢你,我的另一个场景只是一个容器,显示之前在我的主场景中显示的文本。现在,我可以拥有一个 fxml,通过 Namepace 变量初始化内容,可以在多个地方重用它。我不必创建任何新方法或更改我的构造函数或启动器 - 只需在我的 FXML 中添加变量并在主控制器的 fxmloader 代码中添加一行。
4赞 diego matos - keke 4/29/2016 #5

这有效..

请记住,第一次打印传递值时,您将得到 null, 您可以在加载窗口后使用它,对于您想要为任何其他组件编码的所有内容都相同。

第一个控制器

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赞 Menai Ala Eddine - Aladdin 9/19/2017
当您将参数从第一个控制器传递到第二个控制器时,这可以工作,但是如何将参数从第二个控制器传递到第一个控制器,我的意思是在加载 first.fxml 之后。
0赞 jewelsea 1/12/2018
@XlintXms请参阅相关问题 JavaFX FXML 参数从控制器 A 传递到 B 并返回,该问题解决了您的其他问题。
3赞 CTN 10/22/2016 #6

您必须创建一个 Context 类。

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

现在,您可以将参数从整个应用程序传递给任何控制器。

评论

0赞 Bob 8/28/2019
我们使用这种方法,效果很好。我喜欢我可以访问构造函数或 initialize 方法中的数据,并且不必在构造后在控制器中设置数据
-3赞 Nospaniol Noah 3/15/2018 #7

您可以决定使用公共可观察列表来存储公共数据,或者只创建一个公共 setter 方法来存储数据并从相应的控制器检索

18赞 Zephyr 6/27/2018 #8

我意识到这是一个非常古老的帖子,并且已经有一些很好的答案, 但我想做一个简单的 MCVE 来演示这种方法,并允许新编码人员快速看到这个概念的实际应用。

在此示例中,我们将使用 5 个文件:

  1. Main.java - 仅用于启动应用程序并调用第一个控制器。
  2. 控制器 1.java - 第一个 FXML 布局的控制器。
  3. Controller2.java - 第二个 FXML 布局的控制器。
  4. Layout1.fxml - 第一个场景的 FXML 布局。
  5. Layout2.fxml - 第二个场景的 FXML 布局。

所有文件都完整地列在这篇文章的底部。

目标:演示从 到 传递值,反之亦然。Controller1Controller2

程序流程:

  • 第一个场景包含 a 、a 和 a 。单击 时,将加载并显示第二个窗口,包括在 中输入的文本。TextFieldButtonLabelButtonTextField
  • 在第二个场景中,还有一个 、 a 和一个 .将显示在第一个场景中输入的文本。TextFieldButtonLabelLabelTextField
  • 在第二个场景中输入文本并单击其 时,第一个场景将更新以显示输入的文本。TextFieldButtonLabel

这是一个非常简单的演示,当然可以代表一些改进,但应该使概念非常清晰。

代码本身也注释了一些正在发生的事情和方式的细节。

代码

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

    }
}

控制器1.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);
    }
}

控制器2.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());
    }

}

布局1.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>

布局2.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赞 Halfacht 10/20/2018
是否可以在FXML文件中设置控制器?Beause 删除行:并在 FXML 文件中添加控制器会使应用程序崩溃loader.setController(this)
1赞 Zephyr 10/20/2018
如果 FXML 是从控制器本身内部加载的,则不会。例如,如果从 Main 类加载 FXML,则可以在 FXML 文件中定义控制器,并使用loader.getController()
0赞 jabba 2/5/2020
最后,我设法找到了一个解决方案,一个很好的例子。我在我的项目中实现了它,现在我正在尝试使两个窗口同时打开,并使它们的第一个成为模态窗口。不幸的是,只有一个打开。谁能帮忙?
2赞 Montassar Bouajina 1/31/2019 #9

是的你可以。
您需要添加第一个控制器:

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

然后在第二个声明一个客户端,然后在控制器的底部:

public void setclien(Client c) {
    this.client = c;
}
-4赞 Vector 8/28/2019 #10

为什么要回答一个 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 控制器

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>

评论

9赞 Zephyr 9/18/2019
对不起,但是发布一百行代码而没有解释它的作用或你为什么这样做,这不是一个非常好的答案。另外,您发布的代码组织得很差,难以遵循。
3赞 Zeyad 6/3/2020
没有必要对提问的人无礼。我们都来学习