JavaFX using Kawa - introduction

Thu, 28 Jul 2011 11:06:26 -0700
JavaFX, Scheme, kawa

JavaFX 1.0 was a next-generation GUI/client platform. It had a new Node-based GUI API and used a new language, JavaFX Script, whose goal was to make it easier to program Rich Client applications. (Yours truly was hired by Sun to work on the JavaFX Script compiler.) In 2010 the JavaFX Script language was cancelled: JavaFX would still refer to a new GUI based API based on many of the same concepts, but the primary programming language would be Java, rather than JavaFX Script.

Java is a relatively low-level and clumsy language for writing Rich Client appliations, though it's not too painful. Still, there was a reason we worked on JavaFX Script: It had a number of features to make such programs more convenient. Luckily, other JVM languages - and specifically Kawa-Scheme - can take up the slack. Below I'll show you a simple Hello-World-type example, and then explain how you can try it yourself. In later acticles I'll show different examples.

Simple buttons and events

Our first example is just 3 buttons and 2 trivial event handlers. It is translated from HelloButton.java written in Java by Richard Bair.

(require 'javafx-defs)
(javafx-application)

(javafx-scene
 title: "Hello Button"
 width: 600 height: 450
 (Button
  text: "Click Me"
  layout-x: 25
  layout-y: 40
  on-action: (lambda (e) (format #t "Event: ~s~%" e))
  on-key-released: (lambda (e) (format #t "Event: ~s~%" e)))
 (Button
  text: "Click Me Too"
  layout-x: 25
  layout-y: 70)
 (Button
  text: "Click Me Three"
  layout-x: 25
  layout-y: 100))

For those new to Scheme, the basic syntactic building block has the form:

(operator argument1 ... argumentN)

The operator can be a function (like format), an arithmetic operator in prefix form (like (+ 3 4)), a command, a keyword (like lambda), or a user-defined macro. This general format makes for a lot of flexibility.
The first two lines in HelloButton.scm are boiler-plate: The require imports various definitions and aliases, while the (javafx-application) syntax declares this module is a JavaFX Application.

The javafx-scene form (a macro) creates a scene, which is a collection of graphical objects. The Scene has certain named properties (title, width, and height), specified using keyword arguments. The Scene also has 3 Button children. Finally, the make-scene command puts the scene on the stage (the window) and makes it visible.
Each Button form is an object constructor. For example:

(Button
 text: "Click Me Three"
 layout-x: 25
 layout-y: 100)

is equivalent to the Java code:

javafx.scene.control.Button tmp = new javafx.scene.control.Button();
tmp.setText("Click Me Three");
tmp.setLayoutX(25);
tmp.setLayoutY(100);
return tmp;

The on-action and on-key-released properties on the first Button bind event handlers. Each handler is a lambda expression or anonymous function that takes an event e as a parameter. The Kawa compiler converts the handler to a suitable event handler object using SAM-conversion features. (This conversion depends on the context, so if you don't have a literal lambda expression you have to do the conversion by hand using an object operator.)
Getting it to run

Downloading JavaFX 2.x beta

For now JavaFX is only available for Windows, but Mac and GNU/Linux ports are being worked on and mostly work. (I primarily use Fedora Linux.) The primary JavaFX site has lots of information, including a link to the download site. You will need to register, as long the software is beta. Download the zipfile and extract it to some suitable location.
In the following, we assume the variable JAVAFX_HOME is set to the build you've installed. For example (if using plain Windows):

set JAVAFX_HOME=c:\javafx-sdk2.0-beta

The file %JAVAFX_HOME%\rt\lib\jfxrt.jar should exist.
Downloading and building Kawa

The JavaFX support in Kawa is new and experimental (and unstable), so for now you will have to get the Kawa source code from SVN.
There are two ways to build Kawa. The easiest is to use Ant - on plain Windows do:

ant -Djavafx.home=%JAVAFX_HOME%

or on other platforms (including Cygwin):

ant -Djavafx.home=$JAVAFX_HOME

Alternatively, you can use configure and make (but note that on Windows you will need to have Cygwin installed to use this approach):

$ KAWA_DIR=path_to_Kawa_sources
$ cd $KAWA_DIR
$ ./configure --with-javafx=$JAVAFX_HOME
$ make

Running the example

On Windows, the easiest way to run the example is to use the kawa.bat created when building Kawa. It sets up the necessary paths for you.

%KAWA_HOME%\bin\kawa.bat HelloButton.scm

On Cygwin (or Unix/Linux) you can use the similar kawa.sh. I suggest setting your PATH to find kawa.bat or kawa.sh, so you can just do:

kawa HelloButton.scm

Using the kawa command is equivalent to

java -classpath classpath kawa.repl HelloButton.scm

but it sets the classpath automatically. If you do it by hand you need to include %JAVAFX_HOME%\rt\lib\jfxrt.jar and %KAWA_DIR%\kawa-version.jar.
This is what pops up:

If you click the first button the action event fires, and you should see something like:

Event: javafx.event.ActionEvent[source=Button@3a5794[styleClass=button]]

If you type a key (say n) while that button has focus (e.g. after clicking it), then when you release the key a key-released event fires:

Event: KeyEvent [source = Button@3a5794[styleClass=button],
target = Button@3a5794[styleClass=button], eventType = KEY_RELEASED,
consumed = false, character = , text = n, code = N]

Note: Running a JavaFX application from the Kawa read-eval-print-loop (REPL) doesn't work very well at this point, but I'm exploring ideas to make it useful.
Compiling the example

You can compile HelloButton.scm to class files:

kawa --main -C HelloButton.scm

You can execute the resulting application in the usual way:

java -classpath classpath HelloButton

or use the kawa command:

kawa HelloButton

Next
JavaFX-using-Kawa-animation