Templating in JavaFX

Most web frameworks come with "Templating Support", which enables a common look and feel across all pages of the project. A desktop application in JavaFX could also make use of "Templating" pattern. There is not much documentation, that I found about templating in JavaFX 2.0.

It is however possible to do templating using javaFX available features and this is one such attempt.

About the Sample Module

The module contains following

  1. Template file "testtemplate.fxml"
  2. Template's constituents like header, footer etc (top.fxml, bottom.fxml and right.fxml)
  3. Application pages like first.fxml and second.fxml
  4. Controller classes

"Template"

Template file "testtemplate.fxml", creates a layout structure, in which there is a header component, a footer component, a right component and a "main" component. Files "top.fxml", "bottom.fxml" and "right.fxml" fill as the common component and are loaded using "<fx:include>".


<Pane layoutX="14.0" layoutY="14.0" prefHeight="740.0" prefWidth="996.0" style="-fx-background-color: white;&#10;-fx-border-radius: 20;&#10;-fx-background-radius: 20;">
  <children>
    <FlowPane prefHeight="733.0" prefWidth="996.0">
      <children>
        <AnchorPane id="top" prefHeight="175.0" prefWidth="996.0"  >
          <fx:include source="top.fxml"/>
        </AnchorPane>
        <AnchorPane id="main" prefHeight="474.0" prefWidth="867.0"  >
          <TextField id="dummyTxt" layoutX="4.0" layoutY="57.0" text="This is Text Field in template"></TextField>
        </AnchorPane>
        <AnchorPane id="right" prefHeight="474.0" prefWidth="129.0"  >
          <fx:include source="right.fxml"/>
        </AnchorPane>
        <AnchorPane id="bottom" prefHeight="77.0" prefWidth="996.0"   >
          <fx:include source="bottom.fxml"/>
        </AnchorPane>
      </children>
    </FlowPane>
  </children>
</Pane>

The template also contains an AnchorPain with id "main", it is a placeholder for application pages, which will be loaded by "Application" class.

"Main Application"
"MainController.java" implements "Application" and hence its the starting point of the application, once launched, JavaFX lifecycle calls  "Start(..)" on it. After setting the "Stage",  replaceSceneContent(..) is called, it contains all the template processing logic.

First the page to be displayed is loaded
// get main page
  Page mainPage = Page.getPage(_displayPage);
  main = mainPage.getPane();
  // get reference of Pane to be added to the template.
  main = (AnchorPane) main.lookup("#screenID");
  mainController = mainPage.getController();

then the template
  // get template
  templatePage = (AnchorPane) getTemplate(_template);
  // get reference of the "main" section in template i.e. where the new contents will be added
  AnchorPane origMain = (AnchorPane) templatePage.lookup("#main");

Page contents are added to the template by "Replacing" the children of Anchor Pane "main" with the contents of AnchorPane "screenID"
  // set contents of "mainPage" into the template.
  origMain.getChildren().setAll(main.getChildren());
A Scene is created and set onto stage
  // create scene.
Scene scene = new Scene(templatePage, 1200, 800);
  //set stage.
 stage.setScene(scene);
The resulting page that is displayed contains all four pieces i.e. header, footer, right and main.




Download source here



Prasanna Bhale

Note: Any note or comment is appreciated; it helps improve my blog.

7 comments:

  1. Hi great tutorial and exactly what I was searching for. Seam's your the only documentation for using templating. Anyhow when I run your example code it throws the following exception in Page.java row 37 => "javafx.fxml.LoadException: Root hasn't been set. Use method setRoot() before load." Any idea how to solve this?

    ReplyDelete
    Replies
    1. Hi Jan,

      Try running sample code with JDK 7 and Netbeans 8.0. Simply download the zip file, and open the project in Netbeans and run project.

      Delete
    2. I managed to make it work by replacing the tag <fx:root type="javafx.scene.layout.AnchorPane" with just <AnchorPane in all templates
      I don't see setRoot anywhere in the code, and fx:root requires it's usage: "the calling code must specify this value by calling the setRoot() method. "

      Delete
  2. Been looking for this...Go to the individual fxml file and switch the root tags, in my case I switched to ..... and it worked. Thanks!

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete