Making Swing Groovy, Part II: Binding

In my previous post in this series, I presented a trivial Echo GUI written in Groovy.  By using SwingBuilder and closures, the code for the GUI was dramatically simplified compared to the Java version.  But Groovy can go beyond that.  In this post, I’ll talk about the bind method and the @Bindable annotation, which help transform Swing development into the MVC structure of Griffon.

The code for the Echo GUI currently consists of:

[sourcecode language=”java”]
import groovy.swing.SwingBuilder
import javax.swing.WindowConstants as WC

SwingBuilder.build() {
frame(title:’Echo GUI’, size:[300,100],
visible:true, defaultCloseOperation:WC.EXIT_ON_CLOSE) {
gridLayout(cols: 2, rows: 0)
label ‘Input text: ‘
input = textField(columns:10,
actionPerformed: { output.text = input.text })
label ‘Echo: ‘
output = label()
}
}[/sourcecode]

The closure assigned to the actionPerformed property transfers the input from the text field to the output label.  In order to make that happen, both the field and the label were given names that could be referenced inside the closure.

Groovy 1.5+ includes a method called bind, which works with bound properties in the ancient JavaBeans specification.  For those whose only exposure to JavaBeans is through POJO’s on the server side, the original JavaBeans framework was designed to support GUI builders.  It looked and felt much like building GUIs in VB, in that you dragged these “beans” onto a palette, hooked them together, and set the values of their properties.  It was a way of writing Java user interfaces without writing any Java code, at least until you wanted the various widgets to actually do something.

I remember back around 1998, I convinced my boss at the time to purchase Sun’s proposed IDE based on beans.  I think it was called Sun Java WorkBench, or something like that.  It cost about $99, and it came with beans that you could drag and drop, and you could add your own jar files full of beans as well.  While it looked pretty cool, you didn’t have the source code for any of the beans, which limited their usefulness.

Java on the client side didn’t really take off, and the market for the IDE certainly didn’t pan out.  I do remember that the JavaBeans specification — written largely to support the client-side development model — brought us many aspects of Java that we take for granted now.  My first encounter with serialization came from there, as well as reflection, though they used the extremely awkward name introspection for it.  In addition to implementing java.io.Serializable, JavaBeans according to the spec were also supposed to have default constructors and the now-infamous naming convention for getters and setters for all the properties.  Actually, providing a getter method was sufficient to define a property of a JavaBean.

The spec also referred to various types of properties, like bound and constrained, and JavaBeans were also supposed to implement the PropertyChangeListener interface.

Very few Java programs were actually written using those JavaBeans, and the expected third-party market in JavaBeans libraries never seemed to develop.  I seem to recall that there were a couple of success stories (wasn’t IBM’s VisualAge for Java supposed to be written using the original JavaBeans spec?), but mostly the whole technology went away.

It wasn’t until a few years later that JavaBeans re-emerged, as the way to get Java code out of JavaServer Pages.  Sun’s Model 1 architecture consisted entirely of JSPs and JavaBeans, with no explicit servlets anywhere.  Model 2 changed all that by using servlets for controllers, but that came later.  By then, though, people used what we now call POJO’s for model classes, and you were still supposed to make your beans serializable, but all that stuff about property change listeners was largely ignored.

Groovy gives us a chance to use JavaBeans as model classes in an especially easy way.  First, here’s an illustration of a simple GUI that uses the bind method in Groovy.

[sourcecode language=”java”]
import groovy.swing.SwingBuilder
import javax.swing.WindowConstants as WC
import java.awt.BorderLayout as BL

SwingBuilder.build() {
frame(title:’Binding to Slider’, pack:true, visible:true,
defaultCloseOperation:WC.EXIT_ON_CLOSE) {
panel(constraints:BL.CENTER) {
slider(id:’sl’)
}
panel(constraints:BL.SOUTH) {
label ‘Slider value: ‘
label(text:bind(source:sl, sourceProperty:’value’))
}
}
}
[/sourcecode]

Here we’re taking advantage of the fact that all Swing widgets extend Component, which means they support property change listeners.  In this case, we have a slider with a property called value.  The bind method assigns the text of the label to the value property of the slider.  Dragging the slider immediately updates the label.

This is seriously cool, and means that the Echo GUI shown above can be made even more responsive by replacing the actionListener by binding the output label directly to the input text field.

[sourcecode language=”java”]
import groovy.swing.SwingBuilder
import javax.swing.WindowConstants as WC

SwingBuilder.build {
frame(title: ‘Regular Binding (Groovy)’, size: [300,100],
visible:true, defaultCloseOperation: WC.EXIT_ON_CLOSE ) {
gridLayout(cols: 2, rows: 0)
label ‘Input text: ‘
textField(columns:10, id:’tf’)
label ‘Echo: ‘
label(text:bind(source:tf, sourceProperty:’text’))
}
}
[/sourcecode]

The result is that now, any characters typed into the text field are immediately transferred into the label. Deletes work the same way. The text in the output label is bound to the value of the input text field.

While this is interesting and even useful, a true model-view-controller architecture wouldn’t always bind widgets to other widgets. Instead, input values would be transfered to a model class, and then the model values would be sent to the output view. What we need, therefore, is a way to bind the view elements to an actual Java bean.

If this was Java, we would introduce a class that supported property change capabilities. Consider such a model class in Java:
[sourcecode language=”java”]
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Message {
private String text;
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

public String getText() {
return text;
}

public void setText(String text) {
pcs.firePropertyChange(“text”, this.text, this.text = text);
}

public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}

public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
}
[/sourcecode]
The Message class has a single property, called text. It also relies on the PropertyChangeSupport class to enable it to add and remove property change listeners. When the text property is changed, the setText method fires a property change event to all the listeners, where the arguments to the firePropertyChange method are the name of the property, its old value, and the new value.

How does Groovy simplify this? The key is the @Bindable annotation, which is currently only in Groovy 1.6 beta 2. Fortunately, that version is included in Griffon, though I did go to the trouble to download and rebuild it myself (a post for another time).

Using Groovy 1.6b2, here’s the equivalent Groovy bean:
[sourcecode language=”java”]
import groovy.beans.Bindable

class Message {
@Bindable def text
}
[/sourcecode]
Seems almost unfair, doesn’t it? Add an annotation to the field, and you’re done. It’s hard to get much simpler than that.

Now all you need is a listener. In Java land, the GUI would use something like:
[sourcecode language=”java”]
//…
private Message msg = new Message();
//…
msg.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent evt) {
output.setText((String) evt.getNewValue());
}
});
//…
[/sourcecode]
again using an anonymous inner class to respond to the change. By contrast, here is the Groovy version (where in this case the code is sufficiently succinct that I can include the whole thing):
[sourcecode language=”java”]
import groovy.swing.SwingBuilder
import javax.swing.WindowConstants as WC

def model = new Message()

SwingBuilder.build() {
frame(title:’Echo GUI’, size:[300,100],
visible: true, defaultCloseOperation:WC.EXIT_ON_CLOSE) {
gridLayout(cols: 2, rows: 0)
label ‘Input text: ‘
input = textField(columns:10,
actionPerformed: { model.text = input.text })
label ‘Echo: ‘
label(text: bind { model.text })
}
}
[/sourcecode]
Once again, this won’t work unless you’re using Groovy 1.6b2 or above. The bind method has been modified to take a closure as its last argument, and the closure in question refers to the text property of the model, rather than to another widget. Note that now I’ve gone back to implementing actionListener, because I have to get the text value from the view into the model, so it’s not quite as clean as before. That could be changed, but at the moment it seems reasonable to do it that way.

Of course, if we have a model and we have a view, what we need next is a controller. Griffon shows how to do that, but I’ll leave it for another post.

The bottom line is that by using Groovy’s bind method and @Bindable annotation, constructing a GUI based on a realistic MVC architecture is now viable, and even easy.

5 responses to “Making Swing Groovy, Part II: Binding”

  1. Great post as always Ken. Don’t forget about ObservableMap (a quick way to create observable ‘beans’ without class definition) and the new (in groovy 1.6-beta-2) ObservableList.

  2. That was off da’ chains, Ken! (I stumbled here trying to find out who was sending the extra page view to my humble neck of the woods.) I often wondered about all those extra Java interfaces and sjupporting classes in the beans spec. I knew they were cool somehow but never had the time to study them y’know? It almost makes me wanna brak out the docs on other things like java.nio and generics. These are some other things on my todo list that I haven’t gotten to yet for one reason or another.

  3. I really hope that the Netbeans GUI builder will use groovy to build its GroupLayouts — that would be the ultimate GUI building machine! WYSIWYG + readable code 🙂

  4. Binding Framework is great. Binding is one great feature I like in Adobe Flex and JavaFX.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.