JTable Input Verifier

前端 未结 3 540
一整个雨季
一整个雨季 2021-02-09 18:18

I am trying to create a simple Input Verifier for a JTable. I ended up with overriding the method: editingStopped(). The problem is that the event does not include informations

相关标签:
3条回答
  • 2021-02-09 18:34

    hmm, there might be a simpler solution to this. Please try this, it worked for me. The key is to remember last selected item, and then perform validation on the current item. If input is wrong, you can roll back to the last selected item, and notify user about that. Roll back is performed using EventQueue.invokeLater(...), therefore avoiding recursive call to the listeners.

    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;
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-09 18:45

    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

    0 讨论(0)
  • 2021-02-09 18:51

    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()));
    
    0 讨论(0)
提交回复
热议问题