Удалить строку из JTable с пользовательской моделью таблицы

У меня есть подкласс JTable, который использует пользовательскую табличную модель (реализация AbstractTableModel) для управления данными.

Проблема возникает, когда я пытаюсь удалить строку методом deleteRow. Строка в моей таблице заменяется пустой строкой, но строка не удаляется.

Вот код:

public class LiveSearchTableModel extends AbstractTableModel 
{

  private List<String> columnNames = new ArrayList<String>();
  private Map<Point, Object> displayData = new HashMap<Point, Object>();
  private Map<Point, Object> originalData = new HashMap<Point, Object>();

  public LiveSearchTableModel(List<String> columnNames, 
      Map<Point, Object> tableData) 
  {
    this.columnNames = columnNames;
    this.displayData = tableData;
    this.originalData.putAll(tableData); 
  }

  @Override
  public int getColumnCount() {
    return columnNames.size();
  }

  @Override
  public int getRowCount() {
    return displayData.size() / columnNames.size();
  }

  @Override
  public Object getValueAt(int rowIndex, int columnIndex) {
    return displayData.get(new Point(rowIndex, columnIndex));
  }

  public void deleteRow (int row)
  {
    for (int cont = 0; cont < columnNames.size();cont++)
    {   
      displayData.remove(new Point (row,cont)); 
    }

    this.fireTableRowsDeleted(row, row);
  }

  @Override
  public void setValueAt(Object value, int rowIndex, int columnIndex) 
  {
    this.displayData.put(new Point(rowIndex, columnIndex), value);
    this.fireTableDataChanged();
  }
}

person Luca    schedule 08.09.2012    source источник
comment
Можете ли вы отредактировать свой пример кода, чтобы предоставить SSCCE, который мы можем выполнить и с которым можно поэкспериментировать?   -  person Duncan Jones    schedule 08.09.2012
comment
Это не так просто. Я пытаюсь сделать это! спасибо   -  person Luca    schedule 08.09.2012
comment
Обычно это проще, чем вы думаете. Просто небольшой тест JFrame с одной таблицей, кнопкой и датой заполнения. Это не должно быть красиво. Иногда вы найдете ответ, просто создав SSCCE.   -  person Duncan Jones    schedule 08.09.2012
comment
@DuncanJones Trashgod опубликовал код SSCCE. Есть ли у вас какие-либо идеи о пустой строке в таблице после удаления. Мне нужно понять это, а затем я сосредоточусь на проблеме сортировки, как указал трэшгод.   -  person Luca    schedule 09.09.2012


Ответы (1)


sscce ниже иллюстрирует одну потенциальную проблему: ключи Map не упорядочены, в то время как строки таблицы упорядочены. В показанном подходе массив ключей должен обновляться при каждом изменении данных. См. также этот связанный пример. При необходимости вы можете расширить Point для реализации Comparable, как показано здесь для Value.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

/**
* @see https://stackoverflow.com/q/12330167/230513
*/
public class TableModelTest extends JPanel {

    public TableModelTest() {
        super(new BorderLayout());
        final MyModel model = new MyModel();
        JTable table = new JTable(model);
        this.add(new JScrollPane(table));
        this.add(new JButton(new AbstractAction("Delete") {

            @Override
            public void actionPerformed(ActionEvent e) {
                model.remove(0);
            }
        }), BorderLayout.SOUTH);
    }

    public class MyModel extends AbstractTableModel {

        private List<String> names = new ArrayList<String>();
        private Map<Point, Object> data = new HashMap<Point, Object>();
        private Point[] keys;

        public MyModel() {
            this.names = Arrays.asList("Point", "Name");
            data.put(new Point(1, 1), "One");
            data.put(new Point(2, 2), "Two");
            data.put(new Point(3, 3), "Three");
            this.keys = data.keySet().toArray(new Point[data.size()]);
        }

        public void remove(int row) {
            data.remove(keys[row]);
            keys = data.keySet().toArray(new Point[data.size()]);
            this.fireTableRowsDeleted(row, row);
        }

        @Override
        public int getColumnCount() {
            return names.size();
        }

        @Override
        public String getColumnName(int col) {
            return names.get(col);
        }

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

        @Override
        public Object getValueAt(int row, int col) {
            if (col == 0) {
                return keys[row];
            } else {
                return data.get(keys[row]);
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("TableModelTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

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

            @Override
            public void run() {
                new TableModelTest().display();
            }
        });
    }
}
person trashgod    schedule 08.09.2012
comment
Если вы выберете Point, который реализует Comparable, для например, вы можете использовать TreeMap вместо HashMap. - person trashgod; 08.09.2012
comment
Спасибо за ответ. Я так понимаю, вы акцентировали внимание на том, что с HashMap могут быть проблемы с заказом. В моем случае порядок в порядке, но знаете ли вы, почему у меня есть пустая строка в таблице при удалении? Спасибо! - person Luca; 09.09.2012
comment
Извините, ничего не выделяется; вы можете искать ключ null и проверять возвращаемые значения из put() и remove() в поисках неожиданных результатов. - person trashgod; 09.09.2012
comment
@Luca: Для справки, я добавил в свой пример простую кнопку удаления. Проверка диапазона оставлена ​​в качестве упражнения. :-) - person trashgod; 09.09.2012
comment
Большое спасибо. Теперь я буду работать над этим, чтобы изменить реализацию, чтобы сохранить oerder (я видел, что DefaultTableModel использует тип Vector для хранения данных, это хорошее решение для использования этого в моей пользовательской модели таблицы?) и это делает устранение работающим . Спасибо! - person Luca; 10.09.2012
comment
Я предпочитаю гибкость AbstractTableModel, но DefaultTableModel, безусловно, удобен. Когда вы будете готовы, вы можете принять этот ответ, щелкнув пустая галочка слева. - person trashgod; 10.09.2012
comment
Я плохо объяснил. Для моей пользовательской модели таблицы я расширяю AbstractTableModel, но для хранения данных я видел, что в реализации DefaultTableModel используется Vector. Я попробовал реализацию с ArrayList<ArrayList<Obecjt>>. Я не знаю, лучшее ли это и более простое решение. Спасибо! - person Luca; 10.09.2012
comment
Vector почти устарел. Я думаю, что AbstractTableModel стоит небольших дополнительных усилий по вызову fireXxx() по мере необходимости. Иногда я использую List<Row>, где поля Row сопоставляются со столбцами. - person trashgod; 10.09.2012
comment
Объект Row — это объект, который вы создали для хранения значения столбца этой строки? Спасибо! - person Luca; 10.09.2012
comment
Правильно, Row содержит значения столбцов определенной строки. - person trashgod; 10.09.2012