Warning: Declaration of Bootstrap_Walker_Nav_Menu::start_lvl(&$output, $depth) should be compatible with Walker_Nav_Menu::start_lvl(&$output, $depth = 0, $args = Array) in /homepages/10/d412081534/htdocs/clickandbuilds/WordPress/wordpress/wp-content/themes/stanleywp/functions/function-extras.php on line 61
FXML composition and nested controllers | buildpath.de

FXML composition – how to get the controller of an included FXML?

The possibility to declare the UI with an FXML in JavaFX is pretty cool. In bigger applications you have to split the views in different FXMLs which allows you to reuse and compose them in complex FXMLs. Therefore you have to use the  <fx:include>  statement.

The include enables you to get the reference of the embedded view element in your FXML-controller class. Be sure that you use the value of fx:id as the name of the member in the controller class. The FXMLLoader will pass the reference once the View was created.

[...]
<fx:include fx:id="embeddedView" source="SomeOtherView.fxml"/>
[...]
class AViewController{
    @FXML
    Parent embeddedView; //fx:id value as Variable name -> JavaFX injects the reference of the root element in the included FXML
}

Ok, we have the reference of the view element, but how can we get the reference of the embeddedView’s controller?  The solution is a naming convention which you can find here.


Short example (GitHub)

First Step: Create the FXML and the Java Controller which we want to embed:

 <AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="de.saxsys.fxml.RedView">
 <children>
 <Pane prefHeight="200.0" prefWidth="200.0">
 <children>
 <Button fx:id="button1" layoutX="68.0" layoutY="50.0" mnemonicParsing="false" text="Button" />
 <Button fx:id="button2" layoutX="68.0" layoutY="121.0" mnemonicParsing="false" text="Button" />
 </children>
 </Pane>
 </children>
</AnchorPane>
public class RedView {

    @FXML
    private Button button2;

    @FXML
    private Button button1;

    public void foo(String foo) {
       System.out.println(foo);
    }
}
redview

RedView.fxml

Second Step: Create the View which should embed the RedView.fxml. It’s not problem to do this using the Scene Builder. If you are using the developer preview of the Scene Builder 2, you may have problems to set an fx:id to the included elements – in this case add the fx:id attribute directly in the fxml code.

Add

Include FXML files using the SceneBuilder – Don’t forget to set the fx:id to the included element

 <VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.saxsys.fxml.MainView">
 <children>
 <!--Some element -->
 <Circle radius="100.0" stroke="BLACK" strokeType="INSIDE" />
 <!--our included FXML -->
 <fx:include fx:id="embeddedRedView" source="RedView.fxml" />
 <!--Some other element -->
 <Circle radius="100.0" stroke="BLACK" strokeType="INSIDE" />
 </children>
</VBox>
public class MainView {

	@FXML
	private Parent embeddedRedView; //embeddedElement

	@FXML
	private RedView embeddedRedViewController; // $embeddedElement+Controller

	public void initialize() {
		System.out.println(embeddedRedViewController);
		System.out.println(embeddedRedView);
                embeddedRedViewController.foo("It works"); //Console print "It works"
	}
}
Added

Embedded RedView.fxml into MainView.fxml using the Scene Builder

As you can see, we can get the reference of the nested controller by appending the word Controller in addition to the variable name of the embedded element.

public class Starter extends Application {

	@Override
	public void start(Stage stage) throws Exception {

		Parent parent = FXMLLoader.load(getClass().getResource("MainView.fxml"));
		Scene scene = new Scene(parent);
		stage.setScene(scene);
		stage.show();
	}

	public static void main(String[] args) {
		launch(args);
	}

}

Let’s try it – create an JavaFX application which loads the MainView.fxml and you’ll see the printed message on the console, which prooves that we accessed the reference to the FXML-controller of the embedded FXML element.

Example on GitHub

Share Button

9 Comments

  1. Pingback: JavaFX links of the week, July 13 // JavaFX News, Demos and Insight // FX Experience

  2. Pingback: Java desktop links of the week, July 13 « Jonathan Giles

  3. pablo911

    I was so glad to read about this but unfortunately I can’t compile your example downloaded from github.
    I have this error.
    Executing E:\windocs\Documents\NetBeansProjects\testor\dist\run1684577147\testor.jar using platform C:\Program Files\Java\jdk1.8.0/bin/java
    Exception in Application start method
    java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:367)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:305)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
    Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:894)
    at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:56)
    at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:158)
    at java.lang.Thread.run(Thread.java:744)
    Caused by: javafx.fxml.LoadException:
    file:/E:/windocs/Documents/NetBeansProjects/testor/dist/run1684577147/testor.jar!/de/saxsys/fxml/MainView.fxml:9

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2617)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2595)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3230)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3191)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3164)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3140)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3120)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3113)
    at de.saxsys.fxml.Starter.start(Starter.java:14)
    at com.sun.javafx.application.LauncherImpl$8.run(LauncherImpl.java:837)
    at com.sun.javafx.application.PlatformImpl$7.run(PlatformImpl.java:335)
    at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
    at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
    at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
    … 1 more
    Caused by: java.lang.IllegalArgumentException: Unable to coerce     to class javafx.scene.Node.
    at com.sun.javafx.fxml.BeanAdapter.coerce(BeanAdapter.java:495)
    at javafx.fxml.FXMLLoader$ValueElement.getListValue(FXMLLoader.java:801)
    at javafx.fxml.FXMLLoader$ValueElement.processCharacters(FXMLLoader.java:884)
    at javafx.fxml.FXMLLoader.processCharacters(FXMLLoader.java:2852)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2537)
    … 19 more
    Exception running application de.saxsys.fxml.Starter
    Java Result: 1

  4. pablo911

    It took me some time ;) but I manage to compile. Thank you very much for your help and for this example. It means so much to me.

  5. pablo911

    I don’t use github. I just downloaded the source files. So I don’t know this tool, but I will try when I will go back from my vacations. Another problem. :). There is a link to naming convention about embeddedView’s controller but when I click it there is 404 error. Thank you very much.

  6. Golzinne

    Hello,
    Thank you for this very nice example showing the possibility to access from the container to a method of the included fxml.
    Is it possible by pushing on one button of your RedView.fxml to reach a method in your MainView.java ?

    Thank you !

  7. brian

    If you include another fxml in SceneBuilder saying File -> Include -> Redview, the Redview becomes part of the MainView GUI. I thought just including it should be like a dialog and only show up when I click a button.

Leave a Reply to pablo911 Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>