Bean binding Swing example(Swing數據綁定示例)
接觸Swing有一段時間,搜索到JSR295項目,苦于沒有中文資料,所以翻譯了國外的一片文章,英文不好,有語法錯誤請指正。
We'll compare getting and setting bean properties in JBoss Seam with Swing, and show how easy it is in Seam, how painful it is in Swing, and how Beans Binding can save Swing from its misery. We'll end with some discussion of how easy it is to fit Beans Binding into your applications, and future explorations, and how this pattern relates to the Action
pattern we discussed earlier.
The ubiquitous Person
bean will be the backing bean in our examples:

2

3

4

5

6

7

8

We want to create user interface elements which can get and set properties of this bean.
JBoss Seam is great. Set up the component by adding a @Name
annotation:


2

In a Swing application, the code would like like this:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Swing has languished since its introduction with Java 1.2 in December of 1998. One of the reasons for Swing's doldrums was this need to write tedious listener code to bind front-end components to beans. Beans binding solves this problem. Straight to the code. I'll replace
DocumentListener
with a beans binding like this:
2

3

4

5

6

7

8

9

10

11

12

13

Note that
Property
objects are immutable, so you don't need to keep on creating them. The text property can be used to get the text
property of any bean (ie, any bean with a getText()
method).Beans binding gets even better. You can use Expression Language (EL) to create properties:

2

3

4

5

6

7

8


All Swing components are beans, with change listeners, so Beans Binding "just works" on them. Even better, NetBeans 6 comes with great support for beans binding. Right click on the component you want to use as the target and you can bind it to a source without writing any code.
Unfortunately, in NetBeans, only Swing components can be targets. That's great if you want to link a slider to a text field, so the user could slide from 0 to 100, and the text field will show the corresponding number. However, the most common real-world use for beans binding will be not linking UI components to other UI components, but rather, linking UI components to "backing beans". NetBeans 6 doesn't have a point-and-click way of doing that.
But it's easy to do by hand. To use your data bean as a target, just use it. To use it as a source, you'll need to add one more thing: a support for
PropertyChangeListener
s. Let's say some UI component is bound to the Person's firstName. The UI component changes. Under the hood, the Beans Binding works by registering itself as a PropertyChangeListener
. Swing components fire PropertyChangeEvent
s when properties change, so the whole thing happens invisibly when the source is a Swing component.When the source is a bean written for the application, you'll need to add your own support for
PropertyChangeListener
s. This is easy to do, using the PropertyChangeSupport
class. Look at the source code of our Person.java class. The essential change is the addition of the addPropertyChangeListener()
and removePropertyChangeListener()
methods. The beans binding framework uses introspection to look for classes with those two methods. If both of those methods are found, beans binding registers the binding as a PropertyChangeListener
, so it will be aware of changes to the property. Implementing these two methods is trivial; see the source code.Now the Person can be both the source and target for bindings, so our application looks like this:

In this example, I'm using a
GridLayout
. It's ugly. In any real application, I would use NetBeans Matisse, to create beautiful resizable platform-independent interfaces. However, I wanted to keep this code short and simple to focus on the beans binding, without cluttering the example with layout concerns.The savings in lines of code is not great, but the savings in readability, clarity, and verifiability is great.
Now we move on to some more advanced features: adding a validator for that year-of-birth field. Our validation rule is simple: the year of birth can't be in the future.
First write the validator: YearValidator.java. This class extends the
Validator
abstract class, which has one method:
Attaching this validator to the binding requires a twist. It's natural to think of the UI element as the "source" of the data and the bean as the "target" of the data. However, validation occurs on the write-back from the target to the source. Therefore, to use a validator, we must reverse the arguments in the binding, and set the mode to
READ_WRITE
, as follows:
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

The call to
binding.bind()
happens after the validator and converter are added. And note that we use binding.addBindingListener(this);
to add a BindingListener
. The PersonFrame
class, which is also the JFrame
, has been modified to implement the methods of the BindingListener
interface. The method we need to catch validation errors is the

Now we have seen how to use beans binding to easily link UI elements with data beans. We've seen how to use EL to create new properties as combinations of or operations on old properties. We've seen how to use a converter and a validator. That's only the beginning of the beans binding framework.
The main advanced features of the beans binding framework is the ability to bind to collection-style components, such as
JTable
, JList
and JComboBox
. I won't say more about the collection components in this article. In a future article, I'll build a demo of using those components with beans binding. The advantages of using beans binding for simple component are evident. With JTable
components, the advantages are even greater. I will also discuss design considerations. How do you build a desktop application to interact with a shared server? The obvious solution, with built-in support in NetBeans, is to bind front-end JTables
to database tables. This method should not be used in real-world desktop applications, however. I'll explore the alternatives to figure out the right way to do this.Finally, beans binding is called a "framework". The word "framework" brings to mind heavy-weight containers, extending or implementing special classes, threads, a server, tricky XML configuration files, etc. None of these things are present in beans binding. Beans binding works with plain old classes which follow the bean patterns, including, conveniently, all the Swing UI components. The beans binding framework requires only including a small JAR file and creating properties. No server, no configuration, no changes to your existing body of code or deployment practices. It's easy to use, too. I hope after seeing this article, you'll try out the beans binding framework in your project.
In a previous post, we discussed the conventional wisdom for adding functionality to Buttons. The traditional way is to write a
ActionListener
and bind it to the JButton
with addActionListener()
. We showed that this approach is cumbersome, and usually wrong, and the right way is to add an AbstractAction to the JButton. Writing listeners on input components is also cumbersome. Beans binding could be thought of as the correct alternative to change listeners on input UI components, just like AbstractAction
s are the correct alternative to actionPerformed
listeners on command UI elements.I expect that EL and the beans binding framework (JSR 295) will find their way into a future Java release, but there's no reason to wait to start using it.
Download the full sourcecode for this article: example.zip