GUI programming is going to kill me

I don’t care what sort of GUI I’m programming, it seems that I spend a good 90% of my time figuring out what combination of things I’m doing is causing the program not to act like it should. Today is a case in point.

In the Java program I’m currently working on, I wrote a pretty simple dialog to allow you to create or edit “film blocks”, which represent a movie. The dialog has space for the title, rating, genre, and run duration, and then “Save” and “Cancel” buttons. It took me a few hours to knock off.

First time the testers saw it, they said “Make it so that the save button isn’t active if the title is empty or the run duration isn’t set right. Fine, I used a FocusListener on both of those fields and when one or the other lost focus I verify the fields and enable or disable the Save button accordingly. Didn’t take long to do. It worked perfectly for me.

The next time the testers saw it, they didn’t like it. You see, whereas I use the tab key to navigate between fields, they use the mouse, so after they type the run duration in, the Save button isn’t yet active because they haven’t actually left the duration field so my FocusListener hasn’t been invoked. So I had to put on a DocumentListener instead, and check after every document change.

Oh, and while I was at it, they wanted colons between the hour and minute and second fields, and they didn’t want to type them. So ok, I converted the duration from a JTextField to a JFormattedTextField. I tested this, and it seemed to work ok.

But I soon got another bug report – now after entering the duration, they have to click the save button twice. And I tested it, and sure enough, it seems that there is something about that DocumentListener that’s eating the first click – the button’s ActionListener never gets called! So I’ve spent the last couple of hours (longer than I spent writing the first iteration of the dialog) trying to figure out what’s making that click disappear. Of course, if you TAB off the duration, or click in another field first, the click goes to the save button just fine. One of the weird quirks: when I click on the save button, the DocumentListener removeUpdate gets called first, with nothing left in the document, and then an insertUpdate gets called with the entire contents.