java 使用 JavaFX 打开多个窗口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25496692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:07:26  来源:igfitidea点击:

Opening multiple windows with JavaFX

javaeventsintellij-ideajavafx

提问by Serial

I'm trying to open multiple windows with JavaFX, I have an eventlistener that opens a new window when a button is clicked it looks like this:

我正在尝试使用 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();}
}

the first window opens and the new one opens, but my problem is getting events to work with my second window

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

in main.fxmlI have this line:

main.fxml我有这一行:

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

Then in my controller class I have this method:

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

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

but Intellij is telling me that; no controller specified for top level element

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

So, my question is: Do I need to create multiple controller classes or can I use just one for multiple windows if so how?

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

采纳答案by James_D

The recommended approach is to define a controller for each FXML. Since controllers are very lightweight this shouldn't add much overhead. The controller for your main.fxml file might be as simple as

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

import javafx.fxml.FXML ;

public class MainController {
  @FXML
  private void sendChat() {
    // ...
  }
}

I have used this approach with fairly large numbers of FXML files and corresponding controllers in a single project, and have had no issues with managing the code etc. I recommend using a naming convention of the form Main.fxml <-> MainController.

我已经在单个项目中对相当多的 FXML 文件和相应的控制器使用了这种方法,并且在管理代码等方面没有问题。我建议使用表单的命名约定Main.fxml <-> MainController

If your controllers need to share data, use the techniques outlined in Passing Parameters JavaFX FXML

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

As @Vertex points out in the comments, there is an alternative approach provided by the FXMLLoader.setController(...)method. So in your example above, you could do

正如@Vertex 在评论中指出的那样,该方法提供了另一种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() {
    // ...
}

This approach is fine if you are not setting any fields (controls) via FXML injection (i.e. with an fx:idattribute in the fxml and a corresponding @FXMLannotation in the controller). If you are, it will be very difficult to keep track of when those fields have been set. Moreover, if your joinActionhandler is invoked multiple times, you will have multiple instances of the node created by main.fxml, but all sharing a single controller instance (and consequently overwriting the same injected fields). Also note that with this approach, your initialize()method will be invoked bothwhen the original fxml file is loaded, andwhen the main.fxml file is loaded, which will almost certainly cause undesired effects.

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

One last note: if you have many FXML files, and corresponding controllers, you might want to look at the afterburner.fx framework. This is a very lightweight framework that mandates a naming convention on FXML files and their corresponding controllers, and also provides a (very) easy mechanism for sharing data between them.

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

回答by emin deniz

You need to add top level element fx:controller. Look at this answer:https://stackoverflow.com/a/41316536/4247308

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