Wednesday, January 15, 2014

Home made JavaFX SceneBuilder

Ever wanted to have your own build of SceneBuilder? It's easy!



A month ago the source code of Scenebuilder was published. This was great news for the JavaFX community, since it is an example of a non trivial application written in JavaFX written by pros.

As far as I understand, you are even allowed to use the source of Scenebuilder (or parts of it) to build your own applications, since the code is released in a BSD style license. By the way, check out this site if you want to get an elevator pitch for various opensource licenses.

So what is necessary to have your own version of SceneBuilder?

Setting up Scenebuilder in Intellij


The source code for Scene builder can be found in the OpenJFX repository. If you have all tools, just clone the openjfx rt repository. If you are new to the game, you should follow the instructions given here.

After cloning the repository, you will find the source code for the Scene Builder in

rt/apps/scenebuilder

I gave it a try to just import this directory with IntelliJ 13 Community Edition (ignoring the build.xml file) and was able to set it up without build errors in no time! Very nice. The only thing I had to do manually was to set the project SDK to the latest JDK 8 preview and set the project language to 8.0 (with lambdas).


Then, in the project explorer, hit right mouse button and run the main method of the SceneBuilderApp - if you are lucky then you will be rewarded with the following screen:


I've changed the label.untitled in SceneBuilderApp.properties to 'My very own untitled Document' just to illustrate that it is not the default installation.

In addition, I would advise you to import JavaFX8 sources for Intellij like described here.

Project Layout


The project consists of two main parts, SceneBuilderApp and SceneBuilderKit.  The SceneBuilderApp contains the application logic and the SceneBuilderKit the infrastructure. The latter has far more classes, but they are also not application specific. I'm pretty sure that one could find one or the other gem in it. But as far as this post goes, I only describe some aspects of the SceneBuilderApp project.

FXML Handling in SceneBuilderApp


I was interested specifically in how SceneBuilder itself would manage the loading of FXML for its internal controllers.

The first thing which caught my attention was how the SceneBuilderApp project was structured. It seems like that every Controller, its fxml and css and other resources are grouped together in a package.

Controllers, FXML and resources grouped together
If you have a bunch of controllers, this will surely help to keep a clean structure. Using naming conventions clearly improves readability.

fxml and associated static images are placed in the same directory

The controllers extend an abstract controller, which provides utility methods for interacting with the stage. In essence, every controller has its reference to the stage baked in, which comes in handy for many things, for example when handling the setOnCloseRequest(...) on the stage.

Every Controller has its own FXMLLoader, which is fed with resources, the fxml and the controller class. What is interesting also is that right after the loading of the fxml took place and every widget is injected properly, it is checked if the expected widgets don't contain null references.

Like this you can shield yourself from accidental mismatch of FXML id's and fail fast - also a good habit, especially if the application code and the fxml code is maintained by more than one developer.

The FXML is loaded implicitly when you first access the controller - i.e. when you open up the window first time. In this context, checking out the AbstractWindowController and its derivatives is definitely some well spend time for an aspiring JavaFX developer. There are some gems in it like resizing the stage for various screens like seen in the method clampWindow - have a look :)



Example: PreferencesWindowController


Of course I won't discuss every class here, but I'll have a look at one example Controller, let's take the PreferencesWindowController. 

SceneBuilder's Preferences Dialog opened in SceneBuilder (v1.1)
First thing you see are the member declarations which are annotated with the @FXML annotation. Those attributes are injected by the FXMLLoader when loading the fxml ... but when and how does this happen?

head of PreferencesWindowController source



Actually, this problem was tackled in a nice way; every controller which extends from AbstractWindowController has a method called openWindow. This then triggers a chain of calls which ultimately result in the loading of the FXML and hence in injecting the right objects to the attributes of the concrete Controller. The following illustration may help here:

how controllers get to their fxml (pic was made with skitch btw) 

As far as I can tell the FXML gets loaded only once, and the code which does the magic is shared with all controllers. :) After loading the controllerDidLoadFxml() method is called, which resides again in the PreferencesWindowController. The preferences themselves are managed in a singleton named PreferencesController, and the values are now filled up for to the UI. 

At this point in time the ChangeListeners are initialized. The BackgroundImageListener for example changes the default background when selecting the corresponding ChoiceBox. The Listeners are all defined as static inner classes, which keeps things private to the Controller. 

Btw, for the permanent storage of the values the Preferences class was chosen - a nice utility for storing user or app specific values in a portable way.

There are many more aspects to discover in the SceneBuilder source code, I merely scratched the surface.  For me the most important thing is how to structure an application, best practices etc. - here the SceneBuilder source code is a great inspiration. 

It is really trivial to get to your own installation of SceneBuilder, and the code is very readable and definitely worth a look!