Binding a Non-Bound Property

Swing and AWT components can be very frustrating because they generally don't bind any properties. As you know, bound properties are extremely useful in VisualAge for Java, especially because of VisualAge's property-to-property connections.

We'd like some way to make properties bound.

Binding a Swing Property

This is actually pretty easy with Swing, as JComponent already tracks PropertyChangeListeners and has firePropertyChanged() methods

Using JTextField as an example, we'll bind its "text" property:

1: Create class BoundJTextField extending JTextField

NOTE: Make sure you specify that you want to make copies
of the constructors (this is checked by default on the
second page of the "Add class" smartguide)
ALSO: Use the second page of the smartguide to add imports
for:

  com.sun.java.swing.*

  com.sun.java.swing.event.*

  com.sun.java.swing.text.*

or if you're using Swing >=1.1

  javax.swing.*

  javax.swing.event.*

  javax.swing.text.*

2: Create method firePropertyChange()

This may seem weird, but you need this to be able to access the firePropertyChange() method in JComponent from an inner class. I'm not sure whether to think of this as a bug in VAJ's compiler or not...

protected void firePropertyChange(String propertyName, 

                                  Object oldValue, 

                                  Object newValue) {

  super.firePropertyChange(propertyName, oldValue, newValue);

}

3: Create method createListeners()

This method is used to add some listeners to the document (the model) of the JTextField. Whenever the model changes, this listener is informed and will fire a PropertyChangeEvent.

protected void createListeners() {

  getDocument().addDocumentListener(new DocumentListener() {



    public void insertUpdate(DocumentEvent e) {

      firePropertyChange("text", null, getText());

    }



    public void removeUpdate(DocumentEvent e) {

      firePropertyChange("text", null, getText());

    }



    public void changedUpdate(DocumentEvent e) {

      firePropertyChange("text", null, getText());

    }

  });

}

As far as I can see, because the new DocumentListener isn't a subclass of JComponent, and isn't in the same package, it cannot directly access JComponent's firePropertyChange() method...

4: Add a call to createListeners() at the end of each constructor

/**

 * BoundJTextField constructor comment.

 */

public BoundJTextField() {

	super();

	createListeners();

}



/**

 * BoundJTextField constructor comment.

 * @param columns int

 */

public BoundJTextField(int columns) {

	super(columns);

	createListeners();

}



/**

 * BoundJTextField constructor comment.

 * @param doc com.sun.java.swing.text.Document

 * @param text java.lang.String

 * @param columns int

 */

public BoundJTextField(Document doc, String text, int columns) {

	super(doc, text, columns);

	createListeners();

}



/**

 * BoundJTextField constructor comment.

 * @param text java.lang.String

 */

public BoundJTextField(String text) {

	super(text);

	createListeners();

}



/**

 * BoundJTextField constructor comment.

 * @param text java.lang.String

 * @param columns int

 */

public BoundJTextField(String text, int columns) {

	super(text, columns);

	createListeners();

}

5: Make the BeanInfo realize it's bound

In order to use this text property as a bound property in the VCE, we need to explicitly list it as bound in a BeanInfo class. This is necessary because the BeanInfo for JTextField or JTextComponent (probably the latter) explicitly lists the text property as not bound, so we need to override it.

To do this:

  1. Open BoundJTextField to the BeanInfo editor
  2. "Generate BeanInfo class" from the features menu
  3. "Add available features" from the features menu
  4. Select the "text" property -- note that it's only defined as read/write -- we need to change that!
  5. Select the text property in the features pane, and change its "bound" status to true.
  6. Save the beaninfo (you need to right-click somewhere other than the "bound" row to get the popup menu to save)

You now have a bound "text" property.

Other Swing components are similar. Just remember: