JavaFX using Kawa - introduction
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-betaThe 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.scmbut 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 HelloButtonor use the
kawa
command:
kawa HelloButton