Skip to content

Cascading Lists with Groovy’s SwingBuilder

At lunch yesterday, one of my ex-colleagues was telling me that he couldn’t quite get cascading lists to work when using Groovy’s SwingBuilder.

So I knocked up an example for him:

cascade-list-swingbuilder

Mum told me that it is good to share my toys, so:

import groovy.swing.*
import javax.swing.*

def swing = new SwingBuilder()

def masterData = [en: ['Hello, World!', 'How are you?'], es: ['Hola Mundo!', "Como Esta?"], can: ['Foon Ying!', 'Lei Ho Ma?']]

def detailModel = new DefaultListModel()

swing.actions() {
  action(id: 'masterAction',
          name: 'masterAction',
          closure: {e->
            def l = e.source
            if (!e.valueIsAdjusting) {
              def i = l.selectedValue
              detailModel.clear()
              masterData[i].each {
                detailModel.addElement(it)
              }
            }
          })
}
swing.frame(title: 'My Frame', pack: true, visible: true,
                 defaultCloseOperation: javax.swing.WindowConstants.EXIT_ON_CLOSE) {
  panel() {
    tableLayout() {
      tr {
        td {
          scrollPane() {
            list(valueChanged: masterAction.closure, visibleRowCount: 3, listData: masterData.collect {k, v -> k })
          }
        }
        td {
          scrollPane() {
            list(visibleRowCount: 3, model: detailModel)
          }
        }
      }
    }
  }
}

It may not be optimal, but it works.

There’s one or two little ‘gotchas’ here.

First: having to pass ‘masterAction.closure’ directly to the first list seems wrong…elsewhere when using SwingBuilder one would just have to use ‘masterAction’ so this feels a little ‘off’ to me.

Second: the code shown works fine when run under Groovy 1.6.4 via IntelliJ Maia EAP 10666. When run directly in 1.6.4′s GroovyConsole, it gives an error:

Exception thrown: Cannot cast object '[en, es, can]' with class 'java.util.ArrayList' to class 'java.util.Vector'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[en, es, can]' with class 'java.util.ArrayList' to class 'java.util.Vector'

The workaround is to use:

list(..., listData: masterData.collect {k, v -> k } as Object[])

This is probably more ‘correct’ according to the API, anyway.

Still, something feels ‘off’ here…why the different behaviors?

These are minor niggles, however.

It’s still a clean and clear solution.

Gotta love that TableLayout, as well.

[edit]
There was something a bit off, but it should be sorted by now.

Tags: , ,

C, Java Enterprise Edition, JEE, J2EE, JBoss, Application Server, Glassfish, JavaServer Pages, JSP, Tag Libraries, Servlets, Enterprise Java Beans, EJB, Java Messaging Service JMS, BEA Weblogic, JBoss, Application Servers, Spring Framework, Groovy, Grails, Griffon, GPars, GAnt, Spock, Gradle, Seam, Open Source, Service Oriented Architectures, SOA, Java 2 Standard Edition, J2SE, Eclipse, Intellij, Oracle Service Bus, OSB