Best Practices for JavaFX Mobile Applications 5

Today’s post focuses on optimizations for the core JavaFX runtime.

WARNING: The tips I am giving here are true for the current version of JavaFX Mobile, which is part of the JavaFX 1.1 SDK. In future versions the behavior will change, the
current bad performance of the mentioned artifacts will be optimized away or at least significantly improved. Everything I am writing about here is a snap-shot, nothing should be understood as
final!

Item 7: Define variables with def instead of var. Make them script-private.

When defining instance variables, it is good practice to limit the accessibility as much as possible. Also if a variable is immediately initialized and not reassigned afterwards, one should use the keyword def to define it. This is true for almost all bound variables, because bound variables cannot be reassigned (there is no such thing as an unbound-operation) and usually one already knows what they are bound to when they are defined.

Besides resulting in clearer and less error-prone code, following these suggestions also improves performance. The more hints we can provide to the compiler, the more aggressive it can optimize our code. Let’s take a look at an example in Code Sample 1.

1 class Main {
2     def i1: Integer = 0;
3     var i2: Integer;
4     public def i3: Integer = 0;
5     public var i4: Integer;
6 }

Code Sample 1: A sample script with public, private defs and vars

Code Sample 1 defines a small class with four members i1, i2, i3, and i4. The variables i1 and i2 are script-private, i3 and i4 are public; the variables i1 and i3 are defined with def, i2 and i4 are defined with var. Code Sample 2 shows part of the generated Java code.

1 class Main extends java.lang.Object implements Main$Intf,com.sun.javafx.runtime.FXObject{
2     public int $Main$i1;
3     public int $Main$i2;
4     public int $i3;
5     public final com.sun.javafx.runtime.location.IntVariable $i4;
6     ...
7 }

Code Sample 2: Parts of the generated Java code from Code Sample 1

What is remarkable about the generated Java code is the fact that all variables but i4 became simple ints; only the variable i4 is translated into an IntVariable, because it needs to provide more functionality. An int-variable requires less memory and performs faster than an instance of IntVariable.

Item 8: Use Integer instead of Number

Operations on integers are always faster than operations on floating-point values. On limited device, which usually do not have a mathematical coprocessor like desktop computers, the difference is exorbitant. Therefore it is good practice to use Integers whenever possible.

The type-inference mechanism of the JavaFX compiler usually does a very good job in determining the correct type of a variable, but if in doubt, it will chose Number. Therefore one should always set the type of Integer variables explicitly.

Item 9: Use functions of class Sequences

The class Sequences in the package javafx.util provides a large number of useful functions for dealing with sequences. One should be familiar with the provided functions and use them instead of implementing them by oneself. The functions in Sequences have been tested thoroughly and the performance is at least as good, if not better than that of own implementations.

Links to previous parts:

Item 1: Avoid unnecessary bindings
Item 2: Keep the scenegraph as small as possible
Item 3: Use simple shapes instead of images
Item 4: Use small images instead of complex shapes
Item 5: Use the prescaling functionality
Item 6: Use background loading

Best Practices for JavaFX Mobile Applications 4

The fourth part of my series about best practices for JavaFX Mobile Applications focuses on image loading.

WARNING: The tips I am giving here are true for the current version of JavaFX Mobile, which is part of the JavaFX 1.1 SDK. In future versions the behavior will change, the
current bad performance of the mentioned artifacts will be optimized away or at least significantly improved. Everything I am writing about here is a snap-shot, nothing should be understood as
final!

Item 5: Use the prescaling functionality

If an image needs to be scaled and the scaling factor does not change later, it is recommended to use the prescaling functionality. This can be done by setting width and height of an Image object, which will scale the image while it is loaded.

Using prescaling has two benefits. First of all it results in better performance. If prescaling is used, the scaling is definitely calculated only once. In contrast the scaling of an ImageView object is recalculated each time its transformation is changed by something else then a translation. For example changing the rotation will result in recalculating the scaling. Secondly, if an image is down scaled, memory usage is much smaller if prescaling is used.

Scaling can be calculated even faster if the flag Image.smooth is false. But the quality of the scaled image must be checked.

Example

This example generates thumbnails for a number of images. Code Example 1 creates a sequence of thumbnails, using the scaling functionality of ImageView.

1 def thumbnails = for (i in [0..11])
2     ImageView {
3         image: Image {url: "{__DIR__}images/img{i}.png"}
4         preserveRatio: true
5         fitWidth: 30
6         fitHeight: 20
7     }

Code Sample 1: Scaling within ImageView

The same can be achieved using the prescaling functionality of the Image class as shown in Code Example 2. Displaying the thumbnails is usually faster with this approach and the memory usage is much smaller.

1 def thumbnails = for (i in [0..11])
2     ImageView {
3         image: Image {
4             url: "{__DIR__}images/img{i}.png"
5             preserveRatio: true
6             width: 30
7             height: 20
8         }
9     }

Code Sample 2: Prescaling with Image

Item 6: Use background loading

The class Image provides a nice, but easily overlooked feature, to load images asynchronously in the background. This will not speed up the runtime performance or reduce the footprint of an application, but it can significantly improve startup time. To enable it, the flag Image.backgroundLoading must be set.

Background loading has two consequences, which need to be considered during implementation. If an image which is loaded in the background is supposed to be displayed shortly after creation, it is necessary to check the progress of the download. Otherwise an empty image will be shown first. Another option is to set the variable placeholder to display a substitute-image until the real image is finished loading. This approach is used in the example below.

The second consequence is, that width and height of an image are not set until the image is completely loaded. This will probably spoil any layout, which depends on the size of the used images. Again, a placeholder image can be used to overcome this, if placeholder-image and final image have the same size. Or width and height can be set manually, which would prescale the image to the given size. The last option is to recalculate the layout once the image is finished loading.

Example

Code Sample 3 extends the example from above to load the thumbnails in the background and displays them. While the images are loaded a placeholder (logo.png) is displayed, which has the same size as the thumbnails. Note that the logo is not loaded in the background to make sure we can display it immediately.

 1 def logo = Image {url: "{__DIR__}images/logo.png"}
 2
 3 def thumbnails = for (i in [0..11])
 4     ImageView {
 5         image: Image {
 6             url: "{__DIR__}images/img{i}.png"
 7             preserveRatio: true
 8             width: 30
 9             height: 20
10             backgroundLoading: true
11             placeholder: logo
12         }
13         x: i mod 4 * 50 + 20
14         y: ((i/4) as Integer) * 40 + 20
15 }
16
17 Stage {scene: Scene {content: thumbnails}}

Code Sample 3: Loading thumbnails in the background

On the emulator one has to look really close to notice the background loading. On a real device loading the images usually takes longer. With background loading enabled, the screen is displayed quickly, first showing only the placeholders, which are one after the other replaced with the real images. If background loading is disabled, the application would show a blank screen until all images are completely loaded and displayed.

Links to previous parts:

Item 1: Avoid unnecessary bindings
Item 2: Keep the scenegraph as small as possible
Item 3: Use simple shapes instead of images
Item 4: Use small images instead of complex shapes

Best Practices for JavaFX Mobile Applications 3

WARNING: The tips I am giving here are true for the current version of JavaFX Mobile, which is part of the JavaFX 1.1 SDK. In future versions the behavior will change, the
current bad performance of the mentioned artifacts will be optimized away or at least significantly improved. Everything I am writing about here is a snap-shot, nothing should be understood as
final!

Item 3: Use simple shapes instead of images

Item 4: Use small images instead of complex shapes

These two items seem to contradict each other. Unfortunately there is no easy answer available here:  sometimes using shapes is better, sometimes using an image is better. To help making the right decision, here are some points one should consider:

  • Complexity Single basic shapes like rectangles or circles are almost always faster than images. But the higher the number of shapes, which are assembled to get the desired artifact, or the more complex a user-defined path is, the more expensive operations on these shapes are. And the advantage shrinks. Important note: A javafx.text.Text object is a very complex shape.
  • Size The performance of most operations on images behaves quadratic, which means the operations become 4 times as slow if width and height are doubled, 9 times as slow if they are tripled etc. Therefore the bigger an element is, the better is using shapes.
  • Transformations Rotating or scaling does not only look better when using shapes, but it is usually also faster than transforming images. Especially if rotation and scaling are animated, shapes will perform better.
  • Startup time Loading an image and setting up an ImageView is usually slower then setting up shapes.
  • Footprint Static and dynamic footprint is almost always higher when using images.

Important: The variable cache of javafx.scene.Node is currently NOT used in the runtime. Setting it makes no difference!

Links to previous parts:

Item 1: Avoid unnecessary bindings
Item 2: Keep the scenegraph as small as possible

Best Practices for JavaFX Mobile Applications 2

Today I am writing about the second tip to increase performance of JavaFX Mobile applications. I think this and the previous tip are the most important ones.

WARNING: The tips I am giving here are true for the current version of JavaFX Mobile, which is part of the JavaFX 1.1 SDK. In future versions the behavior will change, the
current bad performance of the mentioned artifacts will be optimized away or at least significantly improved. Everything I am writing about here is a snap-shot, nothing should be understood as
final!

Item 2: Keep the scenegraph as small as possible

Behind the scenes of the runtime a lot of communication takes place to update the variables of the nodes in a scenegraph. The more elements a scenegraph has, the more communication is required. Therefore it is critical to keep the scenegraph as small as possible. Especially animations tend to suffer from a large scenegraph.

It is bad practice to keep a node in the scenegraph at all times and control its visibility via the visible-flag or its opacity. Invisible nodes in the scenegraph are still part of the communication-circus in the background. Instead one should remove nodes from the scenegraph and add them only when required.

This approach has one drawback though. Adding or removing nodes takes longer than setting the visibility. Therefore it might not be appropriate in situations were immediate responses are critical.

Example 1

Often one has a set of nodes of which only one is visible. These can be for example different pages, or nodes to visualize different states of an element. One might be tempted to add all nodes to the scenegraph and set only the current as visible.

Code Sample 1 shows a simplified version of this approach. Three colored circles are created to visualize some kind of state (red, yellow, green). Only one node is visible at any time. (Let’s ignore for a second that this could simply be achieved by changing the fill-color of a single circle. In real life applications one would probably have images or more complex shapes for visualizations and simply changing the color would not work.)

 1 def colors = [Color.GREEN, Color.YELLOW, Color.RED];
 2
 3 var state: Integer;
 4
 5 Stage {
 6     scene: Scene {
 7         content: for (i in [0..2])
 8             Circle {
 9                 centerX: 10
10                 centerY: 10
11                 radius: 10
12                 fill: colors[i]
13                 visible: bind state == i
14             }
15     }
16 }

Code Sample 1: Using visibility to switch between nodes

This results in three nodes in the scenegraph although only one is shown. This should be refactored to ensure that only the visible node is in the scenegraph. Code Sample 2 shows one possible implementation.

 1 def colors = [Color.GREEN, Color.YELLOW, Color.RED];
 2
 3 var state: Integer on replace oldValue {
 4     insert nodes[state] into stage.scene.content;
 5     delete nodes[oldValue] from stage.scene.content;
 6 }
 7
 8
 9 def nodes = for (i in [0..2])
10     Circle {
11         centerX: 10
12         centerY: 10
13         radius: 10
14         fill: colors[i]
15     }
16
17 def stage = Stage {scene: Scene{}}

Code Sample 2: Adding and removing nodes when required

The code in Code Sample 1 is more compact, but Code Sample 2 reduced the number of nodes in the scenegraph from three to one. While tuning some of the demos for the JavaFX Mobile release, we were able to reduce the number of nodes in the scenegraph by 50% and more, simply by ensuring that only visible nodes are part of it.

Example 2

If nodes are shown and hidden with some kind of animation, adding and removing the node to the scenegraph becomes extremely simple. One only needs to implement an action at the beginning of the fadeIn-animation and at the end of the fadeOut-animation to add respectively remove the node. Code Sample 3 shows such a usage where a simple message-box is shown and hidden by changing the opacity.

 1 def msgBox = Group {
 2     opacity: 0.0
 3     content: [
 4         Rectangle {width: 150, height: 40, fill: Color.GREY},
 5         Text {x: 20, y: 20, content: "Hello World!"}
 6     ]
 7 }
 8
 9 def fadeIn = Timeline {
10     keyFrames: [
11         KeyFrame {
12             action: function() {insert msgBox into stage.scene.content}
13         },
14         at (1s) {msgBox.opacity => 1.0 tween Interpolator.LINEAR}
15     ]
16 }
17
18 def fadeOut = Timeline {
19     keyFrames: KeyFrame {
20         time: 1s
21         values: msgBox.opacity => 0.0 tween Interpolator.LINEAR
22         action: function() {delete msgBox from stage.scene.content}
23     }
24 }
25
26 def stage = Stage {scene: Scene{}}

Code Sample 3: Using fadeIn- and fadeOut-animations to add and remove nodes.

Best Practices for JavaFX Mobile Applications

As everybody who is interested in JavaFX will know by now, JavaFX Mobile was released a short while
ago. It was a hell of a ride, that’s for sure. I felt so exhausted, I did not even have the energy to blog during the release…

But by now I feel recovered and want to start a little series about lessons we have learned while preparing the release and give some hints how to improve the performance of JavaFX Mobile applications.

WARNING: The tips I am giving here are true for the current version of JavaFX Mobile, which is part of the JavaFX 1.1 SDK. In future versions the behavior will change, the
current bad performance of the mentioned artifacts will be optimized away or at least significantly improved. Everything I am writing about here is a snap-shot, nothing should be understood as
final!

Item 1: Avoid unnecessary bindings

Bindings are very convenient, without any doubt one of the most valuable innovations in JavaFX Script. Unfortunately they come with a price. The generated boiler-plate code is usually not as small and
fast as a manual implementation would be. Especially complex dependency-structures tend to impose a severe penalty on performance and footprint.

For this reason it is recommended to avoid bindings as much as possible. Often the same functionality can be implemented with triggers. One should not use bindings to avoid the hassle of dealing with the initialization order. And it certainly makes no sense to bind to a constant value.

Lazy bindings are most of the time (but not always!) faster if a bound variable is updated more often then read, but they are still not as fast as manual implementations.

Example

A common use-case is a number of nodes which positions and sizes depend on the stage-size. A typical implementation uses bindings to achieve that.

Here we will look at a simple example, which resembles such a situation. The scene consists of three rectangles which are laid out diagonally from the top-left to the bottom-right. The size of the rectangle is a quarter of the screen-size. Code Sample 1 shows an implementation with bindings.

 1 def rectangleWidth: Number = bind stage.width * 0.25;
 2 def rectangleHeight: Number = bind stage.height * 0.25;
 3
 4 def stage: Stage = Stage {
 5     scene: Scene {
 6         content: for (i in [0..2])
 7             Rectangle {
 8                 x: bind stage.width * (0.125 + 0.25*i)
 9                 y: bind stage.height * (0.125 + 0.25*i)
10                 width: bind rectangleWidth
11                 height: bind rectangleHeight
12             }
13     }
14 }

Code Sample 1: Layout calculated with bindings

The first question one should think about is wether the bindings are really necessary. On a real device the screen-size changes only when the screen orientation is switched (provided that the device supports this functionality). If our application does not support screen rotation, the layout can be defined constant.

One possible solution to reduce the number of bindings is shown in Code Sample 2. Two variables width and height are introduced and bound to stage.width and stage.height respectively. Their only purpose is to provide triggers for stage.width and stage.height, since we do not want to override the original triggers. Position and size of the rectangles are calculated manually in the triggers.

 1 def r = for (i in [0..2]) Rectangle {}
 2
 3 def stage = Stage {
 4     scene: Scene {content: r}
 5 }
 6
 7 def height = bind stage.height on replace {
 8     def rectangleHeight = height * 0.25;
 9     for (i in [0..2]) {
10         r[i].height = rectangleHeight;
11         r[i].y = height * (0.125 + 0.25*i)
12     }
13 }
14
15 def width = bind stage.width on replace {
16     def rectangleWidth = width * 0.25;
17     for (i in [0..2]) {
18         r[i].width = rectangleWidth;
19         r[i].x = width * (0.125 + 0.25*i)
20     }
21 }

Code Sample 2: Layout calculated in trigger

Without any doubt, the code in Code Sample 1 is more elegant. But measuring the performance of both snippets in the emulator, it turned out the code in Code Sample 2 is almost twice as fast.

Binding Java Objects in JavaFX Script

Bindings are one of the key features of the JavaFX language, because they simplify one´s life tremendously. By reducing the amount of boilerplate code, which is usually needed to keep the objects in an application in-sync, the developer can concentrate on the really important things. (You know, like a cool looking UI.) 😉

Unfortunately Java objects do not provide this capabilities for their fields. That means the boilerplate code has to be written manually. This article will show a solution to bind properties of Java objects.

Overview

Let´s assume, we have a Java class Rectangle with the four properties x, y, width, and height. We want to show the rectangle on the screen using JavaFX script and update its position and size as the properties of the Java object change.

The code of the class Rectangle would be something like this:

 1 public class MyRectangle {
 2     private int x, y;
 3     private int width, height;
 4
 5     public int getX() { return x; }
 6     public void setX(int x) { this.x = x; }
 7     public int getY() { return y; }
 8     public void setY(int y) { this.y = y; }
 9     public int getWidth() { return width; }
10     public void setWidth(int width) { this.width = width; }
11     public int getHeight() { return height; }
12     public void setHeight(int height) { this.height = height; }
13
14     // ... more functionality here
15 }

Code Sample 1: First draft of MyRectangle

What we want the JavaFX script to look like, is this:

 1 import javafx.stage.Stage;
 2 import javafx.scene.Scene;
 3 import javafx.scene.shape.Rectangle;
 4
 5 Stage {
 6     scene: Scene {
 7     // ... more attributes here
 8         content: Rectangle {
 9             x: bind r.x
10             y: bind r.y
11             width: bind r.width
12             height: bind r.height
13         }
14     }
15 }

Code Sample 2: JavaFX program binding the rectangle

This looks simple enough and the only question remaining is: what is “r”? To allow the script to bind to the fields of the Java object, we need to introduce an adapter between the two, which provides a more JavaFX-like interface of the Java class and which will take care of the synchronization. A simplified class-diagram of the three objects is shown in Figure 1:

Class Diagram

Class Diagram

The basis interface of the adapter can be defined as follows:

 1 public class RectangleAdapter {
 2     public-read var x: Integer;
 3     public-read var y: Integer;
 4     public-read var width: Integer;
 5     public-read var height: Integer;
 6
 7     public-init var javaRectangle: MyRectangle;
 8 }

Code Sample 3: First draft of the adapter RectangleAdapter

Only thing left to do is to add the following line to the script in Listing 3. This will create a new instance of RectangleAdapter and its adaptee Rectangle.

var r = RectangleAdapter { javaRectangle: new MyRectangle }
Looks like we are about halfway through. We defined an adapter and connected it to the JavaFX class. Now let's take a look at the second part: connecting the adapter with the Java object.

Synchronizing with the Java object

Synchronizing the adapter whenever the state of the Java object changes requires some more work. In general there are two possibilities to implement this functionality. The first solution is to make the adapter an observer (or "listener" to speak more Java-like) of the Java object. This is usually the preferred approach, unfortunately it is not always possible. For example, if you are dealing with existing classes, which you cannot change, this approach would be problematic. The second solution, which does not require any changes to the Java class, is to request the current state repeatedly.
Synchronizing using the observer-pattern
There are numerous ways to implement the observer-pattern. Since this article is not so much about implementing Java programs, I will use the simplest approach by extending Observable. This is a utility-class, which provides all of the functionality required by the observer-pattern. All we need to do is add the code to initiate the notification of our observers. The class Observable requires two method-calls for that: setChanged() to signal the object has changed and notifyObservers() to start the notification-process. In our code example, I added a small private method startNotification() to bundle both calls and updated the setters. Code sample 4 shows the new version of the class Rectangle.
 1 import java.util.Observable;
 2
 3 public class MyRectangle extends Observable {
 4     private int x, y;
 5     private int width, height;
 6
 7     public int getX() { return x; }
 8     public void setX(int x) {
 9         this.x = x;
10         startNotification();
11     }
12
13     public int getY() { return y; }
14     public void setY(int y) {
15         this.y = y;
16         startNotification();
17     }
18
19     public int getWidth() { return width; }
20     public void setWidth(int width) {
21         this.width = width;
22         startNotification();
23     }
24
25     public int getHeight() { return height; }
26     public void setHeight(int height) {
27         this.height = height;
28         startNotification();
29     }
30     private void startNotification() {
31         setChanged();
32         notifyObservers();
33     }
34
35     // ... more functionality here
36 }

Code Sample 4: MyRectangle implementing Observable

To finish this solution, we need our adapter to extend the interface Observer. That requires to implement its method update(), and to register the adapter. The registration is done by calling addObserver() in the onReplace-trigger of the attribute javaRectangle.

The method update() comes with two parameters, which are helpful, if we want to observe more than one object or if we are dealing with different events. But in our code example, we can ignore them. Only thing left to do is pull the new values from javaRectangle and update the attributes of the adapter.

But wait! You have to be careful here. While our Java code can run on any thread, JavaFX Script is picky here. We need to make sure, that the update is done on the right thread, otherwise the bindings and subsequent actions might fail.

JavaFX Script provides a mechanism for this. The method FX.deferAction() takes a simple function as a parameter and makes sure, that it is executed on the right thread. The complete adapter is shown in code sample 5.

 1 import java.lang.Object;
 2 import java.util.Observable;
 3 import java.util.Observer;
 4
 5 public class RectangleAdapter extends Observer {
 6     public-read var x: Integer;
 7     public-read var y: Integer;
 8     public-read var width: Integer;
 9     public-read var height: Integer;
10
11     public-init var javaRectangle: MyRectangle
12         on replace { javaRectangle.addObserver(this); }
13
14     override function update(observable: Observable, arg: Object) {
15         FX.deferAction(
16             function(): Void {
17                 x = javaRectangle.getX();
18                 y = javaRectangle.getY();
19                 height = javaRectangle.getHeight();
20                 width = javaRectangle.getWidth();
21             }
22         );
23     }
24 }

Code Sample 5: RectangleAdapter implementing Observer

Synchronizing by pulling the state

The second solution does not require any change to the Java class. Let's assume, we do not want to bind to an object of our own Rectangle, but to an instance of java.awt.Rectangle. This class does not provide any mechanisms to observe state-changes. Instead we have to pull the current state on a regular base to notice changes.

The JavaFX class PauseTransition provides exactly the needed functionality. It comes with two main attributes to setup the behavior. The parameter action defines the task, which needs to be executed, and the parameter duration defines the gap between two consecutive calls.

Defining the right value for the duration is probably the toughest part. The best choice depends on the context. If the value is too low, precious CPU cycles are wasted, if the value is too high, the update might come too late. In our example, the duration is set to 10 ms, which ensures smooth animations.

The adapter for the second solution is shown in code sample 6. Note, that we do not have deal with threading in this solution, because the action of the ActionTransition is already executed on the right thread.

 1 import java.awt.Rectangle;
 2 import javafx.animation.Timeline;
 3 import javafx.animation.transition.PauseTransition;
 4
 5 public class RectangleAdapter {
 6     public-read var x: Integer;
 7     public-read var y: Integer;
 8     public-read var width: Integer;
 9     public-read var height: Integer;
10
11     var action: PauseTransition;
12     public-init var javaRectangle: Rectangle
13         on replace {
14             action = PauseTransition {
15                 duration: 10ms
16                 action: function(): Void {
17                     x = javaRectangle.x;
18                     y = javaRectangle.y;
19                     height = javaRectangle.height;
20                     width = javaRectangle.width;
21                 }
22                 repeatCount: Timeline.INDEFINITE;
23             }
24             action.play();
25         }
26
27     public function stop() {
28         action.stop();
29     }
30 }

Code Sample 6: RectangleAdapter pulling the status

Summary

This article presented two solutions to implement a simple binding of a Java object. The first solution is always preferable, because it uses CPU cycles only when an update took place, while the second solution burns cycles even when nothing happens. The second solution is a fall back in cases, where the observer pattern cannot be implemented.

Creating JavaFX sequences in Java programs

The last article explained, how sequences are represented in the runtime and touched some of the possibilities to create new JavaFX sequences in Java programs. This article and the follow-up will focus on sequence-creation and give an overview of additional possibilities.

The helper-class Sequences

The helper class Sequences in the package com.sun.javafx.runtime.sequence provides a number of methods to create sequences. Most of them have also been presented in the last article.

The methods can be divided in two groups. The first group are distinct factory methods. They create a new sequence from some kind of elements-list:

  • make() – Creates a sequence from a java.util.List, a part of an array or from explicitly listed elements.
  • fromArray() – Creates a sequence from the elements of an array.
  • fromCollection – Creates a new sequence with the elements of a given Collection. Since the elements of a Collection are unordered there is no guarantee about the order in the sequence.
  • range / rangeExclusive() – Creates sequences, which represent Integer- or Number-intervals.
  • singleton – Creates a sequence with a single element.
  • emptySequence() – Creates an empty sequence.

The second group alters an existing sequence. As sequences are implemented immutable, a new sequence is created and returned.

  • concatenate() – Creates a new sequence by concatenating sequences.
  • filter() – Creates a new sequence by masking out some of the elements of a sequence.
  • reverse – Creates a new sequence by reversing the order of a sequence.
  • subsequence – Creates a sequence, which is a fragment of a sequence.
  • upcast – Creates a new sequence by upcasting the elements of a sequence.
  • map – Creates a sequence which one would get after applying a mapping-function to the elements of a sequence. The mapping-function must be defined by implementing the interface SequenceMapper, which is also part of the package com.sun.javafx.runtime.sequence.
  • sort – Creates a new sequence by sorting the elements of a given sequence. The order can be induced either by the natural order of the elements, if they implement java.util.Comparable, or by providing a java.util.Comparator of the elements.

The class SequenceBuilder

The SequenceBuilder in the package com.sun.javafx.runtime.sequence provides a convenient way to create sequences incrementally. It is similar to the class StringBuilder, which creates Strings.

An instance of SequenceBuilder can only create one sequence at a time. It starts with an empty sequence to which elements are appended by calling one of its add()-methods. The result can be extracted by calling the method toSequence().

Refactoring a function to become a bound function

Bound functions are one of the most powerful features, that JavaFX Script introduces, but probably also one of the hardest concepts to understand. There are two main use-cases for bound functions:

  1. The result of the function depends on some external attributes.
  2. The functions returns an object, which is created in the function. If one of the dependencies changes, the function should not create a new object, but alter the one which was created in the first call.

While I have not encountered the second case so far (but maybe that’s because the concept of bound functions has not fully been absorbed by developers like me). The first case is very common. Consider for example the class in Code Sample 1. (Warning: this is a real world example taken from the current UI-runtime.) 🙂

 1 public class CanvasElement {
 2     public attribute parentCanvasElement: CanvasElement;
 3     
 4     public function getContainer(): Container {
 5         while (p <> null) {
 6             if (p instanceof Container) {
 7                 return p as Container;
 8             }
 9             p = p.parentCanvasElement;
10         }
11         return null;
12     }
13 }

Code Sample 1: The original function getContainer()

The class CanvasElement is a node in a tree. The function getContainer() returns the closest parent, which is a Container. The result of the function depends on the attribute parentCanvasElement. Evidently, if the node is moved to another place in the tree, the function will return another result. Now, wouldn’t it be nice to make this function a bound function? This would allow us to notify any object that needs to be notified about the new parentContainer without writing a single line of code.

Unfortunately the permitted statements in a bound function are quite strict. Only the definitions of local variables are allowed plus a final expression to return the result of the function. In other words only method-bodies of the following form are allowed:

1 bound function foo() {  
2     var i = ...; 
3     var j = ...; 
4     [...] 
5     return result; 
6 }

Code Sample 2: The required format of bound functions (informal)

This looks pretty strict at first sight. Consider the function in Code Sample 1. Rewriting the function to match this pattern directly will be hard, if not impossible. But here is a little recipe with which every function can be turned into a legal bound function.

  1. Take the function-body and create a private function with all dependencies as parameters. (I usually make this function static, so that the compiler warns me, if I forgot a non-static-dependency.)
  2. Make the original function a bound function and call the function just created, passing all dependencies to it.

By applying this recipe, the bound function follows the allowed syntax. And whenever a dependency changes the result gets reevaluated. Voilá!

Code Sample 3 shows the refactored function getContainer() from the example.

 1 public class CanvasElement {
 2     public attribute parentCanvasElement: CanvasElement;
 3     
 4     public bound function getContainer(): Container {
 5         return getParentContainer(parentCanvasElement);
 6     }
 7 
 8     private static function getParentContainer(p: CanvasElement): Container {
 9         while (p <> null) {
10             if (p instanceof Container) {
11                 return p as Container;
12             }
13             p = p.parentCanvasElement;
14         }
15         return null;
16     }
17 }

Code Sample 3: The refactored and bound function getComponent()

Creating JavaFX objects in Java programs

So far, all of the examples in my previous article about how to use JavaFX objects in Java code expected the object as an input parameter. But what if you want to create a JavaFX object directly? In this article, I will describe a very simple but effective solution.

(Edit: As Mike Azzi pointed out to me (thanks again!), I should have mention, that it is also possible to create JavaFX objects by using the compiled Java classes directly. I plan to cover this later, in a series of articles about what happens during compilation.)

Let’s assume we want to create an instance of MyJavaFXClass as it was defined in the previous article. Code sample 1 shows the implementation of the class.

 1 import java.lang.System;
 2 
 3 public class MyJavaFXClass {
 4 
 5     public attribute property: String;
 6 
 7     public function printProperty() {
 8         System.out.println (property);
 9     }
10 }

Code Sample 1: Definition of MyJavaFXClass

To create an instance of this class in JavaFX Script, we would usually define an object literal. We can do that as well in Java and pass the object literal to the JavaFX-script engine we already encountered in the previous article. The script engine can parse the object literal and return a new instance of the class.

Code sample 2 shows a Java class, which creates an instance of MyJavaFXClass and uses the script engine to call its function printProperty.

 1 import javax.script.ScriptEngineManager;
 2 import com.sun.javafx.api.JavaFXScriptEngine;
 3 
 4 public class Main {
 5 
 6     public static void main (String[] args) {
 7         ScriptEngineManager manager = new ScriptEngineManager();
 8         JavaFXScriptEngine fxEngine = 
 9                 (JavaFXScriptEngine) manager.getEngineByName ("javafx");
10 
11         try {
12             Object o = fxEngine.eval
13                     ("MyJavaFXClass { property: \"JavaFX class created in Java\" }");
14             fxEngine.invokeMethod (o, "printProperty");
15         } catch (Exception ex) {
16             ex.printStackTrace();
17         }       
18     }
19 }

Code Sample 2: Constructing MyJavaFXClass in Java program

Using JavaFX sequences in a Java program

The last two articles were about how to pass and deal with primitive datatypes, Java objects, and JavaFX objects. This article focuses on JavaFX sequences.

There are quite a number of Java classes implemented to represent JavaFX sequences. Which implementation is used depends on the input parameters during creation. All of the implementations share the interface Sequence, which we must therefore use when dealing with sequences in Java code.

Using a specific sequence

The interface Sequence is generic. When using it as a parameter in a method, we can define the exact type in the method signature or we leave the type open by defining a generic method. The first code sample shows a method which expects a sequence of Integer-objects. Note that the type is not exactly defined, but used as an upper bound. This needs to be done always.

 1 import com.sun.javafx.runtime.sequence.Sequence;
 2 import java.util.Iterator;
 3 
 4 public class MyIntegerLibrary {
 5 
 6     public static void printIntegerSum (Sequence<? extends Integer> seq) {
 7         int sum = 0;
 8         for (Iterator<? extends Integer> it = seq.iterator(); it.hasNext();) {
 9             sum += it.next();
10         }
11         System.out.println(sum);
12     }
13 }

Code Sample 1: Calculating sum of an Integer sequence

The method printIntegerSum in Code Sample 1 iterates through the sequence of Integers and calculates the sum. The JavaFX statement in Code Sample 2 creates a sequence of 5 integers and calls the method printIntegerSum.

 1 MyIntegerLibrary.printIntegerSum( [2, 3, 5, 7, 11] );

Code Sample 2: Calling printIntegerSum

Note that the type of this example is pretty strict. It is for example not possible to pass a sequence of Byte-objects. If you want to allow a more general sequence, you have to use a more general type. The sequence cannot be cast automatically. In the example above, the class Number can be used to allow any kind numbers in the given sequence.

Using a generic sequence

Using the interface Sequence in generic methods works as one would expect (with one exception, which will be covered later). Code Sample 3 defines a method which takes an arbitrary sequence and prints its elements using the method toString().

 1 import com.sun.javafx.runtime.sequence.Sequence;
 2 import java.util.Iterator;
 3 
 4 public class MySequencePrinter {
 5 
 6     public static <T> void printSequence(Sequence<T> seq) {
 7         for (Iterator<T> it = seq.iterator(); it.hasNext();) {
 8             System.out.println(it.next().toString());
 9         }
10     } 
11 }

Code Sample 3: Printing the elements of an arbitrary sequence

The following statement calls the method with an Integer-Sequence.

 1 MySequencePrinter.printSequence( [2, 3, 5, 7, 11] );

Code Sample 4: Calling the Sequence-Printer

When defining a method which expects a sequence and a single element of the same type, you have to define the type of the sequence bounded as in the first example. Code Sample 5 defines a generic method, which takes an arbitrary sequence and an element. As you can see, the type of the sequence-elements extend the type of the single element.

 1 import com.sun.javafx.runtime.sequence.Sequence;
 2 import java.util.Iterator;
 3 
 4 public class MyElementCounter {
 5     
 6     public static <T> void countElement(Sequence<? extends T> seq, T key) {
 7         int sum = 0;
 8         for (Iterator<? extends T>it = seq.iterator(); it.hasNext();) {
 9             if (key.equals(it.next()))
10                 ++sum;
11         }
12         System.out.println(sum);
13     }
14 }

Code Sample 5: Counting element in a sequence

The method countElement in Code Sample 5 counts how often the element appears in the sequence. The following statement calls the method.

 1 MyElementCounter.countElement( [2, 3, 2, 2, 5, 7, 11, 2], 2 );

Code Sample 6: Calling counting element

If you want to know more about generic types and generric methods, this chapter of the Java Tutorial is a good start.

This article finishes the small series about how to deal with parameters passed from JavaFX to Java after primitive datatypes and Java objects were covered in the first article and JavaFX objects in the second article. The next article will be a short intermezzo on how to create JavaFX objects in Java code. After that will follow another small series which focuses some more on sequences.