Как уведомить TableCellEditor о том, что строка таблицы удалена? - PullRequest
3 голосов
/ 10 января 2012

Я пытаюсь реализовать TableCellEditor, который содержит несколько полей и кнопку удаления. Работает хорошо, но при удалении строки содержимое в удаленной ячейке (отображается с помощью TableCellEditor) не обновлено.

Я пытался вызвать и fireTableRowsDeleted(row, row), и fireTableDataChanged() в модели, когда строка удалена, но, похоже, не уведомляет TableCellEditor. Это работает, когда я выбираю другую строку, и индекс строки снова отображается с помощью TableCellRenderer.

Любые предложения о том, как уведомить TableCellEditor об удалении?

  1. Нажата кнопка удаления

    enter image description here

  2. Строка удалена, но содержимое CellEditor не обновлено

    enter image description here

  3. Обновление содержимого строки при повторном использовании CellRenderer.

    enter image description here

Вот код:

public class StringTableDemo extends JFrame {

    public StringTableDemo() {

        final StringTableModel model = new StringTableModel();
        model.addRow("Jonas");
        model.addRow("Hello");
        model.addRow("World");

        RendererAndEditor rendererAndEditor = new RendererAndEditor(model);

        JTable table = new JTable(model);
        table.setDefaultRenderer(Record.class, rendererAndEditor);
        table.setDefaultEditor(Record.class, rendererAndEditor);

        add(new JScrollPane(table), BorderLayout.CENTER);
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    class Record {
        String string;
        boolean isDeleted;
    }

    class StringTableModel extends AbstractTableModel {

        private final List<Record> data = new ArrayList<Record>();

        @Override
        public int getColumnCount() {
            return 1;
        }

        @Override
        public int getRowCount() {
            return data.size();
        }

        @Override
        public Object getValueAt(int row, int column) {
            return data.get(row);
        }

        @Override
        public Class<?> getColumnClass(int column) {
            return Record.class;
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return true;
        }

        @Override
        public void setValueAt(Object aValue, int row, int column) {
            if(aValue instanceof Record) {
                Record r = (Record)aValue;
                if(!r.isDeleted) {
                    data.set(row, r);
                    fireTableRowsUpdated(row, column);
                }
            } else throw new IllegalStateException("aValue is not a Record");
        }

        public void addRow(String s) {
            Record r = new Record();
            r.string = s;
            r.isDeleted = false;
            data.add(r);
            fireTableRowsInserted(data.size()-1, data.size()-1);
        }

        public void removeRow(int row) {
            data.remove(row);
            //fireTableRowsDeleted(row, row);
            fireTableDataChanged();

            System.out.println("row " + row + " deleted");
        }

    }

    class CellPanel extends JPanel {
        private final Action removeAction = new AbstractAction("x") {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                model.removeRow(index);
                isDeleted = true;
            }

        };
        private final JButton removeBtn = new JButton(removeAction);
        private final JTextField field = new JTextField();
        private final StringTableModel model;
        private int index;
        private boolean isDeleted = false;
        public CellPanel(StringTableModel model) {
            super(new BorderLayout());
            this.model = model;
            add(field, BorderLayout.CENTER);
            add(removeBtn, BorderLayout.EAST);
        }

        public Record getRecord() {
            Record r = new Record();
            r.string = field.getText();
            r.isDeleted = isDeleted;
            return r;
        }

        public void setRecord(Record r, int index) {
            field.setText(r.string);
            this.index = index;
        }
    }

    class RendererAndEditor extends AbstractCellEditor implements
     TableCellEditor, TableCellRenderer {

        private final CellPanel renderer;
        private final CellPanel editor;

        public RendererAndEditor(StringTableModel model) {
            renderer = new CellPanel(model);
            editor = new CellPanel(model);
        }

        @Override
        public Object getCellEditorValue() {
            return editor.getRecord();
        }

        @Override
        public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, 
                       int row, int column) {

            renderer.setRecord((Record)value, row);
            return renderer;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, 
                Object value, boolean isSelected, int row, int column) {
            editor.setRecord((Record)value, row);
            return editor;
        }

    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new StringTableDemo();
            }

        });
    }
}

1 Ответ

4 голосов
/ 10 января 2012

Это потому, что ваш CellEditor не замечает, что должен прекратить редактирование ячейки, когда вы нажимаете на кнопку удаления.

Простым решением было бы добавить еще ActionListener к вашему CellEditor и звонить stopCellEditing() каждый раз, когда вы нажимаете на него. Это должно работать:

public RendererAndEditor( StringTableModel model )
{
  renderer = new CellPanel( model );
  editor = new CellPanel( model );

  editor.getRemoveBtn().addActionListener( new ActionListener()
  {
    @Override
    public void actionPerformed( ActionEvent e )
    {
      stopCellEditing();
    }
  });
}
...