Groovy Stopwatch



>> Friday, December 17, 2010

Groovy Stopwatch

Before I started using Groovy, I had created a simple little stopwatch Swing application that basically had one button (Start/Stop) and displayed a time. If you are interested, that is here. I wanted to improve it a bit so I could put a countdown so it would give me a few seconds before it started to time. As a little background, I needed that "feature" so when I was timing this UI I was working on it would give me some time to click "start" on my stopwatch and then switch to the UI I was testing. Not the most advanced tool, but it works fine for my needs.

Instead of updating my Java class, which was already fairly complicated due to the nature of Swing programming, I decided to use Groovy's SwingBuilder.

Here is the final result
Stopwatch
Download the Groovy code here.

It was interesting to find that my original Java class for this simple app was 80 lines and my enhanced application in Groovy was only 61, even though I added new features. I probably could have made each of them a little shorter if I really cared about lines of code, but for comparison sake I thought it was interesting how much shorter Groovy was.

For the application itself, here is the code that sets up and displays the Swing UI:

import groovy.swing.SwingBuilder;
import java.awt.BorderLayout as BL
import javax.swing.JFrame

startTime = 0
started = false

swing = new SwingBuilder()
myFrame = swing.frame(title:'Stopwatch', show: true, size:[200,130], defaultCloseOperation: JFrame.EXIT_ON_CLOSE){
panel (layout: new BL()){
panel(constraints: BL.NORTH){
label 'Countdown time'
countdownField = textField (text:'5', columns:4)
}
panel(constraints: BL.CENTER){
startStopButton = button (text: 'Start/Stop', actionPerformed: {
if(!started){
countdownThenStart()
} else {
stopTimer()
}
})
}
panel(constraints: BL.SOUTH){
messages = label (text:'Click Start')
}
}
}


The countdownThenStart() and stopTimer() methods are explained below. One interesting thing I found out was that if I wanted to reference a button (like "startStopButton"), label (like "messages"), or text field (like "countdownField") again, all I had to do was assign it to a variable. If I didn't need it, then I didn't assign it.

I could have made this even simplier if I didn't use the BorderLayout (remove the "constraints: BL.NORTH") or explicitly set the size. I could have just used "pack: true" in place of size. However, since I was learning how to do this, I added them in.

Also, be sure to put the "defaultCloseOperation: JFrame.EXIT_ON_CLOSE" in the frame. I forgot and ended up with dozens of instances of Java running.

To do the countdown, here is the method I used:
def countdownThenStart(){
int secondsInt = Integer.parseInt(countdownField.text)
enableFields(false)

def th = Thread.start{
for(int i = secondsInt; i > 0; i--){
messages.text = i
sleep(1000);
}
messages.text = "Go..."
startTimer()
}
}


This was a little tricky. I had a problem displaying the countdown. It would just display "Go..." and no digits. It turns out I had to wrap those messages in a separate thread and then it worked like a charm.

Finally, the rest of the helper methods look like this:
def startTimer() {
started = true
startTime = new Date().getTime()
enableFields(true)
}

def stopTimer() {
stopTime = new Date().getTime()
started = false
messages.text = ((stopTime - startTime) / ((double)1000)) + " seconds"
}

def enableFields(def enable){
countdownField.enabled = enable
startStopButton.enabled = enable
}


Nothing surprising or confusing here I hope.

Overall, the SwingBuilder was very easy to use. I've written a number of little Swing apps in the past, and I doubt I will ever need to use anything other than Groovy's SwingBuilder for them again.

0 comments:

Post a Comment

  © Blogger template Webnolia by Ourblogtemplates.com 2009

Back to TOP