Swing 是一个极其强大的 GUI 工具集。但糟糕的是,有时候其复杂性会影响开发人员挥发它的能力。如果您刚接触 Swing,会觉得像是在学习开波音 747,而您实际上只需要开单引擎的 Cessna 或滑翔机。
Groovy 的 SwingBuilder
并不能降低各种任务内在的复杂性,比如选择适当的 LayoutManager
或处理线程问题。它降低的是语法复杂性。Groovy 的命名参数/变量参数构造器非常适合需要实例化的各种 JComponent
,然后马上可以为它们配置一系列设置器。(关于SwingBuilder
的更多信息,请参见 参考资料)。
但是,同样有价值的是 Groovy 对闭包的使用。对于 Swing,我长期关注的问题是自然的层次结构似乎在实现细节中消失了。在 Java 代码中,会得到一组相互脱节的组件,看不出哪个组件属于哪个组件。可以以任意次序声明 JFrame
、JPanel
和 JLabel
。在代码中,它们看起来是平等的;但是,实际上 JFrame
包含 JPanel
,JPanel
进而包含 JLabel
。清单 8 给出一个示例:
import javax.swing.*; public class HelloJavaSwing { public static void main(String[] args) { JPanel panel = new JPanel(); JLabel label = new JLabel("Hello Java Swing"); JFrame frame = new JFrame("Hello Java Swing"); panel.add(label); frame.add(panel); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200,300); frame.setVisible(true); } } |
编译这段代码 (javac HelloJavaSwing.java
) 并运行它 (java HelloJava
),应该会显示图 1 所示的应用程序:
HelloJavaSwing
清单 9 给出用 Groovy 编写的同一个应用程序。可以看到 SwingBuilder
使用了闭包,这让我们可以清晰地看出拥有关系链。
import groovy.swing.SwingBuilder import javax.swing.* def swingBuilder = new SwingBuilder() swingBuilder.frame(title:"Hello Groovy Swing", defaultCloseOperation:JFrame.EXIT_ON_CLOSE, size:[200,300], show:true) { panel(){ label("Hello Groovy Swing") } } |
输入 groovy HelloGroovySwing
会看到图 2 所示的应用程序:
HelloGroovySwing
注意,在 清单 9 中,所有组件名去掉了开头的 J
,方法名中也去掉了多余的 get
和 set
。接下来,注意 frame
的命名参数构造器。在幕后,Groovy 调用无参数构造器,然后调用设置器方法,这与前面的 Java 示例没有区别。但是,设置器方法都集中在构造器中,代码更简洁了,去掉 set
前缀和末尾的圆括号也大大减少了视觉干扰。
如果您不了解 Swing,这段代码看起来可能仍然比较复杂。但是,如果您具备哪怕最粗浅的 Swing 经验,就可以看出它具有 Swing 的特征:干净、清晰和高效。
正如在前一节中所做的,通过脚本了解概念,然后把脚本转换为类。创建文件 Gwitter.groovy,见清单 10。这是 Groovy + Twitter 客户机 UI 的起点。
import groovy.swing.SwingBuilder import javax.swing.* import java.awt.* class Gwitter{ static void main(String[] args){ def gwitter = new Gwitter() gwitter.show() } void show(){ def swingBuilder = new SwingBuilder() swingBuilder.frame(title:"Gwitter", defaultCloseOperation:JFrame.EXIT_ON_CLOSE, size:[400,500], show:true) { } } } |
输入 groovy Gwitter
,确认会出现空的框架。如果一切正常,下一步是在应用程序中添加一个简单的菜单。