内部自定义组件上未调用JavaFX initialize()

时间:2016-03-11 20:50:37

标签: java javafx

我正在使用javaFX,我需要将自定义组件放到我的场景中。因此,我的“main_pane.fxml”包含我的组件的网格窗格(例如DocumentModule)。

main_pane.fxml

<GridPane  xmlns:fx="http://javafx.com/fxml" fx:controller="GUI.MainPane" gridLinesVisible="true" > 
    <padding>
        <Insets bottom="0" top="0" left="0" right="0" />
    </padding>
     .
     .
     .
    <DocumentModule fx:id="documentModule"
                minWidth="200" minHeight="400" 
                GridPane.columnIndex="0" GridPane.rowIndex="1">
    .
    .
    .   
    </DocumentModule>
.
.
.

每个都在单独的fxml文件中定义。

document_module.fxml

<GridPane  xmlns:fx="http://javafx.com/fxml"  fx:controller="GUI.DocumentModule" >
    <padding>
        <Insets bottom="0" top="0" left="0" right="0" />
    </padding>
    <ToolBar fx:id="toolBar" GridPane.rowIndex = "0" GridPane.columnIndex = "0" orientation="HORIZONTAL" >
         .
         .
         .
    </ToolBar>
    <ScrollPane fx:id="scrollPane" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" GridPane.rowIndex = "1" GridPane.columnIndex = "0">
         <DocumentView fx:id="documentView"/>    
    </ScrollPane>
</GridPane>

问题是DocumentModule在构建后没有初始化。它的构造函数被调用但不是它的初始化(URL位置,ResourceBundle资源)方法。因此,不会注入来自fxml的对象。

文档模块的控制器代码

public class DocumentModule extends GridPane implements Initializable {
      protected Document document;

@FXML
private DocumentView documentView;

@FXML
private ScrollPane scrollPane;
.
.
.
public DocumentModule() {
      System.out.println("Document Module constructed.");
      //this is called correctly

}
@Override
public void initialize(URL location, ResourceBundle resources) {
     System.out.println("Document Module initialized.");
     //This is not called at all.
}

}

对于MainPane,一切正常,但不适用于任何内部组件。 组件树似乎构造正确,只是内部组件未初始化。内部组件也没有在应用程序场景中显示(如果我直接加载它们的fxml,如果我使用fx:include它们只是显示)。

MainPane控制器

public final class MainPane extends GridPane implements Initializable {

    @FXML
    private DocumentModule documentModule;

    @FXML
    private EditModule editModule;


    public MainPane() {
        System.out.println("Main Pane constructed.");
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        System.out.println("Main Pane initialized.");
    }

}

应用程序入口类'start method

@Override
public void start(Stage primaryStage) throws Exception {
     FXMLLoader fxmlLoader = new     FXMLLoader(getClass().getResource("main_pane.fxml"));
     GridPane root = fxmlLoader.load();
     Scene scene = new Scene(root, 800, 600);
     primaryStage.setMaximized(true);
     primaryStage.setMinWidth(800);
     primaryStage.setMinHeight(600);
     primaryStage.setTitle("App");
     primaryStage.setScene(scene);
     primaryStage.show();
} 

我没有找到任何相同问题的主题/页面/博客。他们中很少有类似的症状,但没有一个解决方案帮助了我。有没有人知道为什么不在内部组件上调用初始化?

谢谢! 汤姆

1 个答案:

答案 0 :(得分:3)

您的代码中没有任何地方实际加载document_module.fxml,因此永远不会创建在那里定义的元素。当initialize()加载该文件时,在控制器上为fxml文件调用FXMLLoader方法,但由于您从未加载fxml文件,因此永远不会调用initialize()方法。

主FXML中的元素<DocumentModule>仅导致DocumentModule类被实例化(通过调用其无参数构造函数),但是没有从那里到fxml文件的链接。

您似乎正在尝试关注FXML custom component pattern。为此,您需要在自定义组件构造函数中加载FXML文件。指定动态root并且不在fxml中指定控制器类,并在调用load之前在FXMLLoader上设置它们:

document_module.fxml:

<fx:root type="GridPane"  xmlns:fx="http://javafx.com/fxml">
    <padding>
        <Insets bottom="0" top="0" left="0" right="0" />
    </padding>
    <ToolBar fx:id="toolBar" GridPane.rowIndex = "0" GridPane.columnIndex = "0" orientation="HORIZONTAL" >
         .
         .
         .
    </ToolBar>
    <ScrollPane fx:id="scrollPane" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" GridPane.rowIndex = "1" GridPane.columnIndex = "0">
         <DocumentView fx:id="documentView"/>    
    </ScrollPane>
</fx:root>

DocumentModule.java:

public class DocumentModule extends GridPane implements Initializable {
      protected Document document;

    @FXML
    private DocumentView documentView;

    @FXML
    private ScrollPane scrollPane;
    .
    .
    .
    public DocumentModule() {
          System.out.println("Document Module constructed.");

          FXMLLoader loader = new FXMLLoader(getClass().getResource("document_module.fxml"));
          loader.setRoot(this);
          loader.setController(this);
          try {
              loader.load();
          } catch (IOException exc) {
              exc.printStackTrace();
              // this is pretty much fatal, so:
              System.exit(1);
         }

    }
    @Override
    public void initialize(URL location, ResourceBundle resources) {
         System.out.println("Document Module initialized.");
         // This will now be called after the @FXML-annotated fields are initialized.
    }

}