JavaFX 8 将多个 fxml 文件加载到边界窗格中 [英] JavaFX 8 loading multiple fxml files into borderpane

查看:30
本文介绍了JavaFX 8 将多个 fxml 文件加载到边界窗格中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下代码:

公共类 Main 扩展应用程序 {

public class Main extends Application {

private BorderPane rootLayout;
private VBox toolbarLayout;

private URL path;

public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage stage) {                            

    FXMLLoader loader = new FXMLLoader();                

    // Root View

    path = getClass().getResource("mainLayout.fxml");
    try {
        loader.setLocation(path);            
        rootLayout = (BorderPane) loader.load();
    } catch (IOException e){
        System.out.println("Not found: " + path);
        e.printStackTrace();
    }        

    // Toolbar View
    path = getClass().getResource("toolbar/toolbarView.fxml");  
    try {                        
        toolbarLayout = (VBox) loader.load();
    } catch (IOException e){
        System.out.println("Not found: " + path);
        e.printStackTrace();
    }

    rootLayout.getChildren().add(toolbarLayout);

    Scene scene = new Scene(rootLayout);        
    stage.setScene(scene);
    stage.show();
}

如果我注释掉第二个 fxml 'try' rootLayout 加载正常.如果我注释掉边框并将工具栏视图设置为主视图,它也可以正常工作.但是,如果我尝试将 toolbarView 加载到 rootLayout 中,则 rootLayout 加载正常,但 toolbarView 会引发异常:

If I comment out the second fxml 'try' the rootLayout loads fine. If I comment out the borderpane and set the toolbarView as the main view it works fine too. BUT if I try to load the toolbarView into the rootLayout, the rootLayout loads fine, but the toolbarView throws an exception:

javafx.fxml.LoadException: Root value already specified.

显然我不太了解 fxml 加载过程,所以有人可以对此有所了解吗?为什么它认为我试图再次设置根?

Obviously I don't understand the fxml load process well enough, so can someone please throw some light on this? Why does it think I am trying to set the root again?

为了完整起见,这里是 toolbarView.fxml:

For completeness, here is the toolbarView.fxml:

<VBox fx:id="idToolbar" alignment="TOP_CENTER" maxHeight="-Infinity"
 maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
  prefHeight="400.0" prefWidth="100.0" spacing="20.0" 
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">

<children>
  <Button mnemonicParsing="false" text="Button" />
  <Button mnemonicParsing="false" text="Button" />
  <Button mnemonicParsing="false" text="Button" />
</children>
  <opaqueInsets>
    <Insets />
  </opaqueInsets>
<padding>
  <Insets top="20.0" />
</padding>
</VBox>

推荐答案

root 属性包含对 FXML 文件指定结构的引用;即到由 FXML 文件的根元素创建的对象.假设您没有使用 "动态根"()模式,根将作为load过程的一部分设置到根元素对应的对象的 FXML.如果在这个阶段它不是 null(即如果它已经被设置),那么你会得到一个异常.controller 属性也有类似的情况:如果 FXML 文件指定了 fx:controller 属性,则控制器将被设置为 load() 的一部分 过程;如果不是null,则抛出异常.

The root property contains a reference to the structure specified by the FXML file; i.e. to the object created by the root element of the FXML file. Assuming you are not using the "dynamic root" (<fx:root>) pattern, the root will be set as part of the load process to the object corresponding to the root element of the FXML. If it is not null at this stage (i.e. if it has already been set), then you will get an exception. A similar thing is true for the controller property: if the FXML file specifies an fx:controller attribute, the controller will be set as part of the load() process; if it is not null, an exception is thrown.

FXMLLoader 实际上只设计为使用一次,因为您有许多相互依赖的属性,这些属性通常设置为加载过程的一部分:root, locationcontrollerresourcesnamespace 的元素.因此,您应该为要加载的每个 FXML 文件创建一个新的 FXMLLoader:

The FXMLLoader is really only designed to be used once, as you have many interdependent properties which are typically set as part of the load process: root, location, controller, resources, and elements of the namespace. So you should really create a new FXMLLoader for each FXML file you want to load:

FXMLLoader loader = new FXMLLoader();                

// Root View

path = getClass().getResource("mainLayout.fxml");
try {
    loader.setLocation(path);            
    rootLayout = (BorderPane) loader.load();
} catch (IOException e){
    System.out.println("Not found: " + path);
    e.printStackTrace();
}        

// Toolbar View

loader = new FXMLLoader();

path = getClass().getResource("toolbar/toolbarView.fxml");  
try {                        

    // note you omitted this line:
    loader.setLocation(path);

    toolbarLayout = (VBox) loader.load();
} catch (IOException e){
    System.out.println("Not found: " + path);
    e.printStackTrace();
}

rootLayout.getChildren().add(toolbarLayout);

通过小心地取消设置作为先前加载过程的一部分的任何内容,可以重用 FXMLLoader:

It may be possible to reuse an FXMLLoader by carefully unsetting anything that has been set as part of the previous load process:

FXMLLoader loader = new FXMLLoader();                

// Root View

path = getClass().getResource("mainLayout.fxml");
try {
    loader.setLocation(path);            
    rootLayout = (BorderPane) loader.load();
} catch (IOException e){
    System.out.println("Not found: " + path);
    e.printStackTrace();
}     

loader.setRoot(null);
loader.setController(null);
loader.setResources(null);
loader.getNamespace().clear();   

// Toolbar View
path = getClass().getResource("toolbar/toolbarView.fxml");  

try {                        

    // note you omitted this line:
    loader.setLocation(path);

    toolbarLayout = (VBox) loader.load();
} catch (IOException e){
    System.out.println("Not found: " + path);
    e.printStackTrace();
}

rootLayout.getChildren().add(toolbarLayout);

但这确实不是预期的用途,并且可能对 FXMLLoader 实现的未来更改不健壮.

but this is really not the intended usage, and may not be robust to future changes to the FXMLLoader implementation.

这篇关于JavaFX 8 将多个 fxml 文件加载到边界窗格中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆