技术开发 频道

Groovy 1.6的新特性

  Swing builder增强

  现在让我们来看看对Swing开发者大有裨益的两个转换吧:@Bindable与@Vetoable。在创建Swing UI时通常要检查某些UI元素值的变化,为了做到这一点,常规的手段就是在类的属性值发生变化时通知JavaBean PropertyChangeListener。下面展示了该样板式的Java代码:

1 import java.beans.PropertyChangeSupport;
2
3   import java.beans.PropertyChangeListener;
4
5   public class MyBean {
6
7   private String prop;
8
9   PropertyChangeSupport pcs = new PropertyChangeSupport(this);
10
11   public void addPropertyChangeListener(PropertyChangeListener l) {
12
13   pcs.add(l);
14
15   }
16
17   public void removePropertyChangeListener(PropertyChangeListener l) {
18
19   pcs.remove(l);
20
21   }
22
23   public String getProp() {
24
25   return prop;
26
27   }
28
29   public void setProp(String prop) {
30
31   pcs.firePropertyChanged("prop", this.prop, this.prop = prop);
32
33   }
34
35   }

  还好通过Groovy与@Bindable注解可以极大的简化上面的代码:

  class MyBean {

  @Bindable String prop

  }

  再利用上Groovy Swing builder新的bind()方法,定义一个文本输入域并将其绑定到数据模型的属性上:

  textField text: bind(source: myBeanInstance, sourceProperty: 'prop')

  甚至还可以这样写:

  textField text: bind { myBeanInstance.prop }

  绑定还可以处理闭包中的简单表达式,如下所示:

  bean location: bind { pos.x + ', ' + pos.y }

  你或许还有兴趣看看ObservableMap与ObservableList,他们在Map和List上增加了的类似机制。

  除了@Bindable以外,还有一个@Vetoable,用于阻止属性的改变。下面来看看Trompetist类,其中的name不允许包含字母‘z’:

1 import java.beans.*
2
3   import groovy.beans.Vetoable
4
5   class Trumpetist {
6
7   @Vetoable String name
8
9   }
10
11   def me = new Trumpetist()
12
13   me.vetoableChange = { PropertyChangeEvent pce ->
14
15   if (pce.newValue.contains('z'))
16
17   throw new PropertyVetoException("The letter 'z' is not allowed in a name", pce)
18
19   }
20
21   me.name = "Louis Armstrong"
22
23   try {
24
25   me.name = "Dizzy Gillespie"
26
27   assert false: "You should not be able to set a name with letter 'z' in it."
28
29   } catch (PropertyVetoException pve) {
30
31   assert true
32
33   }

  下面来看个完整的使用了绑定的Swing builder示例:

1 import groovy.swing.SwingBuilder
2
3   import groovy.beans.Bindable
4
5   import static javax.swing.JFrame.EXIT_ON_CLOSE
6
7   class TextModel {
8
9   @Bindable String text
10
11   }
12
13   def textModel = new TextModel()
14
15   SwingBuilder.build {
16
17   frame( title: 'Binding Example (Groovy)', size: [240,100], show: true,
18
19   locationRelativeTo: null, defaultCloseOperation: EXIT_ON_CLOSE ) {
20
21   gridLayout cols: 1, rows: 2
22
23   textField id: 'textField'
24
25   bean textModel, text: bind{ textField.text }
26
27   label text: bind{ textModel.text }
28
29   }
30
31   }

  下图展示了该脚本运行后的界面,Frame中有个文本框,下面是个label,label上的文本与文本框中的内容绑定在一起了。

  在过去几年中,SwingBuilder得到了长足的发展,因此Groovy Swing团队决定基于SwingBuilder和Grails创建一个新项目:Griffon。Griffon意在引入Grails的约定优于配置策略,同时还有其项目结构、插件系统、gant脚本功能等等。

  如果你在开发Swing富客户端,请一定要看看Griffon。

1