A Widget Picker Control in JavaFX

The following video shows a custom control in JavaFX that lets you select items from a list and position them in a grid. The items represent UI widgets, that is, JavaFX controls, with a defined size on the grid. The grid represents a page on which these widgets will be shown.

Advertisements

A Graph Editor in JavaFX

Another thing we’ve been working on is going to see the light of day soon: a graph editor for JavaFX. The current beta version provides the following main features:

  • create draggable, resizable nodes and connections between them
  • add multiple input or output connectors to a node
  • create joints inside a connection
  • add custom skins for nodes, connections, connectors, and joints
  • enhanced user experience through comprehensive styling during drag-and-drop actions

Internally, we use an EMF model to represent the UI objects and their state. The model is in sync with the UI at all times.

Here’s a short video of our current development version:

Using FXForm2 with EMF Models

Based on these considerations from July, we gave FXForm2 a shot for generating forms from EMF models. It worked quite smoothly after we wrote the factories that defined how the custom data types used in our models should be displayed.

We found a few things that are worth noting:

  1. Using Java Bean Validation
    In order to validate our EMF models using the Java Bean Validation API (JSR-303) that comes with FXForm2, we wrote wrapper classes for those model elements that we wanted to add constraints to. We decided to not touch the generated code.
  2. Using another validation implementationFXForm2 can use any implementation of JSR-303. Using the Hibernate implementation is suggested on the FXForm2 website, but we found it easy to supply our own implementation based on EMF’s validation features such as the Diagnostician class.
  3. Validation philosophies
    When you enter an invalid value into a field, FXForm2 won’t update the corresponding model attribute. The value you see in the form differs from the value in the model. The model thus always has a valid state.EMF validation typically works in a different way: you start the validation operation only after all model values were set. This allows for invalid states of the model.
  4. Dynamic beans
    An open issue
    seems to be (as least for us) the handling of a String-to-String Map attribute inside an EMF bean class that stores user-supplied key-value pairs which should be displayed as regular attributes of the bean. Antoine suggested a solution based on a custom control (with a factory and a skin), but it comes with a different visual appearance for the user-defined attributes. This is work in progress.

Implementing Breadcrumbs in JavaFX

I’ve been struggling to implement a JavaFX breadcrumbs bar using a ToolBar with a few Button items in it. The breadcrumbs should have the shape of an arrow as in the example shown in Loop81’s blog post:

http://www.loop81.com/2011/11/javafx-2-breadcrumbs-and-styling.html

The breadcrumbs bar in the Ensemble application uses the same approach. What I don’t like about this implementation is the use of rather sophisticated CSS rules in combination with static images.

.breadcrumbs .item {
  -fx-background-color: null;
  -fx-background-radius: 0;
  -fx-background-insets: 0;
  -fx-border-color: null;
  -fx-border-insets: 0;
  -fx-border-image-source: url("crumb.png");
  -fx-border-image-slice: 1 10 1 10 fill;
  -fx-border-image-width: 1 10 1 10;
  -fx-border-image-repeat: stretch;
  -fx-font-size: 18px;
}

.breadcrumbs .item:hover {
  -fx-border-image-source: url("crumb-hover.png");
}

.breadcrumbs .alone {
  -fx-border-image-width: 0 0 0 0;
  -fx-border-image-repeat: stretch;
  -fx-border-image-source: url("crumb-selected.png");
  -fx-border-color: transparent #6e737d transparent rgba(255,255,255,0.3) , transparent rgba(255,255,255,0.3) transparent transparent;
  -fx-border-insets: 0 0 1 0, 1;
}

...

As another approach, I tried to define an arrow-shaped SVG path (using the -fx-shape CSS rule) for the breadcrumb buttons, but I encountered scaling issues. The width of the shape must depend on the width of the text displayed in the button, which could not be achieved using CSS.

.breadcrumbs .item {
  ...
  -fx-shape: "M 0 0 L 100 0 L 130 15 L 100 30 L 0 30 z";
}

So I defined the shape in Java code and used it to set the button’s clip. The width of the shape was computed dynamically based on the button’s text plus two magic numbers for the correct scaling of the shape. This worked nicely, but came with the burden of those two magic numbers that worked well only for the particular font I used.

int textLength = button.getText.length();
// scaling and padding are magic numbers
int mainWidth = TEXT_SCALING * textLength + TEXT_PADDING;

// build the following shape
//   --------
//  \         \
//  /         /
//   --------
Path path = new Path();

// start in upper left corner
MoveTo e1 = new MoveTo(0, 0);

// draw upper horizontal line
HLineTo e2 = new HLineTo(ARROW_WIDTH + mainWidth);

// draw upper part of right arrow
LineTo e3 = new LineTo(ARROW_WIDTH + mainWidth + ARROW_WIDTH, ARROW_HEIGHT / 2.0);

// draw lower part of right arrow
LineTo e4 = new LineTo(ARROW_WIDTH + mainWidth, ARROW_HEIGHT);

// draw lower horizontal line
HLineTo e5 = new HLineTo(0);

// draw lower part of left arrow
LineTo e6 = new LineTo(ARROW_WIDTH, ARROW_HEIGHT / 2.0);

// close path
ClosePath e7 = new ClosePath();
path.getElements().addAll(e1, e2, e3, e4, e5, e6, e7);

// this is a dummy color to fill the shape, it won't be visible
path.setFill(Color.BLACK);

// set path as shape for button
button.setClip(path);

// make button width equal to width of shape
double buttonWidth = 2 * ARROW_WIDTH + mainWidth;
button.setMinWidth(buttonWidth);
button.setMaxWidth(buttonWidth);
button.setPrefWidth(buttonWidth);

In yet another attempt, I implemented a breadcrumbs bar in which every breadcrumb is represented by three buttons: one for the left-hand part of the arrow, one for the central part (showing the text), and one for the right-hand part. This allowed me to work with fixed-width shapes on the left and on the right plus a regular-shaped (rectangular) button in the middle. The obvious drawback was the management of all the extra buttons including the correct update of hover effects for the outer buttons when the mouse was over the inner button, and vice versa.

I don’t think there a JavaFX library out there that provides the functionality I need, so is there anyone with experience in implementing a breadcrumbs bar? Any thoughts or recommendations? Are there solutions that do not come with any of the drawbacks mentioned above?

Any help will be much appreciated.

Update (2013-11-06):
Andy Till suggested an implementation that won my heart: bind the x property of the horizontal lines in the arrow shape to the button’s width. Since the button’s width gets updated to fit the text, the shape will always have the correct width. No need for magic numbers. Thanks, Andy!

// build the following shape
//   --------
//  \         \
//  /         /
//   --------
Path path = new Path();

// begin in the upper left corner
MoveTo e1 = new MoveTo(0, 0);

// draw a horizontal line that defines the width of the shape
HLineTo e2 = new HLineTo();
// bind the width of the shape to the width of the button
e2.xProperty().bind(button.widthProperty().subtract(ARROW_WIDTH));

// draw upper part of right arrow
LineTo e3 = new LineTo();
// the x endpoint of this line depends on the x property of line e2
e3.xProperty().bind(e2.xProperty().add(ARROW_WIDTH));
e3.setY(ARROW_HEIGHT / 2.0);

// draw lower part of right arrow
LineTo e4 = new LineTo();
// the x endpoint of this line depends on the x property of line e2
e4.xProperty().bind(e2.xProperty());
e4.setY(ARROW_HEIGHT);

// draw lower horizontal line
HLineTo e5 = new HLineTo(0);

// draw lower part of left arrow
LineTo e6 = new LineTo(ARROW_WIDTH, ARROW_HEIGHT / 2.0);

// close path
ClosePath e7 = new ClosePath();

path.getElements().addAll(e1, e2, e3, e4, e5, e6, e7);
// this is a dummy color to fill the shape, it won't be visible
path.setFill(Color.BLACK);

// set path as button shape
button.setClip(path);

And this is what my breadcrumbs bar looks like now:
breadcrumbs

Zombieland

Based on Jasper Potts’ 3DViewer app (with support for importing OBJ, MAX, and MAYA files), we are developing an importer for FBX files into JavaFX. Below is a picture of our developer trying to understand the FBX format a screenshot of the extended 3DViewer app after loading an FBX file containing a zombie.

A JavaFX viewer application showing a Zombie object imported from an FBX file.

A JavaFX viewer application showing a Zombie object imported from an FBX file.

For implementing this importer, we took

The importer currently loads all mesh, material, and texture information from all nodes in the FBX graph. We support ASCII and binary file formats.

We do not yet load light, camera, and animation data (the former two should be quite simple, while animation will probably take longer).

Our work is still ongoing, and I hope we can have an improved version soon. Stay tuned!

GUI Generation with JavaFX

Recently, we have had a look at JavaFX libraries for generating UIs in a dynamic way. The idea is that we have a data model (a JavaBean class, an EMF model class, a model class with JavaFX properties,…) as input for some GUI builder that takes the model and generates a matching user interface with bindings between the model and the JavaFX controls. In a perfect world, this library would allow us to use a variety of data models and to customise the generated user interface.

We have had three candidates (all open source). As we use EMF a lot, two of them are based on EMF models.

1. FXForm2

http://dooapp.github.io/FXForm2/

This pops up early when you are looking for UI generation libraries for JavaFX. As the name implies, it is meant for generating forms from model beans.

The main features include:

  • Automatic form generation and binding to bean properties
  • CSS support
  • Bean Validation handling (JSR 303)
  • Fields reordering and filtering
  • Tooltips
  • Localization

It takes three lines to add a generated form to your JavaFX scene graph:

MyBean myBean = new MyBean(); // get an instance of the bean to be edited
Node fxForm = new FXForm(myBean);  // create the FXForm node for your bean
root.getChildren.add(fxForm);  // add it to your scene graph

2. EMF Edit for JavaFX

http://tomsondev.bestsolution.at/2012/12/13/emf-edit-support-is-coming-to-javafx-via-efxclipse/

This library has a broader scope than FXForm2 as it can generate an entire RCP application with a sophisticated visual model editor rather than just a couple of form fields. Or you can define your own controls and easily bind your EMF model instances to these controls, including support for drag & drop and undo/redo commands. An example of a user interface based on a “Contacts” model can be seen in Tom’s video from the link above.

3. EMF Client Platform

http://eclipse.org/emfclient/index.html

This takes the idea of EMF Edit one step further. As the ECP website says:

The goal is to provide a one-click application based on a given EMF model. Besides the EMF model, no additional components have to be developed or generated.

So when you have your EMF model, you are only one click away from a complete client application with a model explorer, an editor, a persistence mechanism, and a couple of other nice things. The editor for the model attributes is similar to the data form generated by FXForm2, but it is embedded in an entire application whose pieces are customisable and extensible.

The bad news is that there is currently no JavaFX support for ECP.
[Update]
As Tom Schindl has pointed out in the comments section, there is a first version of JavaFX support for ECP in one of the development branches of the e(fx)clipse project. See here.

4. Summary

We have not found the perfect solution yet. FXForm2 has a promising approach for easily generating forms, of which we are going to have a lot in our final product. It requires some tweaks to make it work with EMF models but that is a small obstacle. What worries me a bit is the maturity of this library: the latest version is 0.2.2. So is it ready for production use? Well, there’s at least one real-world application that uses it.

EMF Edit is a very powerful framework but does not generate controls on the granularity we require for most parts of our application. It will certainly be of use for fancy features like drag & drop and the command stack. Maybe we can combine its strengths with the power of FXForm2 for generating really rich forms.

The EMF Client platform has a very appealing one-click approach but it lacks support for JavaFX. Once this limitation is gone, we may give it another look. A major question will then be how far we can customise the basic layout of the generated application which by default is very different from what we have in mind for our user interface.