在一个主FXML中使用多个FXML和多个控制器

3

最近,我开始学习JavaFX,但有一些问题困扰着我,我找不到解决方法。虽然我找到了与我的问题类似的问题和一些解决方案,但是我没有找到一个适用于我的或者说我做错了什么。我想做的是在一个主FXML文件中添加(导入)其他具有控制器的FXML文件。我尝试了几种方法,但没有成功,因此我决定描述一下我的操作。首先,我使用Scene Builder创建了主FXML文件,然后创建了主FXML的控制器。然后我在Scene Builder中设置了主FXML的控制器类为主控制器。接下来,我为第二个FXML做同样的操作。然后我尝试将第二个FXML导入到主FXML中,如果我还没有为第二个FXML设置控制器,则可以正常工作。但是,如果我在导入之前为第二个FXML选择了控制器,则尽管我仍能够导入FXML文件并保存它,但运行程序后会出现错误。所以基本上我想做的是在一个具有控制器类的主FXML文件中添加多个具有自己控制器的FXML文件。我不确定这是否可能,所以请告诉我这是否可能,如果可能的话,我做错了什么。这是我的代码:

public class MainSceneController implements Initializable {

@FXML 
private TextField mainTxtField;

public MainSceneController() { 
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);

    try { 
        fxmlLoader.load();
    } catch (IOException exc) { 
        } }
@FXML
public void buttonActionMethod(ActionEvent event) { 
    mainTxtField.setText("Button1 is clicked");
}

@Override
public void initialize(URL location, ResourceBundle resources) {    
} }

我将第二个FXML和第二个控制器命名为LeftScene和LeftSceneController,下面是第二个控制器的代码:

public class LeftSceneController implements Initializable {

@FXML
private TextField leftTxtField;

public LeftSceneController() { 
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
    fxmlLoader.setController(this);
    fxmlLoader.setRoot(this);

        try { 
            fxmlLoader.load();
        } catch (IOException exc) { 
            }
}
@FXML 
public void button2Action(ActionEvent event) { 
    leftTxtField.setText("Button 2 is clicked");
}

@Override
public void initialize(URL location, ResourceBundle resources) {    
} }

最后,这是MainClass,在其中包含主要方法和启动方法:

public class MainClass extends Application {

public static void main(String[] args) { 
    launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("MainScene.fxml"));
    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.setTitle("Multiple FXMLs in one");
    primaryStage.show();
} }

我希望你能明白我的意思。我尝试了很多方法,但都没有达到我想要的效果。如果在导入第二个FXML之前不设置第二个FXML的控制器类,那么这个版本是可以编译和运行的,但是正如你所料,从导入的FXML中的第二个按钮没有任何反应。如果可以的话,我会发布截图,但我是新手,通常只是阅读,所以我不能发布截图。我还尝试过发布我的FXML代码,但是系统出了问题,我无法发布超过一行代码。
那么...是否有可能让它按照我想要的方式工作呢?
如果您阅读了这篇混乱的文章,至少感谢您的时间! :)

你为什么在控制器中加载主场景?你有阅读FXML文档的嵌套控制器部分吗? - James_D
是的,我已经阅读了嵌套控制器部分,这就是为什么两个控制器都有构造函数的原因。我的想法是在主控制器中使用一个第二个控制器(LeftSceneController)对象,这样我就可以使用第二个控制器。这就是为什么第二个控制器加载场景,但可能这不是一个好主意,或者没有做对... - kaloyant
为什么不按照文档中的方式来做呢? - James_D
我想我找到了问题所在。我再次尝试了文档中的方法,但这一次我手动添加了<fx:include ...>标签,而不是使用SceenBuilder将第二个FXML导入到主FXML中,现在它正常工作了。现在的问题是,当我用SceneBuilder打开主FXML时,我甚至无法更改导入的FXML文件的位置,所以我必须通过在编辑器中打开代码来手动完成。现在我只需要找出我是否在使用SceneBuilder时做错了什么或者这只是一个错误。 - kaloyant
我没有意识到你正在使用SceneBuilder。 我相当确定SceneBuilder不支持<fx:include>。 - James_D
1个回答

7
我已经找到了我的问题的答案,虽然花费了一些时间。我在YouTube上找到了这个视频,它正好展示了我需要的内容。但是,在按照视频逐步操作时,我遇到了一些问题。
首先,如果我将另一个FXML文件导入到主FXML中,就像在本教程中一样,SceneBuilder会像导入的FXML中的元素在主FXML中一样导入FXML,这会导致问题。我的意思是,例如,如果您在导入的FXML中有一个按钮,当您使用SceneBuilder将其导入到主FXML中时,导入的按钮会出现在主FXML中,就像一个新的带有所有信息(位置,onClickMethod等)的按钮,并且这不是应该的方式。这会导致错误,因为Java正在查找导入按钮的onClickMethod,但不是在导入FXML的Controller中,而是在Main Controller中。我不知道为什么我的情况与视频中不同,但解决方案很简单。如果您想将FXML文件导入到另一个FXML中,您应该使用编辑器,并只需在主FXML的内容中添加以下行:
<fx:include fx:id="importedFXML" source="ImportedFXML.fxml" />

在这种情况下,重要的是fx:id应该与.fxml文件名称相同,但首字母应小写。
还有一件事,在视频中提到并导致了我的问题,如果您想要有多个导入的FXML文件并且希望它们彼此通信。视频展示了如何做到这一点,但没有提到在MainController中必须创建导入FXML文件的Controller对象,这些对象必须具有与fx:id相同的名称+单词Controller。例如,对于上面的fx:id,对象应该看起来像这样:
@FXML private ImportedFXMLController importedFXMLController 

如果ImportedFXMLController是importedFXML的控制器,那么希望这对某人有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接