JTable Input Verifier

First: input validation on JTable editing is not well supported. A couple of comments

  • tableChanged in a TableModelListener is not a good place to do validation, at that point in time the change already happened (the model notifies its listeners of the fact)
  • as a consequence, whatever validation (verify) method hook you choose, never-ever talk back to the model, you'll end up in an infinite loop (as you have seen)
  • application-provided CellEditorListeners are rather useless because a) there's no guarantee about sequence of notification (JTable might or not have already updated the model) b) the life-cylce of an editor is ill-defined

After all those (incomplete, unfortunately ;-) no-nos, a little hope: best bet is to implement a custom CellEditor which does the validation in stopCellCellEditing: if the new value isn't valid, return false and optionally provide a visual error feedback. Have a look at JTable.GenericEditor to get an idea of how that might be done


What worked for me (tip 'o the hat to kleopatra):

private class CellEditor extends DefaultCellEditor {

    InputVerifier verifier = null;

    public CellEditor(InputVerifier verifier) {
        super(new JTextField());
        this.verifier = verifier;

    }

    @Override
    public boolean stopCellEditing() {
        return verifier.verify(editorComponent) && super.stopCellEditing();
    }

}

// ...

private class PortVerifier extends InputVerifier {

    @Override
    public boolean verify(JComponent input) {
        boolean verified = false;
        String text = ((JTextField) input).getText();
        try {
            int port = Integer.valueOf(text);
            if ((0 < port) && (port <= 65535)) {
                input.setBackground(Color.WHITE);
                verified = true;
            } else {
                input.setBackground(Color.RED);
            }
        } catch (NumberFormatException e) {
            input.setBackground(Color.RED);
        }
        return verified;
    }
}

// ...

table.getColumn("Port").setCellEditor(new CellEditor(new PortVerifier()));