Annotated Event Listeners

After my initial work on Swing Query, I was reasonably happy with the results. Even though SQuery covers only a handful of the selectors offered by jQuery, it does a remarkable job of cutting down the amount boilerplate code needed to get a GUI up and running.

The next area I wanted to tackle was the event handling mechanism in Swing. Whenever I write event listeners I always face a dilemma. Should I use:

  1. Anonymous inner classes
  2. Make the parent class implement the appropriate listener interface.

Personally I go for the second option because it lets me write event handlers as normal methods and not have me worry about access restrictions of anonymous classes. This is what I am talking about:

Anonymous classes give us the advantage of defining the listener inline. But you can no longer access member variables in a straight-forward manner. Plus there’s also the disadvantage of the avalanche of nested curly braces. Implementing the listener interface does not have these problems, but it has its own quirks. For example, once a parent class implements a listener interface, it is a natural thing to point all your button ActionListeners to this.

This way of sharing a single event listener forces you to write if conditions to tell the sources apart.

All these if conditions make your code harder to read and debug. So how can we have the best of both worlds? Enter, Swing Query and Annotated Event Listeners. If you read my previous article, you’ll remember that Swing Query let’s add ids to any Swing component.

Building on top of this idea, Swing Query now let’s you annotate ordinary methods with a query and an event name and turn them into event listeners.

There you have it. The sweet spot between anonymous classes and implementing an interface. You get to add event listeners inline without a zillion nested curly braces. Plus the listeners are all normal methods with access to member variables without any additional hassle. Just annotate your methods, and Swing Query takes care of the rest.

Introduction to Swing Query

I make GUIs for a living. I spend weeks at a time, pulling out JComboBoxes and JTextFields from the UI treasure-box called Swing and slap them over my JFrames and JPanels. And I’ll be honest: It sucks. Not the designing UI part, thats fun. But writing the thousands of lines of boilerplate Swing code to get things to show up on the screen. After doing this for 2 years, I told myself, just because I am required to code corporate GUIs in Java, doesn’t mean I can’t have fun while coding. Why should JS coders have all the fun?

So one weekend, out of utter frustration, I coded up Swing Query, a Java port of the jQuery library for Swing. For those of you don’t know what jQuery is, shame on you. But it lives up to its tag line: “Write Less, Do More”. That’s precisely what I wanted to do. Given the general verbosity of Java code, I wanted to write a lot less and, given my requirements, I wanted to do much more. So I began writing the library to ease my wounds, one scar at a time.

For the purposes of this blog post, I’ll be using an example that I stole from the Swing Tutorial site from Sun (yikes Oracle).

Now have a look at the following snippet, and tell me you have seen this a thousand times before:

I don’t know about you. But this particular way of coding always bothered me. Why do we have to put these lonely variable declarations up in beginning of a class definition. You might say, “Maybe you need to access them outside of the method they were created in, like in an event handler, perhaps?”. Spot on, fellow sufferer. These variables are indeed used in an ItemListener.

If you think about it. It’s kinda lame that you have to put a variable in a class-wide scope. All you want is to check which component fired the event? That is certainly not worth all the pain. Also, formal scopes for components like buttons and checkboxes don’t make sense at all. Even if they are declared locally inside a method, you can still have access to them if you get hold of the parent container.

So, let’s give these checkboxes some good old fashioned CSS-ish ids. So we can refer to them by their id names instead of creating unnecessary global variables.

Let’s assume there’s an object called squery that is responsible for keeping track of all the children of the parent container and their ids. We can now use this object to give ids to the checkboxes:

Not a great improvement in terms of number of lines written. But this is a war against a source of personal frustration. At least there are no global checkboxes any more !! Time to move on. What else do I hate to write? Ah yes, I hate typing chinButton.setThis and chinButton.setThat and keep on repeating that for every checkbox. If wish I could say it all at once. Like, I need a checkbox that is selected initially and its mnemonic set to the character ‘c’.

Now with sQuery, you can get away with writing this:

Again, I don’t know if this means much to you. Its a lot easier to chain these setters together if I only have to set a few things for every checkbox. Now we have begun to improve the line count of the program. Let’s see if we can do better.

See if you can identify a common pattern in these two snippets:

In my mind, I’m thinking, “I need to add the same item listener to all these checkboxes, and then I need to add them to the panel”. But in reality, I can’t deal with these 4 checkboxes as a whole. So i need to add the ItemListener separately and add them to the panel separately. Pssh.. Wish I could some how group together these 4 checkboxes and say, the group as a whole needs this ItemListener, and as a whole it needs to be added to the panel.

Now, isn’t that handy. We added an extra unit in our chain. But that saved us a total of six lines. We can do even better. All the 4 checkboxes have their selected property set to true. No point of saying that 4 times.

At this point, the perfectionist in me kicks in. If we are going to use ids and group names, then we don’t need to assign the checkboxes to a variable at all. That’s true. We can now say:

It just keeps getting better. Now reduced 4 more lines of variable declarations at zero cost. Let’s get back to the event handler.

So why do we need those ids again? Oh, because we want to know which checkbox was clicked, and set the values of index and ‘c’ accordingly. Only if these values were embedded inside the checkbox itself, we wouldn’t need to have all those if statements. But if that makes you think of sub-classing the JCheckBox class, or having arrays of CheckBoxes, indices and the characters, then I feel pity for you. All we need is to associate some data with the check boxes.

I know the chain is getting a bit long. But note that there are two thing happening here. I got rid of the ids. I just anonymously add the checkboxes to the “choice” group. And I use the data method to associate a key,value pair with every checkbox. The end result is a simplified event handler.

Now that just shaved 12 more lines from our code, leaving behind a perfectly readable event handler.

Hope that made those nasty Swing burns of go away. There’s no reason Swing development should be as tedious as it should. It’s a very useful cross-platform GUI toolkit. Why not make it more useful and using a library that makes it fun to use.

Get your copy of SQuery today. Or even better, contribute to the project. Happy coding.