The following comments are based on Thinlet beta 5.
Thinlet is a GUI toolkit that allows rapid prototyping of user interfaces in Java. Taking a similar (but much simpler) approach to XUL it allows an interface to be described using an XML document. It supports quite a rich array of components.
The framework is built around the premise that there's a single class that does all the heavy lifting: i.e. does all the parsing, event handling, layout, etc. This means that the API is very small. It's just one class, albeit a very large one. And explains why the framework operates on Personal Java and MIDP platforms, it's pretty lightweight.
Creating a Thinlet application is quite simple:
- create an XML description of the user interface
- create a sub-class of thinlet.Thinlet for your application
- use the thinlet.AppletLauncher or thinlet.FrameLauncher to bootstrap the GUI from an applet, or main method respectively.
Components in the GUI description should be named to allow them to be looked up from the object model the Thinlet class maintains internally. Objects are manipulated (i.e properties accessed and updated) via their name. Events are tied to components via their action attribute which indicates the name of the method implementing that event handler.
I started looking at Thinlets not as a means for creating interfaces on small devices, but as an alternative to XUL which I find pretty complicated for simple uses. As a quick way to produce a Java interface and tie it together with some simple application logic I've found it hard to beat.
However the design decisions made to make Thinlet lightweight also means that there are a few disadvantages I'll discuss these in a moment.
Disadvantage #1 -- Hand-rolled XML parser
The first disadvantage is that the Thinlet class contains its own hand-rolled XML parser. Presumably this is to limit externally dependencies and make the API as lightweight as possible.
The downside to this is that its not a fully-fledged XML parser and doesn't support (for example) entity declarations. I'd looked to use this feature to break-up a complex GUI description. It also doesn't support namespaces or additional (non-Thinlet) elements in the GUI description, again this would be useful to add in extra data.
I've also found that the errors that the API generates due to a badly formed GUI description pretty opaque.
There are some pretty lightweight parsers out there, so it would be nice if Thinlet could bundle one of these instead.
Disadvantage #2 -- Limited event-handling
I think the most frustrating thing I've found is not the range of events that the framework supports (Drag and Drop is in progress apparently), but the way the event handling is tied to user provided code via the action attribute.
In short the value of the attribute must be a method on your Thinlet subclass. There's no way to delegate event-handling to another class, or register a series of named event-handlers. This means that for more complex applications you'll end up with a very large class unless you factor out the code into separate utility classes.
This is what I've ended up doing, but it'd be nice to be able to remove that last bit of boiler plate code.
Disadvantage #3 -- The Thinlet class is HUGE!
Faced with the above limitations I'd considered refactoring the framework to splice in some of my own code. However the Thinlet class is nearly 9000 lines of Java code, with few comments. This makes it a bit difficult to get to grips with.
I'm not sure whether this is another design decision aimed at reducing download times, but surely a number of smaller classes wouldn't be much large?
Here are a few other problems I've encountered:
- Can't unset icons -- Seems like its impossible to remove an icon from a component. Using setIcon with a value of null doesn't have any effect.
- Can't determine current focus --
I wanted to have a generic action attached to several text fields. It seemed that I was unable to do this easily as it didn't look like there was a way to determine which component currently had the focus. The only alternative seems to be to have one method for each field, and then delegate calls from those to a generic handler.
Happily a response on the Thinlet forum solved my problem. It seems that the action parameter can take some scripted variables, like this:
<textfield name="A" action="foo(this, this.text, this.name)" /> public void foo(Object field, String text, String name) ...
Which neatly solves my problems. I think this will address some of my gripes with the event-handling also.