Registering Multiple Actions (or Handlers) in JavaFX
By Jim Connors 24 February 2009

Java developers, especially those performing any type of GUI work, will ultimately encounter Java's event-driven programming paradigm.  In short, if programmers want to act upon some kind of event they bundle up a chunk of code into a Java method, typically referred to as a handler, and register the handler with that event.  Whenever that event occurs, the handler code will automatically be executed.

JavaFX provides a similar mechanism.  For a straightforward example, the code below defines a simple timer in JavaFX with a resolution of 1 second.  Each time a second expires, the function specified by the action instance variable will be executed.  Here's what it looks like:

import javafx.animation.*;

public class SimpleTimer {
    public def timeline = Timeline {
        repeatCount: 5
        interpolate: false
        keyFrames: [
            KeyFrame {
                time: 1s
                action: function () : Void {
                    println("tick");
                }
            }
        ]
    }
}

Adding a run() function, as follows, to the bottom of this source will enable you run an instance of this timer:

function run() : Void {
    var s = SimpleTimer{};
    s.timeline.playFromStart();
} 

The output from this run looks like this:

tick
tick
tick
tick
tick 

It's all well and good if you only need a single action.  What if you wanted to perform multiple actions and/or dynamically add or subtract a number of actions?  We can enhance our previous SimpleTimer class to dynamically register and unregister handlers by taking advantage of two of JavaFX's features: sequences and function pointers.

Our new class provides more flexibility:

Here's the new class:
import javafx.animation.*;

public class Timer {
    /**
     * User-definable:  specifies the length of time for one cycle.
     */
    public var duration = 100ms;

    public def timeline = Timeline {
        repeatCount: Timeline.INDEFINITE
        interpolate: false
        keyFrames: [
            KeyFrame {
                time: duration
                action: runHandlers
            }
        ]
    }

    // Holds the list of handlers to run
    protected var handlers: function() [];

    /**
     * Add the function, represented by the handler argument, to the list
     * of handlers.  These will run when the elapsed time, specified
     * by the duration instance variable, expires.
     */
    public function registerHandler(handler : function()) : Void {
        for (func in handlers) {
            if (handler == func) {
                return;  // handler already registered -- skip
            }
        }
        insert handler into handlers;
    }

    /**
     * Remove the function, represented by the handler argument, from
     * the list of handlers.
     */
    public function unRegisterHandler(handler : function()) : Void {
        delete handler from handlers;
    }

    protected function runHandlers() : Void {
        for (handler in handlers) {
            handler();
        }
    }
} 

To test this class out, we'll add a run() function at the script level.  The run() function creates a Timer instance and registers two handler functions, decrementTenthsRemaining() and processTicks().  Here's the code:

function run() : Void {
    var t = Timer {};
    var tenthsRemaining = 100;
    var decrementTenthsRemaining = function() : Void {
        tenthsRemaining -= 1;
    }
    var processTick = function() : Void {
        if (tenthsRemaining mod 10 == 0) {
            println("seconds left: {tenthsRemaining / 10}");
        }
        if (tenthsRemaining == 0) {
            t.timeline.stop();
        }
    };
    t.registerHandler(decrementTenthsRemaining);
    t.registerHandler(processTick);
    t.timeline.play();
}

And this is the output from the run:

seconds left: 9
seconds left: 8
seconds left: 7
seconds left: 6
seconds left: 5
seconds left: 4
seconds left: 3
seconds left: 2
seconds left: 1
seconds left: 0

Shameless Promotion:  Keep up to date with the latest status of our upcoming JavaFX Book entitled JavaFX: Developing Rich Internet Applications at jfxbook.com.

Index