Groovy SwingBuilder Model Binding
I've been messing around with Groovy's SwingBuilder in my spare time. I did quite a bit of google-ing trying to figure out how to bind widget values to model properties. The example on the Groovy website wasn't very real world though it did get me pointed in the right direction.
After scanning the mailing list archives for quite a while I finally came up with a decent example of how to bind values from swing widgets to model properties. For this example I am creating a very simple login window. I put everything in a single groovy script to make this easy. Also note that I used MigLayout. While this works I wonder if this is best. I hope to hear from SwingBuilder enthusiast on my approach
import groovy.swing.SwingBuilder
import net.miginfocom.swing.MigLayout
import javax.swing.WindowConstants as WC
class User {
String username
String password
}
def user = new User()
def swing = new SwingBuilder()
usernameTextField = swing.textField(columns:20)
passwordTextField = swing.passwordField(columns:20)
gui = swing.frame(title:'Login',defaultCloseOperation:WC.EXIT_ON_CLOSE) {
panel(layout:new MigLayout('fill')) {
label(text:'Username')
widget(usernameTextField, constraints:'wrap, grow')
label(text:'Password')
widget(passwordTextField, constraints:'wrap, grow')
button(text:'Login', constraints:'span', actionPerformed: {
println user.username
println user.password
})
}
}
swing.bind(source:usernameTextField, sourceProperty:'text', target:user, targetProperty:'username')
swing.bind(source:passwordTextField, sourceProperty:'text', target:user, targetProperty:'password')
gui.pack()
gui.show()
.
Re: Groovy SwingBuilder Model Binding
import groovy.swing.SwingBuilder
import net.miginfocom.swing.MigLayout
import javax.swing.WindowConstants as WC
class User {
String username
String password
}
def user = new User()
SwingBuilder.build {
frame(title:'Login', pack: true, show: true, defaultCloseOperation:WC.EXIT_ON_CLOSE) {
panel(layout:new MigLayout('fill')) {
label(text:'Username')
textField(id:'usernameTextField', columns: 20, constraints:'wrap, grow')
label(text:'Password')
passwordField(id: 'passwordTextField', columns: 20, constraints:'wrap, grow')
button(text:'Login', constraints:'span', actionPerformed: {
println user.username
println user.password
})
}
}
bind(source:usernameTextField, sourceProperty:'text', target:user, targetProperty:'username')
bind(source:passwordTextField, sourceProperty:'text', target:user, targetProperty:'password')
}
Let's review the changes one by one. The first you may notice is that this example uses a static method build() to properly build the UI on the EDT. Frames in SwingBuilder understand two synthetic properties (pack,show), thus eliminating the last two explicit method calls. TextField and PasswordField are build inside the main closure, a (synthetic) id property is used to keep a reference in the SwingBuilder instance (created by the static build method and used as delegate). Lastly the bindings are created also inside the main closure, so that they may have access to the previous saved components.
Benefits of this approach- the UI is built in the EDT (according to Sun's guidelines)
- component references may be saved in the "build" scope
- all UI related behavior is grouped in the build closure
def swing = SwingBuilder.build{ frame(id:'f')}
swing.f.title = "Groovy!"
Cheers,Andres
Re: Groovy SwingBuilder Model Binding
Thank you so much for this example and explanation. You answered a lot of lingering questions I had. I was using widget() to add the components because I read in order to have a reference to them they needed to be created outside of the ui code. Nice to know I can always get them via the ID.
Where would you say is the best source for this kind of information that is up to date?