【问题标题】:Opening multiple windows with JavaFX使用 JavaFX 打开多个窗口
【发布时间】:2014-10-19 05:45:37
【问题描述】:

我正在尝试使用 JavaFX 打开多个窗口,我有一个事件监听器,当单击按钮时会打开一个新窗口,如下所示:

@FXML
private void joinAction() {
    Parent root;
    try {
        Stage stage = (Stage) joinButton.getScene().getWindow();
        stage.close();

        root = FXMLLoader.load(getClass().getResource("main.fxml"));
        stage = new Stage();
        stage.setTitle("TuneUs");
        stage.setScene(new Scene(root));
        stage.show();

    } catch (IOException e) {e.printStackTrace();}
}

第一个窗口打开,新窗口打开,但我的问题是让事件与我的第二个窗口一起工作

main.fxml我有这行:

<TextField id="chat_bar" onAction="#sendChat" layoutX="14.0" layoutY="106.0" prefHeight="22.0" prefWidth="403.0"/>

然后在我的控制器类中我有这个方法:

@FXML
private void sendChat() {
    System.out.println("test");
}

但 Intellij 告诉我;没有为顶级元素指定控制器

所以,我的问题是:我是否需要创建多个控制器类,或者如果需要,我可以只为多个窗口使用一个吗?

【问题讨论】:

  • 为每个 FXML 文件创建一个控制器类(不管你有多少个窗口/阶段)。
  • 您可以用 setController 告诉 FXMLLoader 包含事件处理程序方法的控制器在哪里。例如,如果加载器看到onAction="#sendChat",它将在控制器对象中搜索带有@FXML 注释的方法sendChat
  • @James_D 所以,如果我有很多 FXML 文件,我将不得不为我的控制器准备大量文件
  • @Serial 是的:我从来没有发现这是一个问题。 @Vertex 提供了一种不同的机制,但只能在非常简单的情况下使用(没有注入字段,没有initialize() 方法)。我添加了一个答案。

标签: java events intellij-idea javafx


【解决方案1】:

您需要添加顶级元素 fx:controller。看这个答案:https://stackoverflow.com/a/41316536/4247308

【讨论】:

    【解决方案2】:

    推荐的方法是为每个 FXML 定义一个控制器。由于控制器非常轻量级,因此不会增加太多开销。 main.fxml 文件的控制器可能很简单

    import javafx.fxml.FXML ;
    
    public class MainController {
      @FXML
      private void sendChat() {
        // ...
      }
    }
    

    我已经在单个项目中使用这种方法处理大量 FXML 文件和相应的控制器,并且在管理代码等方面没有任何问题。我建议使用 Main.fxml &lt;-&gt; MainController 形式的命名约定。

    如果您的控制器需要共享数据,请使用Passing Parameters JavaFX FXML 中概述的技术

    正如@Vertex 在 cmets 中指出的那样,FXMLLoader.setController(...) 方法提供了另一种方法。所以在你上面的例子中,你可以这样做

    @FXML
    private void joinAction() {
        Parent root;
        try {
            Stage stage = (Stage) joinButton.getScene().getWindow();
            stage.close();
    
            FXMLLoader loader = new FXMLLoader (getClass().getResource("main.fxml"));
            loader.setController(this);
            root = loader.load();
            stage = new Stage();
            stage.setTitle("TuneUs");
            stage.setScene(new Scene(root));
            stage.show();
    
        } catch (IOException e) {e.printStackTrace();}
    }
    
    @FXML
    private void sendChat() {
        // ...
    }
    

    如果您不通过 FXML 注入设置任何字段(控件)(即在 fxml 中使用 fx:id 属性并在控制器中使用相应的 @FXML 注释),则此方法很好。如果是,那么很难跟踪这些字段的设置时间。此外,如果您的 joinAction 处理程序被多次调用,您将拥有由 main.fxml 创建的节点的多个实例,但它们都共享一个控制器实例(并因此覆盖相同的注入字段)。另请注意,使用这种方法,您的 initialize() 方法将在加载原始 fxml 文件时调用 both,在加载 main.fxml 文件时调用 ,这将几乎可以肯定会导致不良影响。

    最后一点:如果您有许多 FXML 文件和相应的控制器,您可能需要查看 afterburner.fx framework。这是一个非常轻量级的框架,它要求对 FXML 文件及其相应的控制器进行命名约定,并且还提供了一种(非常)简单的机制来在它们之间共享数据。

    【讨论】:

      猜你喜欢
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      • 1970-01-01
      • 2017-08-26
      • 2019-08-07
      相关资源
      最近更新 更多