Making JavaFX Sing
Column inches aren't really a metric one can easily apply to the intangible world of blogging, but when it comes to JavaOne 2007 such a measurement would be largely academic. There was clearly one announcement which stood out head and shoulders over the rest in terms of the fuss it caused.
For those of you living in a cave since early May: JavaFX is Sun's attempt to leap onto a bandwagon already crowded by Adobe's Apollo and Microsoft's Sliverlight, with even more players lining up to scramble on board next to them. At JavaFX's core is JavaFX Script, a declarative statically typed scripting language (formerly known as F3) which speeds the development of user interfaces and GUI effects. The goal is a single consistent technology stretching across the desktop and mobile spaces, ideal for creating Rich Internet Applications (RIAs) with attractive front ends.
Like a lot of people who spend time developing for the desktop market, I'd taken only a brief fly-by tour of F3. It looked interesting, but not mature enough to merit serious consideration for the time being. But when Sun's announcement elevated the technology to 'super hot' I decided to get a little more earnest about exploring this strange new language, and its potential.
The results left me with some mixed feelings.First a health warning: The following comments document first impressions only. They are not the product of someone well versed and practiced in F3 or JavaFX. Quite the opposite: they outline precisely what it is like to come to this technology fresh, from a Swing background. Save for a couple of tutorials and a brief syntax guide, JavaFX is not well served with documentation at this current moment (learning about the API is most effectively done by reading the source code.) For that reason it should be noted that any issues I raise below may well have very simple solutions. Assumptions may be wrong. Facts may be incorrect (although I've tried my best...) You have been warned...!
If the evidence provided by the blogosphere is to be believed, plenty of people have downloaded JavaFX and tried out the demos. Many have gone on to play with the bundled JavaFXPad application (enter snippets of code to immediately see their effect), but few actually tried to develop an actual application from scratch.
FXPlay is a simple (almost useful!) MP3 jukebox, boasting a user interface entirely written from scratch in JavaFX. The pure Java MP3 player is courtesy of JavaZoom's JLayer library. The top section allows the user to select a track to listen to. The lower section houses the status line, a time bar (you can just see a fleck of yellow), the pan/gain controls, and some basic PLAY/PAUSE/STOP buttons.
While it may not be the most functional of applications, it serves as a hands-on examination of what it is really like for a total beginner to write their first application in this much-touted technology.
To try the application yourself:
- Download the zip. You will need Java 5.0 or later, but you do not need JavaFX, as I've included the necessary Jar files as part of the archive.
- Create a new directory and unpack the zip into it.
- From a shell, CD into your directory.
- Make sure you have Java on your path.
- run_me should start the application up from Unix flavoured OS's (you may need to chmod the script to restore execute permissions.) run_me.bat should start the application from Windows.
- Use the Add file menu item to select MP3 files, one at a time, and add them to your play list.
Let us get down to business. What was my first serious experience of JavaFX like?
What is tricker to adapt to is the way variables and components interact with each other.
Under AWT the data the user interface relies upon (for example, the text of a button label) lives within the component itself. Swing's Model/View/Controller-based design introduced the concept of external models for components with very complex data requirements. Still, the programmer commonly must retain a reference to the component to manipulate it, because key settings and attributes continue to be held within the component.
In JavaFX Script variables may be bound to UI components, meaning that not only does the component keep a reference to that data (and all data!) it needs to function, but it automatically receives notification when said data changes.
This leads to some interesting design patterns. For example, it isn't really desirable to simply change the label on a button (from "Play" to "Pause" for example) by arbitrarily calling a
.setText() type method. Instead one defines a string in an object somewhere, binds the button text to that string, then manipulates the string. In effect what you are being asked to do is create a model external to the UI component, and interact with the model rather than the component itself. This is evident in the fact that only the top level components in the FXPlay application actually have references. All the internal buttons, sliders, etc. are anonymous — they merely bind to the data they need.
This pull rather than push mindset can be very tricky to get accustomed to. Instead of pushing changes into UI components, the components themselves pull their changes from whichever compatible piece of data you bound them to.
A similar trick, familiar to those who write database procedures, is the ability to construct triggers: blocks of code which run whenever a given variable, array or object is created, changed, etc. In FXPlay, triggers were used to automatically save the play list to file whenever a new MP3 was added. (A special switch had to be added to disable this, so they didn't run when the data was loaded into the array from file. Saving while loading... ouch!)
Again, this leads to some subtle new ways of thinking about coding: JavaFX does not support constructors, for example, one merely attaches an object creation trigger to the class.
One of the side effects of binding was that it became difficult to initialise data with default values. In FXPlay the information displayed on the status line (the line of text below the play list) does not get populated until the play list is loaded and a track selected. The label's text attribute is bound to the name of the current track. When the UI is first laid out the label text is unset, and consequently the label reports zero height. This causes the UI to jostle when the field is finally populated and sized.
I tried assigning a default value to the string which the label was bound to, but the UI still jostled. Was this something which I did wrong, or are the default values not assigned until after an object's UI components are constructed? Are they initialised in the order of their 'prototypes' in the class structure, the order of their 'bodies' in the source file, or some other order?
Another problem I had was trying to get many UI components to report their location and size. It seems that if layout managers are used to determine the geometry of a UI, the components (or a least the lightweight JavaFX classes which wrap the real Swing components) do not receive/retain their x, y, width and height in a form which can be read from other JavaFX objects.
Then again, I did get a bucketful of stuff shooting up the console whenever I so much as breathed heavily on a component's width or height attribute, so maybe this area should be marked UNDER CONSTRUCTION for now?
Interacting with Java objects was generally painless, except in the case where I had to extract stuff from a hash map which needed casting. The cast worked for simple things like numbers, but arrays of 'things' resulted in errors. (Again, possibly my fault!)
Being honest. the majority of the headaches I encountered while developing the application came not from JavaFX itself, but from trying to integrate it with JLayer. JLayer, while a lovely API for doing simple things (playing an MP3) doesn't make it easy to do more advanced things (pausing/restarting, fast forward, rewind, etc.) However, a more compliant library might not have provided as thorough a test of JavaFX.
Is FX the future?
Yes, JavaFX is new (well, to most of us!) And yes, its pull rather than push model of interacting with UI components takes some getting used to at first. And yes, it is very much incomplete and still needs a whole lot of work before it could be considered as a candidate for a professional desktop application. (You'll note here I've concerned myself only with the language and API itself. Discussions on the state of the tool support can be summed up in four words: THERE AREN'T ANY, YET!)
But is JavaFX the future of desktop and mobile RIAs?
I'd love to say I could answer that with a resounding "YES", but the truth is I have my doubts.
JavaFX Script is an interesting, if sometimes frustrating, language to learn. Yet I can't say my early experiences with it have put me off, quite the contrary. However, I am not the target audience for JavaFX. The target audience is your average Flash user, and Flash users tend to be graphics orientated people with a smattering of (largely self-taught) programming skills; rather than someone like myself, a programmer with a smattering of (largely self-taught) graphics skills.
Is JavaFX Script really the right language to be putting in front of an audience with limited programming skills? Perhaps. JavaFX does lend itself neatly to event driven software, and should the right Flash-like tool emerge for authoring applications this could be a boon. Or could it?
My experiences with JavaFX have not put me off. It's early days, but there's much to be encouraged about. My next project, already underway, is an Instant Messenger using an entirely JFX interface. The lack of tools needs to be addressed urgently, and once those tools start to find themselves in the hands of RIA designers we'll all be in a much better position to judge how suitable this technology really is.
Good luck to Liverpool FC in their Champion's League final tonight. Although, by the time most of you will read this, they'll probably be limping home from Athens after a 3-0 thrashing. Ever the optimist, me... :)