【问题标题】:JavaFX 8 loading multiple fxml files into borderpaneJavaFX 8 将多个 fxml 文件加载到边框窗格中
【发布时间】:2015-10-15 17:53:15
【问题描述】:

给定以下代码:

公共类主扩展应用程序{

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会抛出异常:

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>

【问题讨论】:

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

标签: javafx fxml


【解决方案1】:

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

FXMLLoader 实际上只设计为使用一次,因为您有许多相互依赖的属性,这些属性通常设置为加载过程的一部分:rootlocationcontrollerresourcesnamespace 的元素。所以你真的应该为你想要加载的每个 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 实现的未来更改不可靠。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    相关资源
    最近更新 更多