Вопрос по swing, verification, verify, jtable, input – хм, могло бы быть более простое решение этого. Пожалуйста, попробуйте это, у меня получилось. Ключ заключается в том, чтобы запомнить последний выбранный элемент, а затем выполнить проверку текущего элемента. Если ввод неправильный, вы можете вернуться к последнему выбранному элементу и уведомить об этом пользователя. Откат выполняется с помощью EventQueue.invokeLater (...), поэтому избегая рекурсивного вызова слушателей.

6

аюсь создать простой Input Verifier для JTable. Я закончил с переопределением метода: editStopped (). Проблема состоит в том, что событие не включает в себя информацию о ячейке, которая была обновлена.

Это мой "псевдокод":

  If (user finished editing a cell)  {
     Check if cell`s value is "1" or "0" or "-"  (Karnaugh-Veitch)
     If (check = false)
        setValue (cell, "");
   }

Первое, что я попробовал, было здесь:

table.getModel().addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                inputVerify (e.getColumn(), e.getFirstRow());
            }
});

    public void inputVerify (int column, int row) {
        boolean verified = true;
        String field = table.getValueAt(row, column).toString();

        if (field != null && field.length() == 1) {
            if ( !(field.charAt(0) == '0' || field.charAt(0) == '1' || field.charAt(0) == '-' ))
                verified = false;
        }
        else {
            verified = false;
        }

        if (!verified) {
            table.getModel().setValueAt("", row, column);
            java.awt.Toolkit.getDefaultToolkit().beep();
        }

        System.out.println ("Column = " + column + " Row = " + row + " Value = " + table.getValueAt(row, column) +" Verified = "+verified);
    }

Но это заканчивается исключением: StackOverflow. Я предполагаю, что проблема в том, что: setValueAt (..) запускает другое событие tableChanged () и генерируется бесконечный цикл.

Теперь я попробовал это здесь:

    table.getDefaultEditor(Object.class).addCellEditorListener(new CellEditorListener() {

        // called when editing stops
        public void editingStopped(ChangeEvent e) {

            // print out the value in the TableCellEditor
            System.out.println(((CellEditor) e.getSource()).getCellEditorValue().toString());

        }

        public void editingCanceled(ChangeEvent e) {
            // whatever
        }
    });

Но, как вы видите, я могу просто получить новое значение ячейки, а не «координаты». Мне нужно вызвать: setValueAt (..) метод, но я не знаю, как получить координаты ячейки.

Или есть более простой способ создать входной верификатор ??

С наилучшими пожеланиями Иоаннис К.

нет, вы не хотите вызывать setValueAt, поэтому вам не нужны координаты :-) kleopatra

Ваш Ответ

3   ответа
12

проверка ввода при редактировании JTable не поддерживается. Пара комментариев

tableChanged в TableModelListener не является хорошим местом для выполнения проверки, в тот момент, когда изменение уже произошло (модель уведомляет своих слушателей об этом)как следствие, какой бы метод проверки (проверки) вы ни выбрали, никогда больше не обращайтесь к модели, вы попадете в бесконечный цикл (как вы видели)Предоставляемые приложением CellEditorListeners довольно бесполезны, потому что: а) нет никакой гарантии относительно последовательности уведомлений (JTable может уже обновлять модель или нет) б) жизненный цикл редактора не определен

После всех этих (неполных, к сожалению ;-) нет-нет, небольшая надежда: лучше всего реализовать пользовательский CellEditor, который выполняет проверку в stopCellCellEditing: если новое значение недопустимо, вернуть false и при необходимости предоставить визуальную ошибку Обратная связь. Посмотрите на JTable.GenericEditor, чтобы получить представление о том, как это можно сделать

Спасибо Клеопатре за это приятное и полезное разъяснение! Я понял, что верификатор ввода в моем случае очень неудобен. Не только для меня, но и для пользователей. Я решил добавить / изменить CellEditor. Наконец, я получил DefaultCellEditor и JComboBox в качестве параметра конструктора. Каждый раз, когда пользователь хочет отредактировать ячейку, появляется JComboBox с записями «0», «1» и «-». Таким образом, нет необходимости проверять правильность ввода, и это более удобно для пользователя :-) Ioannis K.
0

могло бы быть более простое решение этого. Пожалуйста, попробуйте это, у меня получилось. Ключ заключается в том, чтобы запомнить последний выбранный элемент, а затем выполнить проверку текущего элемента. Если ввод неправильный, вы можете вернуться к последнему выбранному элементу и уведомить об этом пользователя. Откат выполняется с помощью EventQueue.invokeLater (...), поэтому избегая рекурсивного вызова слушателей.

private final DefaultTableModel dtm = new DefaultTableModel();
private final JTable table = new JTable(dtm);
private final Object[] lastItem;
private final AtomicInteger lastIndex = new AtomicInteger(-1);
private final ItemValidator validator = new ItemValidator();


public YourConstructor() {

    lastItem = new Object[table.getColumnCount()];


    //store last value of selected table item in an array.
    table.addMouseListener(new MouseAdapter(){
        public void mouseClicked(MouseEvent evt){
            lastIndex.set(table.getSelectedRow());
            int row = lastIndex.get();
            for(int i=0;i<lastItem.length;i++){
                lastItem[i] = table.getValueAt(row, i);
            }
        }
    });

    //for input validation, and database update.
    dtm.addTableModelListener(new TableModelListener(){

        @Override
        public void tableChanged(TableModelEvent e) {
            switch(e.getType()){
            case TableModelEvent.INSERT:
                System.out.println("insert");
                break;
            case TableModelEvent.UPDATE:
                validateUpdate();
                break;
            case TableModelEvent.DELETE:
                System.out.println("delete");
                break;
            default:
                break;
            }
        }

    });
}

public void validateUpdate(){
    String item;
    for(int i=0;i<lastItem.length;i++)
    {
        item = (String)table.getValueAt(lastIndex.get(), i);
        if(i>1 && i<lastItem.length)//column range to be checked
        {
            if(!validator.hasNumericText(item))
            {
                final int col = i;
                final Object lastObject = lastItem[i];
                final int row = lastIndex.get();

                //the most important part, to avoid StackOverflow
                //by using EventQueue, you avoid looping around 
                //the TableModelListener.
                EventQueue.invokeLater(new Runnable(){
                    public void run(){
                        table.setValueAt(lastObject, row, col);
                    }
                });

                System.out.println("Error at " + i);
                break;
            }
        }
    }
}
4

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()));
спасибо :-) Просто немного остерегайтесь: строго говоря, ваша реализация проверки не совсем корректна, так как не имеет побочных эффектов. Хотя вам, вероятно, это сойдет с рук, поскольку побочным эффектом является установка только фона. kleopatra
@kleopatra: спасибо, это приятно знать. Dave

Похожие вопросы