Monday, November 27, 2006

Waiting and Blocking Input

Those pesky users are always trying to submit forms more than once, or creating new files willy nilly while they're waiting for feedback.

This article addresses two strategies for avoiding Impatient User Syndrome. First, provide some feedback to show that the program is busy, and second, don't allow any additional input.

Now, Java provides a JProgressBar, which you can throw up in a Dialog, but those aren't always appropriate. Sure if you want to block all application input (or in the case of Java 1.6, all frame input), that'll work, and you can always disable one component at a time. But suppose, for instance, that you've got a single frame, with a couple of different sections or docked panels. If their operation is independent of one another, you certainly don't want to block them all with a dialog.

The following demo shows how to block input on individual components, groups of components, or an entire frame, as well as providing "busy" feedback. The class WaitIndicator installs a component in the JLayeredPane above the target component, which prevents any mouse input from reaching the target component, and displays an hourglass cursor over the target component. It also installs a key event handler to ensure that no key events reach the target component.

The WaitIndicator also provides a paint method, which you can use to provide whatever visual feedback is appropriate to your program. The default implementation fades to the target component's background color. The demo itself uses a SpinningDialWaitIndicator, which paints an Apple-like spinner (which you can also see in the animated icon demo applet a few entries back).


Tree (and tree table) with checkboxes

When the user needs to select a non-trivial number of items from a hierarchy, normal tree item selection is too prone to losing the selection through mistaken clicks. The standard solution to provide a more robust selection method is to include check boxes next to each selectable item in the tree.

Hat tip to some previous online implementations (each has a different implementation):

Bare bones

With a TreeCellEditor

More recent variations

After a couple of iterations of checkbox trees (and tree tables), I rolled this up into a standalone TreeCellRenderer so that it can be applied more easily to any tree-oriented component. This implementation also properly handles rollover effects on the checkbox, which is lacking in the above implementations (most visible under w32; Java's Metal LAF has no checkbox rollover effects).

The checkbox painting is handled by using a real checkbox and painting its contents into an icon. The state of the checkbox is set just prior to painting to ensure the proper rollover state. The original cell renderer's icon is replaced with a composite icon of the original plus the checkbox (hit ^-shift-O to switch component orientation).

The renderer provides the current checked selection as an array of TreePath or an array of int representing the rows.

I also applied this to my own tree table implementation (similar to SwingX JXTreeTable) by just overriding a few protected methods which translate mouse coordinates into rows/paths.