JavaFX8将多个fxml文件加载到borderpane

JavaFX8将多个fxml文件加载到borderpane,javafx,fxml,Javafx,Fxml,给定以下代码: 公共类主扩展应用程序{ private BorderPane rootLayout; private VBox toolbarLayout; private URL path; public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) { FXMLLoader lo

给定以下代码:

公共类主扩展应用程序{

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加载很好。如果我注释掉borderpane并将toolbarView设置为主视图,它也可以正常工作。 但是,如果我尝试将toolbarView加载到rootLayout中,rootLayout可以正常加载,但toolbarView会引发异常:

javafx.fxml.LoadException: Root value already specified.
显然,我对fxml加载过程的理解还不够透彻,所以有人能解释一下吗?为什么它认为我在试图再次设置根


为完整起见,这里是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文件根元素创建的对象的引用。假设您未使用,则根将作为加载过程的一部分设置为FXML根元素对应的对象。如果不是
null
在此阶段(即,如果已经设置),则会出现异常。
controller
属性也存在类似情况:如果FXML文件指定了
fx:controller
属性,则将控制器设置为
加载()的一部分
进程;如果它不是
null
,则引发异常

fxmloader
实际上只设计为使用一次,因为您有许多相互依赖的属性,这些属性通常作为加载过程的一部分进行设置:
root
location
controller
resources
,以及
命名空间的元素。因此,您应该真正创建一个新的
FXMLLo要加载的每个FXML文件的ader

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

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

但是这实际上不是预期的用途,并且对于将来对
fxmloader
实现的更改可能不可靠。

属性包含对FXML文件指定的结构的引用;即对FXML文件的根元素创建的对象的引用。假设您没有使用,根将在
load
过程中设置为与FXML根元素对应的对象的一部分。如果在此阶段它不是
null
(即,如果已经设置),则会出现异常。
controller
属性也存在类似情况:如果FXML文件指定了
fx:controller
属性,则控制器将被设置为
load()
过程的一部分;如果它不是
null
,则会引发异常

fxmloader
实际上只设计为使用一次,因为您有许多相互依赖的属性,这些属性通常作为加载过程的一部分进行设置:
root
location
controller
resources
,以及
命名空间的元素。因此,您应该真正创建一个新的
FXMLLo要加载的每个FXML文件的ader

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

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

但这并不是预期的用途,并且可能对
fxmloader
实现的未来更改不太可靠。

为了完整起见,这里有一个fxml:您不能对不同的fxml文件重复使用单个
fxmloader
。只需为您要加载的每个文件创建一个新的
fxmloader
。这很有效-谢谢但是为什么loader类不能被重用呢?我认为通过重置位置(loader.setLocation),它只需加载一个新的fxml,我在第二次“加载”之前就有这一行,但在加载失败时将其取出)。每个fxml加载程序是否都保留对其加载的fxml文件的内存引用?简言之,因为这是他们编写API的方式。我怀疑之所以做出此决定,是因为每个加载过程都依赖于多个相互依赖的属性(位置、资源、控制器),因此,如果可以重用加载程序,则很容易引入难以跟踪的错误。我错过了最后一部分:是的,加载程序保留了对
root
属性中加载的结构的引用。为完整起见,这里有一个fxml:对于这样的不同fxml文件,不能重用单个
fxmloader
。只需创建一个新的
FXMLLoader
对于要加载的每个文件都有效。谢谢。但是为什么不能重复使用loader类呢?我认为通过重置位置(loader.setLocation),它只需加载一个新的fxml,我在第二次“加载”之前就有这一行,但在失败时将其取出)。每个FXML加载程序是否保留对其加载的FXML文件的内存引用?简而言之,因为这是他们编写API的方式。我怀疑之所以做出此决定,是因为每个加载过程依赖于多个相互依赖的属性(位置、资源、控制器),因此,如果可以重用加载程序,很容易引入难以跟踪的错误。我错过了最后一部分:是的,加载程序保留了对
根属性中加载的结构的引用。