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的方式。我怀疑之所以做出此决定,是因为每个加载过程依赖于多个相互依赖的属性(位置、资源、控制器),因此,如果可以重用加载程序,很容易引入难以跟踪的错误。我错过了最后一部分:是的,加载程序保留了对根属性中加载的结构的引用。