Jens Schauder is software developer since 1997. He loves software development for the constant challenges and constantly changing environment. A great chance to learn and teach. He is also blogger, author of various articles and speaker at conferences. Jens is a DZone MVB and is not an employee of DZone and has posted 87 posts at DZone. You can read more from them at their website. View Full User Profile

Binding Scala Objects to Swing Components

07.23.2011
| 5051 views |
  • submit to reddit

If you do Swing application development, especially the enterprise application type you know lots of code that looks like this:

    public class Person {
        private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
     
        public void setName(String aName){
            String oldValue = name;
            name = aName;
            pcs.firePropertyChange("name", oldValue, aName);
        }
     
        public String getName(){
            return name;
        }

Having properties like this you can bind them to Swing components using JGoodies Binding like this:

MyBean bean = new MyBean();
      BeanAdapter adapter = new BeanAdapter(bean, true);
      ValueModel stringModel = adapter.getValueModel("name");
      JTextField field = BasicComponentFactory.createTextField(stringModel);

If you don’t know JGoodies Binding you should read this article about it asap.

If you do form based Swing applications this is the way to go: don’t write Listeners, bind components.

Yet I have a huge problem with this code. Actually multiple problems:

  • You have to repeat the name of the property in four places and you will end up in hell if you don’t do it in the correct way: In the name of the setter, in the name of the getter, in the first argument to firePropertyChange and in the call to the binding framework.
  • A trivial property takes 8 lines of code. Thats EIGHT lines of code. Or depending on your code quality probably about 1/100th to 1/10th of a bug, for a trivial property.
  • Apart from being to much code, it also has a high degree of duplication, because it is the same pattern over and over again. Yet their doesn’t seem to be a reasonable way to abstract over this kind of thing

If you are willing to switch to another language you actually can abstract over this quite nicely. This of course in no surprise, since it should be easy to write a language that offers support for this kind of property. But that is not what I’m talking about. I’m of course talking about a little Scala goodness. How about this for defining a class with a property:

 

    class Person extends PropertyOwner {
        val name : Property[String] = "smith"
    }

Note that there is only one line defining the property (including setting it to an initial value). So how would binding it to a JTextField look like? Like this:

        val p = new Person
        val nameTextField = new JTextField()
        Binder.bind(p.name, nameTextField)

Note that I don’t use the String “name” anywhere. Its all just normal, strongly typed values. If I use firstName instead of name by accident, the compiler will complain. The trick is obviously that I actually use objects of type Property, instead of fields, getters and setters. Yet using this thing looks (almost) perfect natural:

        val p = new Person
        p.name := "Alf"
        println(p.name())

The code to achieve this is rather simple and short. The key is that a Property has a apply method returning its value and an := operator as replacement for a setter.

    class Property[T](var value : T) {
        var listeners = List[T => Unit]()
     
        def apply() = value
     
        def :=(aValue : T) {
            if (value != aValue) {
                value = aValue
                fireEvent
            }
        }
     
        def registerListener(l : T => Unit) {
            listeners = l :: listeners
        }
     
        private def fireEvent {
            listeners.foreach(_(value))
        }
    }
     
    object Property {
        implicit def apply[T](t : T)(implicit owner : PropertyOwner) : Property[T] =
            new Property(t : T)
     
        implicit def toT[T](p : Property[T]) : T = p()
    }
     
    trait PropertyOwner {
        implicit val THE_OWNER = this
    }
     
    object Binder {
        def bind(p : Property[String], textField : JTextField) {
            var locked = false
     
            initTextField
            syncFromTextFieldToProperty
            syncFromPropertyToTextField
     
            def initTextField = p() match {
                case null => textField.setText("")
                case _    => textField.setText(p().toString())
            }
     
            def syncFromPropertyToTextField {
                p.registerListener { value : String =>
                    if (textField.getText != value)
                        textField.setText(value)
                }
            }
     
            def syncFromTextFieldToProperty = textField.getDocument.addDocumentListener(new DocumentListener() {
                def changedUpdate(e : DocumentEvent) = updateProperty
                def insertUpdate(e : DocumentEvent) = updateProperty
                def removeUpdate(e : DocumentEvent) = updateProperty
            })
     
            def updateProperty = {
                p := textField.getText
            }
        }
    }

This is currently just a little toy, call it proof of concept if you like. It only works with JTextFields, and the event notification might needs tweaking, since it provides just the new value of the property right now. There are many more ideas how to use this as a basis for building nice clean code with a Swing GUI. Watch this blog for more ideas and toys like this.

From http://blog.schauderhaft.de/2011/05/01/binding-scala-objects-to-swing-components/

Published at DZone with permission of Jens Schauder, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)