JavaFX Tip 12: Define Icons in CSS

When you are a UI developer coming from Swing like me then there is a good chance that you are still setting images / icons directly in your code. Most likely something like this:

import javafx.scene.control.Label;
import javafx.scene.image.ImageView;

public class MyLabel extends Label {

    public MyLabel() {
        setGraphic(new ImageView(MyLabel.class.
            getResource("image.gif").toExternalForm()));
    }
}

ImageExample

In this example the image file is looked up via Class.getResource(), the URL is passed to the constructor of the ImageView node and this node is set as the “graphic” property on the label.

This approach works perfectly well but with JavaFX there is a more elegant way. You can put the image definition into a CSS file, making it easy for your and / or others to replace it (once the marketing department has decided to change the corporate identity once again).

The same result as above can be achieved this way:

import javafx.scene.control.Label;

public class CSSLabel extends Label {

    public CSSLabel() {
        getStyleClass().add("folder-icon");
    }
}

Now you obviously need a CSS file as well:

.folder-icon {
	-fx-graphic: url("image.gif");
}

And in your application you need to add the stylesheet to your scene graph. Here we are adding it to the scene.

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MyApplication extends Application {

	public void start(Stage primaryStage) throws 
		                             Exception {
		CSSLabel label = new CSSLabel();
		label.setText("Folder");
		label.setAlignment(Pos.CENTER);
		
		Scene scene = new Scene(label);
		scene.getStylesheets().add(MyApplication.class.
		      getResource("test.css").toExternalForm());
		
		primaryStage.setScene(scene);
		
		primaryStage.setTitle("Image Example");
		primaryStage.setWidth(250);
		primaryStage.setHeight(100);
		primaryStage.show();
	}

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

With this approach you have a clean separation of your controls and their apperance and you allow for easy customization as well.

JavaFX Tip 11: Updating Read-Only Properties

Custom controls often feature “read-only” properties. This means that they can not be set from outside the control, not even from their own skin class. It is often the behaviour of a control that leads to a change of the read-only property. In JavaFX this behaviour can be implemented in the control itself and in the skin. So we sometimes end up with a skin wanting to update a read-only property of the control. How can this be done?

Backdoor: Property Map

The solution is quite simple: use the properties map of the control as a backdoor to the control class. The properties map is observable, so if the skin sets a value in the map then the control will be informed and can update the value of the read-only property itself.

The Control Class

The property in the control class might be defined like this:

private final ReadOnlyDoubleWrapper myReadOnly =
   new ReadOnlyDoubleWrapper();

public final ReadOnlyDoubleProperty myReadOnlyProperty() {
    return myReadOnly.getReadOnlyProperty();
}

public final Double getMyReadOnly() {
    return myReadOnly.get();
}

To update the property the control class registers a listener with its own property map and listens for changes to the property called “myReadOnly”:

getProperties().addListener(new MapChangeListener() {
  public void onChanged(Change c) {
    if (c.wasAdded() && "myReadOnly".equals(c.getKey())) {
      if (c.getValueAdded() instanceof Number) {
        myReadOnly.set((Double) c.getValueAdded());
      }
      getProperties().remove("myReadOnly");
    }
  }
});

Important: make sure to use a unique name for the property key or you might end up with naming conflicts. It is good practise to prefix the name with the package name of your control, e.g. com.myframework.myReadOnly.

The Skin Class

Now the skin class can update the property by setting the property value in the control’s property map:

getSkinnable().getProperties().put("myReadOnly", 42);

JavaFX Tip 10: Custom Composite Controls

Writing custom controls in JavaFX is a simple and straight forward process. A control class is needed for controlling the state of the control (hence the name). A skin class is needed for the apperance of the control. And more often than not a CSS file for customizing the apperance.

A common approach for controls is to hide the nodes they are using inside their skin class. The TextField control for example uses two instances of javafx.scene.text.Text. One for the regular text, one for the prompt text. These nodes are not accessible via the TextField API. If you want to get a reference to them you would need to call the lookup(String) method on Node. So far so good. It is actually hard to think of use cases where you would actually need access to the Text nodes.

But…

It becomes a whole different story if you develop complex custom controls. The FlexGanttFX Gantt charting framework is one example. The GanttChart control consists of many other complex controls and following the “separation of concerns” principle these controls carry all those methods and properties that are relevant for them to work properly. If these controls were hidden inside the skin of the Gantt chart then there would be no way to access them and the Gantt chart control would need to implement a whole buch of delegation methods. This would completely clutter the Gantt chart API. For this reason the GanttChart class does provide accessor methods to its child controls and even factory methods for creating the child nodes.

Example

The following screenshot shows a new control I am currently working on for the ControlsFX project. I am calling it ListSelectionView and it features two ListView instances. The user can move items from one list to another by either double clicking on them or by using the buttons in the middle. 

ListSelectionView 

List views are complex controls. They have their own data and selection models, their own cell factories, they fire events, and so on and so on. All of these things we might want to either customize or listen to. Something hard to do if the views are hidden in the skin class. The solution is to create the list views inside the control class via protected factory methods and to provide accessor methods.

The following code fragment shows the pattern that can be used:

public class ListSelectionView<T> extends Control {

    private ListView<T> sourceListView;
    private ListView<T> targetListView;

    public ListSelectionView() {
        sourceListView = createSourceListView();
        targetListView = createTargetListView();
    }

    protected ListView<T> createSourceListView() {
        return new ListView<>();
    }

    protected ListView<T> createTargetListView() {
        return new ListView<>();
    }

    public final ListView<T> getSourceListView() {
        return sourceListView;
    }

    public final ListView<T> getTargetListView() {
        return targetListView;
    }
}

The factory methods can be used to create standard ListView instances and configure them right there or to return already existing ListView specializations. A company called ACME might already provide a standard set of controls (that implement the company’s marketing concept). Then the factory methods might return a control called ACMEListView.

JavaFX Tip 9: Do Not Mix Swing / JavaFX

The JavaFX team has tried very hard to convince us that migrating from Swing to JavaFX is easy because of the option to embed Swing content in a JavaFX UI and vice versa. I must admit that I never tried it myself but based on the feedback I am getting from my customers I can only recommend to not mix Swing and JavaFX. At the time of this writing there were over 200 unresolved issues (120+ bugs) related to Swing integration (registered with the JavaFX issue management system).

Issue Types

The following is a list of issues that you might encounter if you still decide to go with it:

  • Appearance – there will always be a noticeable difference between the parts that were done in Swing and those that were done in JavaFX. Fields will show different font quality, different borders, different focus highlighting, etc….
  • Flickering – you might encounter flickering in your UI
  • Behaviour – controls will behave differently. The user will be able to scroll JavaFX controls with a gesture but not the Swing controls. The columns of a JavaFX TableView control will autosize when you double click the line between two column headers, the Swing JTable does not.
  • Threading – you are constantly dealing with issues related to the use of two different UI threads (the Swing EDT and the JavaFX application thread). You will run into freezing UIs and inconsistent state issues.
  • Window Management - controlling which window will be on top of which other windows and which window is blocking input (modality) for other windows becomes difficult / impossible. Popup windows might no longer hide themselves automatically.
  • Focus Handling- the wrong window might get the focus. Focus traversal between Swing controls and JavaFX controls might not work.
  • Context Menus – you might not be able to close the menu by clicking somewhere else in the UI or you might end up with two context menus open at the same time (one controlled by JavaFX, one controlled by Swing).
  • Cursor – setting different cursors on different controls / components will not work as expected.
  • Drag and Drop – wether within the SwingNode itself or between Swing and JavaFX, exceptions are heading your way.
  • Performance – the performance / rendering speed of JavaFX controls mixed with Swing components will degrade

Conclusion

What does this mean now? Well, it means that in the end you will not save time if you are following the Swing/JavaFX mixing strategy. At least not if quality is important to you. If your focus is only on making features available then maybe, but if you want to ship a commercial grade / professional application, then no.

If you have already decided to migrate to JavaFX, then do the Full Monty and redo your entire application in JavaFX, it is worth the wait.

JavaFX Tip 8: Beauty is Skin Deep

If you are developing a UI framework for JavaFX, then please make it a habit to always split your custom controls into a control class and a skin class. Coming from Swing myself this was not obvious to me right away. Swing also uses an MVC concept and delegates the actual component rendering to a UI delegate, but people extending Swing mostly subclassed one of its controls and added extensions / modifications to the subclass. Only very few frameworks actually worked with the UI delegates (e.g. MacWidgets).

I have the luxury of being able to compare the implementation of the same product / control once done in Swing and once done in JavaFX and I noticed that the JavaFX implementation is so much cleaner, largely because of the splitting in controls and skins (next in row: CSS styling and property binding). In Swing I was exposing a lot of things to the framework user that I personally considered “implementation detail” but that became public API nevertheless. The JavaFX architecture makes it much more obvious where the framework developer draws the line between public and internal API.

The Control

The control class stores the state of the control and provides methods to interact with it. State information can be: the data visualized by the control (e.g. the items in TableView), visual attributes (show this, hide that), factories (e.g. cell factories). Interaction can be: scroll to an item, show a given time, do this, do that. The control class is the contract between your framework code and the application using the framework. It should be well designed, clean, stable, and final.

The Skin

This is the place to go nuts, the Wild West. The skin creates the visual representation of your control by composing already existing controls or by extending the very basic classes, such as Node or Region. Skins are often placed in separate packages with package names that imply that the API contained inside of them is not considered for public use. If somebody does use them then at their own risk because the framework developer (you) might decide to change them from release to release.

 

 

 

JavaFX Tip 7: Use CSS Color Constants / Derive Colors

When working on FlexCalendarFX I got to the point where I had to define a set of colors to visualize the controls for different calendars in different colors. And not just one color per calendar but several: a background and a text color for deselected / selected / hover states.

The  colors were used in several places but for the sake of brevity I only focus on the visual calendar entries in the day view of FlexCalendarFX. The two screenshots below show the same entry, first deselected, then selected.deselected-entry
selected-entry

What is important to notice is that these are not completely different colors but they all have the same base color (green) but with different saturation.

The code below shows the best way I could find to define related colors in JavaFX CSS. I define the base color globally under “.root” and derive all other colors using this constant.

.root {
   -style1-color: rgb(119, 192, 75, .9);
}

.style1-entry {
   -fx-background-color: derive(-style1-color, 50%);
}

.style1-entry:selected {
   -fx-background-color: -style1-color;
}

.style1-entry-time-label, .style1-entry-title-label {
   -fx-text-fill: derive(-style1-color, -50%);
}

Please notice that the base color is using transparency as described in my previous blog about transparent colors. The other background colors in this CSS fragment are all derived from the base color. They are either brighter (positive percentage value in derive function) or darker (negative percentage value).

By using this approach to defining colors you can achieve a consistent and smooth look for your application and it will not look like your child’s coloring book.

JavaFX Tip 6: Use Transparent Colors

Picking the right colors for your user interface elements is always a great challenge, but it is even more challenging when you develop reusable framework controls where you as a developer have no control over the look and feel of the application using them. While you might always add elements on top of the default gray background the developers embedding your controls  might have more of a gothic tendency and use a black background. All of a sudden the nice colors your picked clash with the rest of the application.

To tackle this problem the best way I found while working on FlexGanttFX and FlexCalendarFX was to use semi-transparent colors. When you do the color of your UI elements will always be a mix of their own color and the background color. Your colors will become brighter if the application uses a white background and darker if it is using a black background. The contrast between your element and the background will never be strong, which makes for a smooth appearance.

The following screenshots were taken from FlexCalendarFX (work-in-progress).

opacity1

Same UI now with a darker background. You might not see it at first, but the green and blue are actually different between these two screenshots. These are very subtle differences, but they make a big difference in the overall impression of your application.

opacity2

In JavaFX you can define colors in CSS with an alpha channel value smaller than 1 to achieve transparency:

.my-style {
    -fx-background-color: rgba(255, 255, 255, .7); // transparent white
}

Using opacity also has the nice side-effect that you can still distinguish different elements even when they overlap each other.

JavaFX Tip 5: Be Observable

Even in this time of total NSA surveillance it is still a good idea to implement your JavaFX controls with observability in mind. This is easy to achieve in JavaFX especially compared to Swing.

The Old Days

Coming from Swing I was used to spending a lot of energy and time on making custom controls observable. It usually required adding methods to add and remove listeners of a certain type. This listener type was a new interface, the single method of that interface accepted a new event object. To send this event object the control had to “fire” it inside my custom control, so I ended up writing fireXYZ() methods. A lot of work only to let somebody know that some aspect of the control’s state has changed.

The New Age

In JavaFX observability can be achieved much more easily by using properties and observable collections. In the FlexGanttFX framework almost every attribute of its controls are properties and all collections are created via the FXCollections class, which returns observable collections. This makes a lot of sense because the total of the attributes of each control define its state and this state needs to be observable so that other parts of the application (especially other controls) can react to state changes.

Boilerplate Code

The downside of using properties is that you end up writing a lot of boilerplate code but still much less than in Swing. In the case of a boolean property it will look like this:

public final BooleanProperty showStuff =
     new SimpleBooleanProperty(this, "showStuff", true);

public final BooleanProperty showStuffProperty() {
   return showStuff;
}

public final boolean isShowStuff() {
   return showStuff.get();
}

public final void setShowStuff(boolean show) {
   showStuff.set(show);
}

And yes, you should follow exactly this coding convention. For a property called xxx provide a property accessor method called xxxProperty(), a setter called setXXX() and a getter called getXXX(). This is the way it is used throughout JavaFX and you should stick to it.

When working with collections you typically end up with at least this code:

private final ObservableList<String> names =
     FXCollections.observableArrayList();

public final ObservableList<String> getNames() {
   return names;
}

In the JavaFX core controls collections are often stored in a property so that the whole collection can be replaced by a new collection. So far I haven’t really seen a strong requirement for this in my controls and not doing so means I do’t have to write property listeners for this case.

Listeners

Now that our control attributes are properties we can easily react to state changes by adding listeners to them (using lambda expressions).

myControl.showStuffProperty().
   addListener(it -> showStuffChanged());

myControl.getNames().
   addListener((Observable observable) -> namesChanged());

Conclusion

When designing your own custom control expose its state in the control class via properties and observable collections. By doing so everyone will be able to observe the state of your controls in a way that is consistent with the entire JavaFX framework and that will enable other developers to seamlessly integrate their controls / their application with your controls.

JavaFX Tip 4: Have the Final Word

When developing custom controls for JavaFX I would highly recommend to follow in the footsteps of  the core JavaFX controls and to make the API of your controls as final as possible and to put the “final” keyword in front of all your method declarations.

Example

In FlexGanttFX I have a lot of code that looks like this:

public final Activity getActivityAt(double x, double y) { ... }
public final Row getRowAt(double y) { ... }
public final void setShowLinks(boolean show) { ... }

 

Why?

When you design a control you have a specific behaviour of the control in mind. This behaviour can be protected by using “final”. If you do not use it then other developers will subclass the control, they will override its methods, they will run into problems, and they will submit a defect ticket to your issue management tool. In the end you will waste your time on chasing their bugs. Bugs that only exist because your control was used in a way that you couldn’t possibly foresee.

Where?

Protection is especially needed for the public API of the control class, which is managing the “state” of the control. It is the contract between you and the user of your control. It is less true for the skin of the control, because skins are “implementation detail” and people modifying skins know that they are interfering with the inner workings of the control. You still want to make it easy for other developers to modify the “appearance” of the control.

New Concept?

Protecting your controls this way is not a new concept but it wasn’t used very much in Swing. The case for using “final” is stronger now because JavaFX controls are much more observable than Swing controls. They are exposing their state via properties and observable collections. This way applications can react to state changes by “listening” to the control instead of plugging themself into the control by overriding its methods. Another reason is the clean separation into “control” and “skin” in JavaFX. Swing components often had “skin” aspects right in the component itself and not in the UI delegate (e.g. paintComponent()).

JavaFX Tip 3: Use Callback Interface

As a UI framework developer it is part of my job to provide ways to customize the appearance and behavior of my controls. In many cases this is done by allowing the framework user to register a factory on a control. In the past I would have created a factory interface for this and provided one or more default implementations within the framework.

These things are done differently in JavaFX and I have started to embrace it for my own work. JavaFX uses a generic interface called javafx.util.Callback wherever a piece of code is needed that produces a result (R) for a given parameter (P).

The interface looks like this:

public interface Callback<P,R> {
    public R call(P param);
}

Advantages

At first I didn’t like using this interface because my code was loosing verbosity: I no longer had self-explaining interface names. But in the end I realized that the advantages overweight the lack of verbosity. The advantages being:

  • We end up writing less code. No specialized interface, no default implementations.
  • The developer using the API does not have to remember different factories, instead he can focus on the object that he wants to create and the parameters that are available to him.
  • The Callback interface is a functional interface. We can use Lambda expressions, which makes the code more elegant and we once again have to write less code.

Case Study

The  FlexGanttFX framework contains a control called Dateline for displaying (surprise) dates. Each date is shown in its own cell. The dateline can display different temporal units (ChronoUnit from java.time, and SimpleUnit from FlexGanttFX). A factory approach is used to build the cells based on the temporal unit shown.

Before I was using the callback approach I had the following situation: an interface called DatelineCellFactory with exactly one method createDatelineCell(). I was providing two default implementations called ChronoUnitDatelineCellFactory and SimpleUnitDatelineCellFactory. By using Callback I was able to delete all three interfaces / classes and in the skin of the dateline I find the following two lines instead:

dateline.setCellFactory(SimpleUnit.class,
    unit -> new SimpleUnitDatelineCell());

dateline.setCellFactory(ChronoUnit.class,
    unit -> new ChronoUnitDatelineCell());

Two lines of code instead of three files! I think this example speaks for itself.