Darrius
Darrius

Reputation: 177

Checking input validity BEFORE saving to JTable Cell

I would like to check the validity of user input every time they change a value on the JTable. The method I thought of is similar to this simplified sample code:

public static void main(String[] args) {
    JFrame main = new JFrame();

    JTable table = new JTable(6, 4);
    table.setSize(300, 300);


    table.getModel().addTableModelListener((TableModelEvent e) -> {
            Object s = e.getSource();
            TableModel d = (TableModel) s;                    
            if(!checkValid(d.getValueAt(e.getFirstRow(), e.getColumn())))
            {
                d.setValueAt(" - ", e.getFirstRow(), e.getColumn());                    
            }

    });

    main.add(table);
    main.setSize(300,300);
    main.setLocationRelativeTo(null);
    main.setVisible(true);
    main.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}

The code will check the input if a change in the table occurs and will revert back to "-" if the input is invalid.

However, an error will occur stating that Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError.

a.) Could someone explain the error and how to solve the issue?

b.) Or is there a better way of implementing a listener that checks the user input BEFORE exiting editing mode or saving the table?

EDIT: I have tried implementing the CellEditorListener like the sample below:

table.getCellEditor().addCellEditorListener(new CellEditorListener() {
    public void editingStopped(ChangeEvent e)
    {

    }
    public void editingCanceled(ChangeEvent e)
    {

    }
});

This in turn prompted an error Exception in thread "main" java.lang.NullPointerException. There isn't that much of documentation on CellEditorListener and didn't quite understood on how it works and how to use it.

Upvotes: 1

Views: 183

Answers (1)

gthanop
gthanop

Reputation: 3366

According to the corresponding section of the corresponding Java tutorials, you can override stopCellEditing of DefaultCellEditor to return false if the editor should not lose focus or true otherwise. Which means we can use it to check user input first and then, according to the user's input, return false if he/she enters invalid text (or true if he/she enters valid one).

In the following example code I'm using a JTextField, which lets the users type whatever they want and then checks the user's input in stopCellEditing to be non-empty (as defined by my static checkValid method, but you can obviously alter it according to your needs):

import java.awt.Toolkit;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;

public class Main {
    public static boolean checkValid(final String text) {
        return text != null && !text.trim().isEmpty(); //Your checks here...
    }

    public static class MyCellEditor extends DefaultCellEditor {
        public MyCellEditor() {
            super(new JTextField());
        }

        @Override
        public boolean stopCellEditing() {
            final JTextField field = (JTextField) getComponent();
            if (checkValid(field.getText())) {
                //field.setBackground(Color.WHITE);
                return super.stopCellEditing(); //Fires 'editing stopped' event and returns true.
            }
            Toolkit.getDefaultToolkit().beep();
            //field.setBackground(Color.ORANGE.darker());
            JOptionPane.showMessageDialog(field, "You must enter a non-empty value!", "Oups!", JOptionPane.ERROR_MESSAGE);
            return false;
        }
    }

    public static void main(final String[] args) {
        final JTable table = new JTable(new DefaultTableModel(10, 10));
        table.setDefaultEditor(Object.class, new MyCellEditor());

        final JFrame frame = new JFrame("JTable DefaultEditor");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(table);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

I use DefaultTableModel for easy initialization of the table. It also returns that each cell in the table is editable (we obviously need at least one cell to be editable, in order to check the validity of the program). Every cell starts initially empty, but the cell editor won't let you leave it empty, if you start an editing event.

An alternative solution could be to add an InputVerifier in the JTextField of the editor, but this would be a bit more tricky as I tested it, so I would rather not post it here in favor of the better above solution (and also suggested by the Java tutorial).

Upvotes: 1

Related Questions