Nice Weather for Some Clojure (UIs)
Summary: I tried build something slightly non-trivial with Seesaw and learned some things.
And so it came to pass that it seemed like I needed to start dog-fooding Seesaw a bit. I’ve been steadily adding features and building tiny toy apps to demonstrate them. Others (and others) have apparently found it useful, but I haven’t tried anything myself.
So, I decided to write Gaidica, a little app that displays weather info for user-selected cities. The whole process wasn’t terrible, but shows that there’s work to do. I’d guess about 4 hours of work including fixing Seesaw bugs as I hit them and at least an hour puzzling over Clojure XML stuff. Here’s a screenshot of the forecasts:
The code is all available on github.
Intro
Just to make sure we’re on the same page, Seesaw is an API/DSL for building user interfaces in Clojure. It happens to be built on Swing as you’ll see below, but please don’t judge it too harshly. I’m working hard to make it so you never need to know that Swing’s even there.
The Data
I decided to use Weather Underground’s XML API for the data. It provides the data in a simple format and as a bonus, includes icons for weather conditions, which saved me some work. Additionally, I got to do some XML wrangling in Clojure. Let’s just say that that deserves a blog post of its own.
In any case, I just point Clojure’s (xml/parse) function at the URL and get back some results. All this is done in a background thread using (future) to keep the UI responsive.
The Good
I mostly want to focus on the bad in this post, but despite any difficulties I had, building this was more enjoyable in Clojure+Seesaw than the equivalent Clojure+Swing or raw Java code. The lack of (proxy) and (reify) usage is testament to that.
Seesaw’s table support, seen in the webcam tab below, really paid off. Compared to the equivalent JTable-wrangling you’d have to do, it was downright dreamy.
Here’s the code to create that table:
(defn make-webcam-table []
(table
:id :webcam-table
:model
[:columns
[{:key :handle :text "Name" }
:lat :lon
{:key :updated :text "Last Updated"}
{:key :image :text "Image"}]]))
The Bad
I learned a lot during this exercise. One thing I noticed is that Swing is a pain in the ass. I think when you’re in the depths of a Java-based Swing app, you don’t even notice it because you’re already so mired in Java verbosity. It’s a form of Stockholm Syndrome I guess.
Most of the pain centered around, you guessed it, layout. I wanted to do it with the vanilla Swing layouts provided by Seesaw (border-panel, vertical-panel, etc), but after fiddling with component alignments and lame resize problems, I eventually surrendered and ran back to MigLayout. It’s powerful and pretty easy to use, but it’s yet another little language to learn. Luckily Seesaw already has Mig support.
Otherwise, most of the other issues I had were just missing functionality. Swing methods not yet wrapped by Seesaw. The nice thing is that since Seesaw’s a fairly thin wrapper, it’s easy to drop down to raw Swing when needed. Some random functionality that I’m going to address as a result:
- Manipulation of the widget hierarchy needs to be seamless. This has historically been a problem in Swing (
invalidate(); revalidate(); repaint()!!) - Widget styling. Sprinkling fonts and colors throughout the code is a hassle. The main question is whether I just add convenience options for this, or go whole hog and try for a CSS-style styling.
- Saner defaults for “vanilla” layouts. I think I can tune some of the defaults and add some dials to make it less frustrating. It still really bugs me that I had to use Mig for something so simple.
Conclusion
From the perspective of a potential Seesaw user, already suspicious of Swing, all of this is a problem. I’ll take it as a challenge to continue making Seesaw a buffer between them and the occasional craziness of Swing. Feedback welcome!

