JavaFX 8将多个fxml文件加载到borderpane中 [英] JavaFX 8 loading multiple fxml files into borderpane
问题描述
给出以下代码:
公共类Main扩展Application {
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设置为主视图,它也可以正常工作. 但是,如果我尝试将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?
为完整起见,这是工具栏View.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文件的根元素创建的对象.假设您没有使用动态根"(<fx:root>
)模式,则根将作为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
,location
,controller
,resources
和namespace
的元素.因此,您实际上应该为要加载的每个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文件加载到borderpane中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!