DataFX Controller Framework Preview
Today we released the version 2.0 of DataFX. Thanks for all the feedback that we received with the last release candidates. As a next step we will work on DataFX 8.0 that will use Java 8 and JavaFX 8. One of the new features that will be part of the next release are currently in development. Today I will show a first preview to DataFX 8.0.
The last month I added a new framework to DataFX. This framework should help to create the views of applications, define actions on them and create flows that contain a subset of views.
To show the features of the framework I will create a simple JavaFX application. The app should manage persons. Persons can be loaded, created, edited and deleted by the app. Let’s have a first look on the general concept of the application:
As you can see the app contains 3 different views:
- a master view that shows all persons in a list
- a create view that can add a new person
- a edit view to edit a person
All this views are linked by actions (“save”, “add”, etc.) that will manipulate the data or show another view. First of all we want to take a look on the data model. Here a simple Person class is defined:
This class defines a person. Because we want to handle a list of persons we need another class that in our case defines the global data model:
This class defines a list of persons and the currently selected person by an index. To create a first default set of persons that can be loaded we define a additional class. In a real world application this class could wrap a database connection, for example:
After the data model is defined we can create the first view. Let’s start with the master view. To create the view Scene Builder can be used. Here we can easily design the following view:
For all needed controls IDs are defined in the FXML. Normally you need to define a controller class in FXML. This is not needed for the DataFX Controller API. Instead of this we can bind a controller and a FXML view by the use of an annotation. As the next step a controller is needed. As a first step we create a small controller with some additional annotations:
In this first version there is only one difference to the default JavaFX APIs: The FXMLController annotation is added. This annotation defines the link between the controller class and the FXML file. As a next step we want to create a data model. Here the next benefit of the framework can be used: Context Dependency Injection. To add a model to the the controller we can simple inject it:
To explain what happens here the CDI module in DataFX need to be described a little bit more. As in JEE CDI different scopes are supported in DataFX:
All this scopes have a different context is is managed by the framework. All items that are part of the ViewScope have a lifetime of one view. A view is for example the master view in our example. The Application scope is defined as a global scope. All items in this scopes are singletons. The Singleton scope that is already defined in javax.inject can be used here, too. The flow scope defines a flow of views. In our example we will create one flow that handles all the defines views. In a more complex applications different flows can be handled. You can easily create a flow for each tap in a business application, for example. Additionally DataFX supports the dependent scope as it is defined in JEE.
The data model in our application need to be defined in the flow scope. It should be accessed from all views in this scope. To do so a scope annotation need to be added to the class:
Once this is done we can easily inject the data model in our view:
As a next step some initial setup is needed. To do so the PostConstruct annotation is supported by the DataFX framework:
Now the ListView is bounded to the data model. To create some basic data a action is needed. This action should fire when the “load” button is pressed. First we create a simple class that handles the action:
As you can see the injected model is used here, too. This task can be added to the button by the use of the Flow API. This API defines a flow through all views. The first very simply version of our flow looks like this:
This defines a flow that starts with the master view and adds a task action to this view. The action is defined by the id “load”. To bind this action to the load button only a additional annotation is needed in the controller:
Now the first version of the application can be started. To do so we need a main class that adds the flow to a JavaFX scene:
The DefaultFlowContainer class is used in the code. This class is a default implementation of a Pane that wraps a flow. When you start the application the “load” button can be used to load the list of persons. Because of the JavaFX binding the result will be shown directly:
As a next step we want to add the edit action to the application. Here an additional view need to be created by Scene Builder:
Additionally a controller class is needed. This class uses the described features:
The data model is injected to the controller. Because it is defined in the flow scope it will be the same instance as in the master view. Additionally some bindings will be created to bind the UI controls to the data model. A flow action is added to the save button. This action is defined by the “save” ID. To add this view to the flow only some additional code is needed:
As you can see two links are added to the flow. This links are actions that will change the current view of the flow. In this cases we want to link from the master page to the edit page and vice versa. When you start the application now you can edit all persons that are part of the list:
As a next step we want to add the remove action to the master view. This can be easily done by adding another action:
As the import action this action need to be defined in the flow and bound to a button:
Additionally the flow need to be changed:
The Flow API of DataFX supports different types of actions. The link action and the task action are used in this example until now. As a next step we want to add the view to create new persons. Here we will use some additional features of the framework.
Because the view should look like the edit view we can reuse the FXML here. Additonally a controller is needed. Here is a first basic version:
The data that is added in the view will be stored in the two properties that are defined in the view. Once everything is fine a new person should be created and added to the data model. To do so we use a new action type: The MethodAction. With this type a method of the controller can easily bound to an button. To do so we add a method with the needed annotation in the controller class:
Like all other actions this action need to be added to the flow. Because we want to add the person to the data model and then jump back to the master view a action chain is used here:
A action chain defines a list of actions that will be handled. In this example the “save” button is bound to an action chain that first calls the “addPerson” method and then links to the master view. By doing so new persons can be created.
Next to all the action types that are shown in this example DataFX will provide additional ones and the ability to add custom action classes.
As a last step we want to add validation. When a new person is created we want to check if the name is not null. The DataFX API supports the default Java Bean Validation and adds to support for JavaFX properties. Because of this we can easily add a NotNull annotation to the name property:
To validate the data of the view a validation action can be added to the action chain that is bound to the “save” button:
The validation action automatically validates all validatable fields that are defined in the controller. Groups, as defined in the Java Bean Valdidation, are supported, too. When any data is not valid the action chain will stop.
To provide feedback to the user some additional code is needed. The validator can be injected to the controller:
Now we can add a event handler to the validator that will show violations on screen:
Once this is done the view will show violations on the screen:
This example shows some of the DataFX Controller features. The complete API is not finished yet and can be found in a branch of the DataFX repository. I hope to receive some feedback about this example.