By using a combination of events and adapters, we can connect beans in many interesting ways. We can even “bind” two beans together so that if a property changes in the first bean, the corresponding property is automatically changed in the second bean. In this scenario, the beans don’t necessarily have to be of the same type, but in order to make sense, the properties do.
Close the Molecule
file and start
a new one. Grab two NumericField
beans from
the palette, drop them in the workspace, and select one of them. You’ll
probably want to set the AbsoluteLayout again. You can also adjust the
width of the fields by dragging them at the sides. You’ll notice that a
NumericField
has many of the standard
properties of a Swing component. If you look in the Other Properties
section of the Properties pane, you can find an integer property called
value
that represents the numeric value
of the field. You can set it there or enter a number directly into the
field when you run the program. NumericField
rejects nonnumeric text.
Let’s bind the value
property of
one of the fields to the other. Activate the Connection Wizard to create a
connection between the two fields. Click first on numericField1
and then on numericField2
so that numericField1
is the source. In the wizard,
choose the propertyChange()
event of
the source field. This is the listener method for PropertyChangeEvent
, a generic event sent by
beans when one of their properties changes. When a bean fires property
change events in response to changes in a particular property, that
property is said to be “bound.” This means that it is possible to bind the
property to another bean through the generic mechanism. In this case, the
value
property of our NumericField
beans is a bound property, so
whenever it changes, a PropertyChange
Event
is
fired.
Choose Next, and select the value
property as the target for numericField2
. Click Next again, and select the
Property radio button on the Parameters screen. Click the “...” editor
button to pop up a Select Property dialog. Select the source numeric field
(probably named numericField1
, if that
is your source button) from the pull-down menu, and then choose the
value
property. Click OK and Finish to
complete the hookup.
Run the application, and try entering values in the first field
(numericField1
). The second field
should change each time. The second bean’s value property has been bound
to the first.
Try binding the value property in the other direction as well so that you can change the value in either bean, and the changes are propagated in both directions. (Some simple logic in the beans prevents infinite loops from happening here.)
NetBeans has again generated an adapter for us. This time, the
adapter listens for PropertyChangeEvent
s and invokes the setValue()
method of our target field. We
haven’t done anything earth shattering. The PropertyChangeEvent
does carry some extra
information—the old and new values of the property—but we’re not using
them here. And with the Connection Wizard, you can use any event source as
the impetus to set a property on your target bean. Finally, as we’ve seen,
the property can derive its value from any other bean in the layout. The
flexibility of the Connection Wizard is, to some extent, masking the
purpose of the events, but that’s OK. If we are interested in the specific
property that changed, or if we want to apply logic about the value, we
can fill in the generated method with our own code.
Many Swing components have bound properties, which are usually documented in the Javadoc for the class.
In the previous section, we discussed how beans fire PropertyChangeEvent
s to
notify other beans (and adapters) that a property has changed. In that
scenario, the object that receives the event is simply a passive
listener as far as the event’s source is concerned. JavaBeans also
supports constrained properties, in which the event
listener gets to say whether it will allow a bean to change the
property’s value. If the new value is rejected, the change is cancelled;
the event source keeps its old value.
The concept of constrained properties has not been heavily used in
the normal operation of Swing, so we won’t cover it in detail here. But
it goes something like this. Normally, PropertyChangeEvent
s are delivered to a
propertyChange()
method in the
listener. Constrained properties are implemented by delivering
PropertyChangeEvent
s to
a separate listener method called vetoableChange()
. The vetoableChange()
method
throws a PropertyVetoException
if it
doesn’t like a proposed change. In this way, components can govern the
acceptable values set by other components.
Get Learning Java, 4th Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.