Thursday, August 23, 2007

Groovy SwingBuilder and Secret Methods

Last night, I mocked up a little Groovy example that split an environment variable (e.g. PATH) and displayed each entry. This is a modest experiment to mitigate Microsoft's dreaded, 1970-vintage line editor for modifying environment variables. (I had done something similar in Python years ago, and the topic has come up recently. More on this to come).




I used straight-ahead, quick-n-dirty Swing, and then decided to reduce the code by using a SwingBuilder.

As usual, most of it went fine, except when it came to simply performing something like this:


jPanel.add( scrollPane );

On a couple of projects now, I have spent considerable energy trying to figure out how to do this.

Widget To The Rescue

The answer may be in the GINA book but on the web, the only morsel of help that I could find is an article from 2004. (thank you!)

The answer is the secret widget method! See the code listing below for an example on how to use it.

As an aside, I find it useful to display non-existent PATH entries in red (see screenshot).

import java.awt.*
import javax.swing.*
import javax.swing.table.*
import groovy.swing.SwingBuilder

class MyTableCellRenderer extends JLabel
implements TableCellRenderer {
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int rowIndex, int vColIndex) {

setText(value.toString())

File file = new File(value)

if( !file.exists() ) { setForeground(Color.red) }

return this
}
}

///////////////////////////////////////////////////////////////
// static public void main(String[] args)
//
// args[0] = env var to view

final String DELIMITER = ';' // change this for Unix

String envVar = System.getenv(args[0])

// Build data

String[] columns = [ args[0] ]

String[] values = envVar.split(DELIMITER)
Object[][] data = new String[values.length]

for( i in 0..values.length-1 ) {
String[] row = new String[1]
row[0] = values[i]
data[i] = row
}

// Build GUI. Note that this is quick-n-dirty stuff,
// that illustrates a SwingBuilder more than proper
// Swing techniques.

builder = new SwingBuilder()

JTable table = new JTable(data, columns)
def renderer = new MyTableCellRenderer()
table.columnModel.getColumn(0).setCellRenderer(renderer)
JScrollPane scrollPane = new JScrollPane(table)

gui = builder.frame( title:'Code to Joy',
size:[520,500] ) {
panel( layout: new BorderLayout(),
constraints: BorderLayout.NORTH ) {
widget(scrollPane) // THIS is a revelation
}
}

gui.show()

5 comments:

rhyolight said...

Sweet. But maybe you could use the File.pathSeparator instead of ";". Then no change for a different OS.

Anonymous said...

why wouldn't the follwing work for you?

gui = builder.frame( ... ) {
scrollPane {
widget( table )
}
}

you could also use SwingBuilder's jtable support for models and columns, check GINA page 263 ;-)

Michael Easter said...

re: rhyolight.

Thanks: you are absolutely right. Excellent point.

re: Andres.

Indeed, it works for me. I was just so happy to discover "widget" that I posted as soon as it worked.

I don't own GINA but it is on my list. Duly-noted. Thanks

M.

Danno Ferrin said...

It's also listed on the Groovy Wiki...

http://groovy.codehaus.org/Alphabetical+Widgets+List

It gets monotonous reading the obvious entries, so I can see why it is missed.

Also entertatining are
- map(...) which returns a java.util.Map of the attributes
- container(...) {...} which will be a container variant of widget(...), right now it's exactly the same.
- actions() {...} which returns a list of the declared items, intended to be used to declare actions in context of a given swing builder and attaching it's id: attribute, used in GroovyConsole.

Anonymous said...

Great! you'll find more info on programming UIs with Groovy at http://groovy.codehaus.org/GUI+Programming+with+Groovy
like the brand new SwingXBuilder (swingx from http://swinglabs.com) and JideBuilder for the JIDE JCL.
Keep on Groovying!