Проверка правильности ввода перед сохранением в ячейку JTable - PullRequest
1 голос
/ 13 января 2020

Я хотел бы проверять достоверность ввода пользователя каждый раз, когда они меняют значение в JTable. Метод, о котором я подумал, похож на этот упрощенный пример кода:

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);
}

Код проверит ввод, если произойдет изменение в таблице, и вернется к «-», если ввод недействителен.

Однако произойдет ошибка, сообщающая, что Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError.

а.) Может кто-нибудь объяснить ошибку и как решить проблему?

b.) Или есть лучший способ реализации прослушивателя, который проверяет пользовательский ввод ДО выхода из режима редактирования или сохранения таблицы?

РЕДАКТИРОВАТЬ: я пытался реализовать CellEditorListener как пример ниже:

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

    }
    public void editingCanceled(ChangeEvent e)
    {

    }
});

Это в свою очередь вызвало ошибку Exception in thread "main" java.lang.NullPointerException. На CellEditorListener не так много документации, и он не совсем понял, как она работает и как ее использовать.

1 Ответ

1 голос
/ 14 января 2020

В соответствии с соответствующим разделом Java учебников , вы можете переопределить stopCellEditing из DefaultCellEditor, чтобы вернуть false, если редактор не должен терять фокус или true в противном случае. Это означает, что мы можем сначала использовать его для проверки ввода пользователя, а затем, в соответствии с вводом пользователя, вернуть false, если он вводит недопустимый текст (или true, если он вводит верный).

В следующем примере кода я использую JTextField, который позволяет пользователям вводить все, что они хотят, а затем проверяет, чтобы введенные пользователем данные в stopCellEditing были непустыми (как определено в моем стати c checkValid метод, но вы, очевидно, можете изменить его в соответствии с вашими потребностями):

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);
    }
}

Я использую DefaultTableModel для легкой инициализации таблицы. Он также возвращает, что каждая ячейка в таблице является редактируемой (нам, очевидно, требуется по крайней мере одна ячейка для редактирования, чтобы проверить правильность программы). Каждая ячейка изначально пуста, но редактор ячеек не позволит вам оставить ее пустой, если вы запускаете событие редактирования.

Альтернативным решением может быть добавление InputVerifier в JTextField редактора, но это было бы немного сложнее, так как я тестировал его, поэтому я бы не стал публиковать его здесь в пользу лучшего решения выше (а также предложенного в учебнике Java).

...