JavaFX 8 将多个 fxml 文件加载到 borderpane
JavaFX 8 loading multiple fxml files into borderpane
给定以下代码:
public class 主要扩展应用程序 {
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 加载过程,所以有人可以解释一下吗?为什么它认为我正在尝试再次设置 root?
为了完整起见,这里是 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 文件的根元素创建的对象。假设您没有使用 "dynamic root" (<fx:root>
) pattern,root 将作为 load
过程的一部分设置为对应于 FXML 根元素的对象。如果在这个阶段它不是 null
(即如果它已经被设置),那么你会得到一个异常。 controller
属性 也是如此:如果 FXML 文件指定了 fx:controller
属性,控制器将被设置为 load()
进程的一部分;如果不是null
,则抛出异常。
FXMLLoader
实际上只设计为使用一次,因为您有许多相互依赖的属性,这些属性通常设置为加载过程的一部分:root
、location
、controller
、resources
和 namespace
的元素。所以你真的应该为每个你想加载的 FXML 文件创建一个新的 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();
}
// 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);
但这确实不是预期的用途,并且可能对 FXMLLoader
实现的未来更改不稳健。
给定以下代码:
public class 主要扩展应用程序 {
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 加载过程,所以有人可以解释一下吗?为什么它认为我正在尝试再次设置 root?
为了完整起见,这里是 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 文件的根元素创建的对象。假设您没有使用 "dynamic root" (<fx:root>
) pattern,root 将作为 load
过程的一部分设置为对应于 FXML 根元素的对象。如果在这个阶段它不是 null
(即如果它已经被设置),那么你会得到一个异常。 controller
属性 也是如此:如果 FXML 文件指定了 fx:controller
属性,控制器将被设置为 load()
进程的一部分;如果不是null
,则抛出异常。
FXMLLoader
实际上只设计为使用一次,因为您有许多相互依赖的属性,这些属性通常设置为加载过程的一部分:root
、location
、controller
、resources
和 namespace
的元素。所以你真的应该为每个你想加载的 FXML 文件创建一个新的 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();
}
// 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);
但这确实不是预期的用途,并且可能对 FXMLLoader
实现的未来更改不稳健。