2005-07-12

Book: "Swing Hacks"

If you're not interested in Swing or Java 2D, I imagine you find my blog pretty dull. If you are interested in Swing and/or Java 2D, you've perhaps been intrigued by the new O'Reilly book "Swing Hacks".

In terms of physical artifact, this is at the better end of O'Reilly's offerings. Decent paper, good image reproduction, and subtle use of the color purple, except in the preface which is made more difficult to read by the absence of anything that ought to have been purple. This book is much better produced than its fatter contemporary, Killer Game Programming in Java. (One final point: the book smells great. I'm not sure if I have a congenital love of this particular smell, or if it's because it's how Acorn's RISC OS 3 Programmers' Reference Manuals smelled. Either way, I like the smell. It's probably killing me.)

I'm wary of being unfair towards this book. A lot hinges on what purpose you think it's meant to serve and, in particular, how you understand "hack".

Amongst people I know, there are three main uses of "hack". It can mean "breaking in to a computer", "coming up with an unorthodox but good solution to a problem", or "coming up with an ugly expedient solution to a problem". Obviously, this book has nothing to do with the first sense (which seems to be being overtaken by the verb "own0r" in my circles, even though the slashdotter's suggested "cracker" never went anywhere amongst people I know).

In this book's title, "hack" seems to mean "ill-advised, badly-implemented, or uninteresting code".

Some hacks are lacking in non-obviousness
A strong candidate for the worst hack in the book is hack #16 "Make Different List Items Look Different". This "hack" is basically just using ListCellRenderer. Seriously. Did they actually mean to call this book "Swing Hacks For People Who Haven't Read Sun's Java Tutorial"?

This hack has other problems, too. It's ugly on-screen, and the source is full of copy and paste code (for which the author actually congratulates himself when he points out that it could have been even worse). Related to the copy and paste code, a more useful hack might have been "You Don't Ever Need GridBagLayout And Should Avoid It", but it looks like someone needs to teach the author that first. He even suggests a visual Swing GUI builder, at which point I heard the sound of foreheads banging against desks.

Some hacks are obvious because they were articles on the Swing Connection years ago. Examples would be the trio right near the start of hack #5 "Add a Watermark to a Text Component", hack #6 "Watermark Your Scroll Panes", and hack #7 "Put a NASA Photo into the Background of a Text Area". (This theme of near-duplicate hacks continues throughout the book. I think they must have been told they had to reach the magic number 100.)

Hack #52 "Use HTML and CSS in Text Components" is truly trivial. This is in the JavaDoc, never mind the tutorial! How can anyone but an absolute beginner (or non-reader) not know that you can do this? It's in the SwingSet demo! The author describes it as a "little-known feature". On what planet?

Hacks such as hack #25 "Export Table Data to an Excel Spreadsheet" are just rewrites of old JavaWorld tips from back when JavaWorld sometimes had interesting content. Hack #81 "Make Mac Applications Behave Normally" is far less detailed than Apple's own "Java Property, VM Option, and Info.plist Key Reference for Mac OS X".

These are the kind of things you get better answers to by just typing your question at Google.

Some hacks aren't good enough to be used in a real program
Hack #17 "Reorder a JList with Drag-and-Drop" is a good example of something potentially useful that just doesn't quite look right.

Hack #42 "Make Your Frame Dissolve", if you run it, is so bad it's almost funny. It would be better described as a failed hack. "Here's something that doesn't really work."

Hack #48 "Make Text Components Searchable" is a really weak implementation, not even bothering to use highlighters. There's a much better example in Kim Topley's "Core Swing: Advanced Programming", which is out of print even though it's the best Swing book I've seen. (Sun's tutorial's pretty good for the beginner.)

Hack #59 "Create a Color Eyedropper" is laughably bad. Run it and see. I cringed.

Some hacks are badly implemented
Even supposing the general idea is sound, some of the implementations are not the kind of thing you'd want your less experienced coworkers copying in to your codebase.

Hack #50 "Auto-Completing Text Fields" creates a Thread rather than a Runnable to pass to SwingUtilities.invokeLater (this is a frequent error in the book; where were the technical reviewers?). And implements ListSelectionListener in a top-level class for no obvious reason. And doesn't bother to pop down the list of completions if focus is lost. And the regular expression in the text is wrong; the one in the code is different but also wrong because metacharacters in the result of JTextField.getText aren't escaped. (The whole use of regular expressions to implement String.startsWith is bad craziness anyway, so even fixing both the regular expressions would still leave me unhappy.) And there's no attempt made to give the pop-up list a pleasing width. If your 12 year old kid had written this, you'd give them a pat on the head for effort, point out their mistakes, and suggest they pair program with you next time. When you see it in a book, it's depressing...

Hack #79 "Launch External Programs on Windows" is about Runtime.exec, which is well-known and well-documented. (See an earlier section of complaints. Many of the hacks actually fit in multiple problem categories.) Also well known, though seemingly not to the author of this "hack", is that you shouldn't use the exec(String) form. Hack #80 "Open Files, Directories, and URLs on Mac OS X" makes the same mistake, but does at least go on to explain how to cope with spaces. If they're aiming at people who don't even know about Runtime.exec, they really ought only show them String[] forms. And would a less valueless "hack" have been to show how to work on MS Windows and Mac OS?

Hack #91 contains ""+(char)0xf099 with no explanation of what's wrong with "\uf099", which seems like it would be strongly advantageous. There's a distressing amount of this kind of voodoo.

There are plenty of unnecessary casts, too.

Some hacks don't work with different LAFs
One of the big problems when customizing Swing components is taking the different LAFs into account. Hack #10 "Building a Drop-Down Menu Button", for example, doesn't work on Mac OS. The author congratulates himself that "one nice thing about assembling the drop-down from standard components is that it will still look good when used with a different Look and Feel", ignoring the fact that you can't change the background color of a button on Mac OS. The screen shot is one of the few that wasn't taken on Mac OS. Presumably someone noticed it didn't work, but they couldn't be bothered to fix it or add a note?

Using setMargin on the JButton used for the down arrow also doesn't work on Mac OS, leaving the button far too narrow for its icon. And the pop-up pops up to the left of the button, not beneath it. (Looking at their screenshot figure 1-28, I'm a little confused as to what they were really trying to achieve. Nothing like any drop-down menu I've ever seen.)

Some hacks are lacking in utility
Hack #51 "Write Backward Text" would be okay if it were the only hack that demonstrates painting into a transformed Graphics2D, but it isn't. So we have a useless effect that we could have inferred an implementation of based on the same technique being used in an earlier hack.

Some hacks are things you just wouldn't want to do
Hack #4 "Display Dates in a Custom Calendar" springs to mind. Date pickers always seem to suck, and this is a particularly weak one.

There's a whole chapter of hacks related to JFileChooser, when the only hack you need there is one that uses the AWT dialogs on Mac OS and MS Windows, and the Swing one on other Unixes (where anything's better than what Motif has to offer). One day, when Sun dumps Motif for GTK+, I'll be able to forget JFileChooser completely. The fact that Sun refuse to fix various problems with the AWT dialogs still isn't enough to make them a worse choice.

There's almost no mention of trade-offs or alternatives
This is one of my most frequent complaints about books, and here it's perhaps unfair. A good example of a book that goes out of its way to present detailed and useful analysis of trade-offs and alternatives is Addison-Wesley's "Design Patterns". As a reference book, it's particularly important that it fulfill that criterion. "Killer Game Programming in Java" was weak for lack of such discussion, I felt, and I expect better from a book that's supposed to be a tutorial. But how about "Swing Hacks"? It's not a reference work, and it's not really a tutorial either. It's more of a bag of ideas.

All the same, I think it would have been a better bag if the authors had explained their reasons for considering and rejecting other implementations. Take hack #15 "Make JLists Checkable", for example. Why doesn't the hack author simply use a JTable with a Boolean column alongside the column representing the list data? It's easy, and it's a lot less weird. This and other hacks smell of hacking for hacking's sake. Hacking in the sense of "ugly solution".

It's a shame to have one of the Swing developers as an author without getting any sort of guidance about "this is the kind of flexibility we were imaging you'd exploit to implement this kind of thing". (I notice that there's little mention of UI delegates in "Swing Hacks". Anyone who's tried to use them knows that, though they must have seemed like a good idea, they're a real pain. If you need to work with UI delegates, it's usually easier to just write your own delegate-less component from scratch. Hack #12 "Add Translucence to Menus" is an exception.)

It not just that, though. Even within the bounds of a particular hack, they don't tend to explore alternatives. Take hack #44 "Turn Dialogs into Frame-Anchored Sheets", for instance. There are two obvious ways to implement a sheet. One is to add a component to the glass pane. The other is to use a WindowListener to make one window follow another about (and stay on top of it). The book only discusses the glass pane method, not even mentioning that on Mac OS it looks totally wrong because the component doesn't have the shadow that a real window does. Use a real window, though, as I've done in SCM, and you find that the disadvantage is potential lag if the use does move a window around while it has a sheet showing, and problems coordinating the window's level in the desktop's z-order (which Java gives you only very primitive access to). Their sheet slides out all wrong, too. I didn't even bother implementing that. Apple keep making it quicker in recognition of the fact that it's not very useful and vaguely annoying.

Summary

Poor (or absent) technical reviewing seems to be a common problem amongst O'Reilly books. It's been a long time since I've seen one I'd unequivocally recommend. If you know about the glass pane, know about java.awt.Robot, know about overriding paintComponent to modify the Graphics2D or to paint into an image, you'll probably find this book boring. If you don't know about these things, but you do know what you're doing to a sufficient extent that you're not scared to look dodgy code in the eyes, and think you can see through some of the implementation details to the ideas, then you might like "Swing Hacks".

I strongly recommend that you download the source from O'Reilly's web site, and check out the overall quality of "hack" before you give them any of your hard-earned cash for the dead tree.

The book's not a total wash-out. I may already have better implementations of some of the hacks, but I'll be reconsidering the trade-offs where "Swing Hacks" offers an alternative implementation, and gratefully accepting a few tricks that I don't already have. My reaction to many of the hacks of "my mum could do better than that!" also means I'll be having fun putting my money where my mouth is.

Appendix

I know you're dying to know which hacks I found interesting. So far I've mainly talked about hacks that I didn't like for one reason or another. So here you go:

  • Hack #8 "Animate Transitions Between Tabs". I don't see the point of animating JTabbedPane transitions: it just seemed to make the UI slower to use. But if I had a similar class (call it JTransitionPanel, say) where transitions weren't initiated by the familiar tab interface, it might be useful. I'm thinking of something like flipping Apple's Dashboard widgets.
  • Hack #35 "Add Windows Resize Icons". Mac OS' grow box looks wrong in Java applications because it doesn't use transparency. Maybe I should be drawing my own?
  • Hack #37 "Save Window Settings". I already have an equivalent implementation of this, but this has reminded me that I should make a greater effort to keep saved state up to date. And a greater effort to code in a style amenable to it.
  • Hack #39 "Spin Open a Detail Pane". A good idea with an okay implementation, but it looks hideous. Spruced up, it might be interesting in places where I currently unconditionally show stack traces and the like.
  • Hack #56 "Create a Magnifying Glass". It's about time I got round to finishing my Java replacement for Apple's Pixie.
  • Hack #96 "Debug Components with a Custom Glass Pane". I once wrote something that aimed to be a Java equivalent of the Self core sampler. This reminds me that I'd like to write that again, and finish it this time.