Chapter 7
[ 159 ]
Any Swing app I've ever worked on has been a mess of component initialization
code, intermingled with anonymous inner classes for event handling. Each Swing
component, however small or insignificant, has to be renewed and given a name.
Figuring out how all of the components nest together, when some such as button
groups and panels may not even be visible, is an endless chore.
The following is a UI built with SwingBuilder that puts a simple UI onto the
GeeTwitter searching DSL from the last chapter. You can see in the forthcoming
screenshot how the markup mirrors the actual layout in the UI. Closures are used in
place of anonymous inner classes for events such as actionPerformed on the Exit
menu. This took less than five minutes to throw together, and unlike a pure Swing
API version, it is production-ready as soon as we remove the Napkin Look and Feel
line from the code:
@Grab(group='net.sf.squirrel-sql.thirdparty-non-maven',
module='napkinlaf', version='[1.2,)')
import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*
import net.sourceforge.napkinlaf.*
data = []
def results
swing = new SwingBuilder()
swing.lookAndFeel(new NapkinLookAndFeel())
frame = swing.frame(title:'Twitter Search') {
menuBar {
menu('File') {
menuItem 'Exit', actionPerformed: { System.exit(0) }
}
}
panel(layout: new BorderLayout()) {
panel (constraints:BorderLayout.NORTH) {
label 'Search for Tweets'
textField(columns:10, actionPerformed: { event ->
println "Search for Event ${event.source.text}"
data = GeeTwitter.search(event.source.text)
results.model = tableModel(list:data) {
propertyColumn(header:'Sender',
propertyName:'from',preferredWidth:20)
propertyColumn(header:'Tweet',
propertyName:'tweet',preferredWidth:140)
}