- JavaFX 2.0, FXML and Spring
- Better Controller Injection
- Multiple Controllers with Shared Resources
- Views within Views, Controllers within Controllers
- Generic Controllers
- Client Server with JavaFX 2 and Hessian (+Guice +FXML)
- JFX Flow early access
- JavaFX and MVP – a smörgåsbord of design patterns
- JavaFX and Maven
- Porting “First Contact” to Spring
- Going Remote – JavaFX and Spring Remoting
- JavaFX and persistence: adding database support
- Search like you mean it
- Captains Log
- JavaFX and Spring Security
GUIs are like onions (and Ogres) – they have layers. There are very few GUIs out there that show a single screen and that’s it. In traditional desktop applications we often end up with a screen full of complex sub-views, some tab panes perhaps, and often way too many popup dialogs. In a web app, we usually end up with a series of interconnected pages that hyperlink between each other, many of which contain sub-pages of information within them.
In either case we end up with the problem of how to embed and link our views and yet still keep them as nice, contained, reusable modules of code. At the core of it, all the presentation frameworks and architectures out there aim to address this issues in some way or another and FXML is no different. We just specify <fx:include> in our FXML file and the loader will magically pull in a second FXML file and drop it into our parent file. Great!
But there’s a problem. We’ve just come up with a great way to use dependency injection with our controllers and share resources between them, but this requires us to expose our controllers through the factory with the @Bean annotation. If the FXMLLoader magically creates our sub-views and sub-controllers for us, we’re back to square one.
So we need another way. In fact we need to make a mental gear change for this and come at it from another angle. The FXML approach assembles views by creating aggregates of other views, the controllers are somewhat of an afterthought. Sub-controllers have no real knowledge of their parent or child controllers, yet the views do. When we stop and think about this, shouldn’t it be the other way around? Our controllers should be the ‘brains’ of the operation, the views are just there to look pretty and smile.
Looking at if from this new angle, what we really need is a way to assemble controllers with sub-controllers and have these tell their corresponding views how to connect up with each other. As it turns out we’ve just put a mechanism in place for doing just that – dependency injection and a factory is exactly what we need to make this work.
In the rest of this post, I’m going to walk through a small example that has a three controllers. The MainController provides the outer container and a way to switch between the two sub-controllers (Page1Controller and Page2Controller) using a tab pane style approach. I’ll keep the controllers deliberately simple to get the idea across and, as usual, we’ll add more complexity in later posts.
Our end GUI is going to look something like this:
Let’s start with the simple stuff. Our two sub-pages will be simple, dumb controllers and views, just to give us something to work with. You can see the code for these here:
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="view"
fx:controller="com.zenjava.jfxspring.MainController"
xmlns:fx="http://javafx.com/fxml">
<styleClass> <String fx:value="welcome"/> </styleClass>
<top>
<HBox spacing="4">
<children>
<Button text="Show Page 1" onAction="#showPage1"/>
<Button text="Show Page 2" onAction="#showPage2"/>
</children>
</HBox>
</top>
<center>
<BorderPane fx:id="contentArea"/>
</center>
</BorderPane>
So it’s left to our MainController to actually show the appropriate view when each button is selected. To do this it needs to get hold of the Page1 and Page2 controllers and then it can happily access the views for each. Using Spring’s @Autowired annotation we can easily achieve this, so long as all three controllers are exposed by our factory class. It all looks a little like this:
MainController.java
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.layout.BorderPane;
import org.springframework.beans.factory.annotation.Autowired;
public class MainController
{
@FXML private Parent view;
@FXML private BorderPane contentArea;
@Autowired private Page1Controller page1Controller;
@Autowired private Page2Controller page2Controller;
public Parent getView()
{
return view;
}
public void showPage1(ActionEvent event)
{
contentArea.setCenter(page1Controller.getView());
}
public void showPage2(ActionEvent event)
{
contentArea.setCenter(page2Controller.getView());
}
}
SampleAppFactory.java
import javafx.fxml.FXMLLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.io.InputStream;
@Configuration
public class SampleAppFactory
{
@Bean
public MainController mainController() throws IOException
{
return (MainController) loadController("/Main.fxml");
}
@Bean
public Page1Controller page1Controller() throws IOException
{
return (Page1Controller) loadController("/Page1.fxml");
}
@Bean
public Page2Controller page2Controller() throws IOException
{
return (Page2Controller) loadController("/Page2.fxml");
}
protected Object loadController(String url) throws IOException
{
// as before (see full code for details)
}
}
In the end, embedding views and controllers is actually quite simple with this approach. Architecturally it feels pretty clean, each of our child controllers is a stand-alone, reusable piece of code. Our parent controller has some fairly intimate relations with its children, and often this will be OK. In a lot of cases however, we will want a parent that is less tightly bound to its children. In the next post we’ll have a go at achieving that.
The full code for this post can be found at: http://code.google.com/p/jfxee/source/browse/trunk/jfxee4


Nice blog! The FXML is quiet great. But can we set all the value of standard JavaFX Class value? from FXML.?
Thanks.
Narayan
Hi Narayan,
Yep, FXML just uses reflection to call the methods on your classes so you can call anything (even methods you create yourself). You can read all about it in the FXML guides:
http://download.oracle.com/javafx/2.0/fxml_get_started/jfxpub-fxml_get_started.htm
http://download.oracle.com/javafx/2.0/api/javafx/fxml/doc-files/introduction_to_fxml.html
Nice stuff! I’m converting my application which was getting a bit too monolithic using your blog entries (albeit with Guice), thanks a lot for the information.
Hi, I’m having difficulty making the sample works. I copied every files and upon running I get the result “java.lang.IllegalStateException: Cannot load configuration class: javafxapplication.SampleAppFactory”, please help … thanks.