JTable Input Verifier - PullRequest
       3

JTable Input Verifier

6 голосов
/ 03 мая 2011

Я пытаюсь создать простой 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 (..), но я не знаю, как получить координаты ячейки.

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

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

Ответы [ 3 ]

12 голосов
/ 04 мая 2011

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

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

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

4 голосов
/ 12 апреля 2013

Что сработало для меня (наденьте шляпу клеопатре):

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()));
0 голосов
/ 16 июля 2016

хм, может быть, есть более простое решение для этого.Пожалуйста, попробуйте это, у меня получилось.Ключ заключается в том, чтобы запомнить последний выбранный элемент, а затем выполнить проверку текущего элемента.Если ввод неправильный, вы можете вернуться к последнему выбранному элементу и уведомить об этом пользователя.Откат выполняется с помощью 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;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...