JavaFX, WidgetFX and my first widget
A few tips & tricks, a little DiskSpace Widget
I became interested in the early version of the JavaFX Script language, F3 script, thanks to the nice GUI and graphics demos. I'm guessing I'm not alone in that :)
Anyway, the preview release of the JavaFX SDK was released a while ago and I looked at it with some interest. I became more interested in actually doing something with it when I saw the
WidgetFX project, simply becuase I like the idea of widgets/gadgets etc. Until now I haven't been able to develop and run them in a Java environment.
I also saw the oppertunity to actually learn JavaFX Script since widgets are a really good way to make a really small, but still useful application, while getting to know the language.
If you're interested in developing widgets you really should check out the WidgetFX Developers Google group.
People like Stephen Chin, who's been answering loads of my questions :), are really good at answering all kinds of questions about WidgetFX!
It took me quite a lot of time to get at least a bit used to declarative UIs. I'm still not there, but I've made some progress and it's fun.
| This is just a small post about my first widget, a disk space monitor. It's not a step by step tutorial, more of a tips and tricks for a beginner. I've included stuff I've learned when working with the JavaFX Script language and the WidgetFX API. It'll require at least some basic knowledge of the JavaFX script language. |
|
| Read on, visit the quite sparse DiskSpace Widget page or try it out right now. |
|
Versions used:
DiskSpace Widget
The DiskSpace widget is nothing complicated, it's just a small widget displaying how much free space there is on a device. You can try it out here: DiskSpace Widget Remember that it's supposed to run in the WidgetFX container so it's not supposed to be a standalone Java Web Start application.Update: How clumsy of me to forget to add index.html to the welcome files list. Done. Now the link should work. Thanks to Stephen Chin for pointing that out.
The icon I'm currently using in the widget is from the really nice collection Tango Desktop Project. Check it out if you need good looking icons in either PNG or SVG format.
Progress bar
The first thing I started out with was the progress bar. I didn't really know where to start so I simply looked at James Weaver's GUI demo and copied what I needed from that. I really love it when people are helpful and shares these kinds of things. Big thanks to James Weaver for some really good looking demos and their code!
WidgetFX Configuration
Configuration is a handy feature of WidgetFX. It's simply automaticly persist a basic object like Strings, Numbers, Booleans etc. for you. All that is needed to persist for example a String is this:Configuration
configuration: Configuration {
properties: [
StringProperty {
name: "path"
value: bind path with inverse
}
]
}
However you'll need to supply your own GUI for each configuration property.
Here's a piece of code from my widget. This handles the disk space path.
I've not gone through it really well since I'll have a few things
I want to get done before I add all the config I need, so if you see
something strange shoot me a message.
I have two variables here, the path and configPath. That's because bind path with inverse instead of using configPath would keep the TextField and the path in sync all the time and I don't want the change to happen before the user clicks the Done button.
Configuration with GUI
var configPanel:ClusterPanel;
var path:String = System.getProperty("user.home");
var configPath = path;
private function updatePath() {
file = new File(path);
}
private function initConfig() {
configPanel = ClusterPanel {
var label = Label {text: "Path:"};
var textField = TextField {
text: bind configPath with inverse,
hpref: 300 };
vcluster: ParallelCluster { content: [
label,
textField
] }
hcluster: SequentialCluster { content: [
label,
textField
] }
}
}
private function configSaved():Void {
path = configPath;
updatePath();
}
Widget {
configuration: Configuration {
properties: [
StringProperty {
name: "path"
value: bind path with inverse
}
]
component: bind configPanel;
onSave: configSaved;
}
onStart: function():Void {
initConfig();
}
Preview code
Widgets can't be previed in the SDK preview panel since they are not based on a class the preview can render, like for example Frame. However having a preview can still be useful. Having a little piece of "preview code" in your custom node can achieve this with little work.Widget with preview code
import org.widgetfx.Widget;
// Main widget code
Widget {
content: [
Group {
content: [
ProgressNode {
progress: ...
progressTitle: ...
margin: 4
}
]
}
]
}
// Preview code
import javafx.application.*;
Frame {
visible: true, width: 200, height: 200;
stage: Stage { content: [ ProgressNode { progress: 0.7, margin: 4, progressTitle: "test" } ] }
}
JavaFX Script
As I stated in the beginning of this post, widgets are a really good way to get to know this language. There are a few things
Sensible defaults
Always include sensible defaults when you create your own CustomNode. It's so much easier to try out things you don't know if there is a set of default values that presents something in a nice way.
Timeline
Even though it's in the animation package javafx.animation.Timeline can not only be used for animations but for doing things in the background at in interval.Timeline variable
var t = Timeline { ... }
t.start();
...or standalone if you don't need to reference it later on:
Timeline on it's own
Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 1s
action: function():Void {
...
}
}
]
}.start();
Binding with if statement
Binding is a really nice feature that I appreciate a lot. Not only can you bind it one way with just bind, two ways with the bind X with inverse, but you can also use an if statement.bind if
Rectangle {
fill: bind if(progress >= warningThreshold) then barFill else barWarningFill
}
Read more about binding at the PlanetJFX wiki.
Formatting text
Not everything is present in the current preview release of the SDK. I'm guessing that a simple way of formatting will be there in the future, but for now we'll have to use the standard java.text.* classes for this. Not that it's such a burden, but beeing able to write "{total format as <<#,##0>>}" which is mentioned in the PlanetJFX FAQ would of course be nice.Formatting a number
import java.text.DecimalFormat;
var numberFormatter: DecimalFormat = new DecimalFormat(".00");
numberFormatter.format(numberVariable)
What I'm missing
There are mainly two things I've been missing when I've worked with JavaFX. The worst is the lack of design tools. JavaFX is of course a competitor to Flash and Silverlight, but I don't think it'll ever be mentioned in the same context as Flash by any other than Java developers unless we have a real design tool. At least a tool that has the ambition to be used by non programmers.It would also be nice to have better IDE support. Don't get me wrong, NetBeans is a great IDE, but it has spoiled me. Things like fix imports and code formatting isn't working for JavaFX Script code. Code completion is a bit off as well. But hey, it's a preview release of the SDK so I guess it's a work in progress.
There's also a little thing that I find annoying after the API changes. JavaFX Script went through a change from an interpretated language to a compiled one not so long ago. Not surprisingly some changes were made to the API thanks to this. The annoying part is that a lot of examples one can find out there is still in the old format. PlanetJFX has a page about converting to the new syntax that covers some of it. This will of course be fixed over time since new tutorials and examples will be produced. However, people new to the langauage might be turned off when they find that every now and then there is a piece of code they copy from an example that just can't work.
Conclusion
Not much needs to be said other than to repeat what I've stated earlier. JavaFX Script is quite fun and WidgetFX is a nice way to get into it. Not to mention that the actual widgets have a good potential to be really useful.