Friday, June 23, 2006

Skipping read-only text components in Swing with TAB

After a superficial web search, I did not turn up a simple way (read cut and paste) to TAB over read-only components while navigating a container in Swing. JComboBox, JTextComponent and JTree all have an isEditable/setEditable(boolean) pair, however it has different meaning for each of them.

The case I am interested in JTextComponent. For text components, uneditable is equivalent to read-only: you can select the text from the component but cannot change it. The alternative is to disable the component, but then the text is not selectable for copying.

So, given a uneditable text component, what happens when I traverse through a form with the TAB key? Unfortunately, the JDK by default will move the focus (the caret) into the read-only text field even though you cannot type anything. Fixing the form to skip over read-only text fields is straight-forward but not directly documented:

public static void skipReadOnlyTextComponents(
        final Container container) {
    // Without this, JDK ignores policy
    container.setFocusCycleRoot(true);
    container.setFocusTraversalPolicy(new MyPolicy());
}

class MyPolicy extends LayoutFocusTraversalPolicy {
    @Override
    protected boolean accept(final Component c) {
        return !isReadOnly(c) && super.accept(c);
    }

    private static boolean isReadOnly(
            final Component c) {
        if (c instanceof JTextComponent)
            return !((JTextComponent) c).isEditable();

        return false;
    }
}

In broader use, it is worthwhile to make an Editable interface for isEditable/setEditable and add that to the instanceof tests in isReadOnly.

No comments: