2

I've a subclass of JTable that uses a custom table model (an implementation of AbstractTableModel) to manage data.

The problem occurs when I try to delete a row with the method deleteRow. The row in my table is replaced by a blank string but the row is not deleted.

Here is the code:

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();
  }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Luca
  • 1,704
  • 3
  • 29
  • 42
  • 3
    Can you edit your code example to provide a [SSCCE](http://sscce.org/) that we can execute and experiment with? – Duncan Jones Sep 08 '12 at 11:40
  • It's not so simple. I try do that! thanks – Luca Sep 08 '12 at 11:55
  • 1
    It's normally easier than you think. Just a little test JFrame with one table, a button and some populated date. It needn't be pretty. Sometimes you'll find the answer just be creating an SSCCE. – Duncan Jones Sep 08 '12 at 11:59
  • @DuncanJones trashgod posted the SSCCE code. Do you have any idea about the blank row in the table after delete. I need to understand that and then I will focus on sorting problem as pointed out by trashgod – Luca Sep 08 '12 at 20:32

1 Answers1

3

The sscce below illustrates one potential problem: The keys of a Map are not ordered, while the rows of a table are. In the approach shown, an array of keys must by updated with each change to the data. See also this related example. If required, you could extend Point to implement Comparable, as shown here for 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();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • If you go with a `Point` that implements `Comparable`, for [example](http://users.dickinson.edu/~braught/courses/cs132s02/classes/code/Point.src.html), you can use `TreeMap` instead of `HashMap`. – trashgod Sep 08 '12 at 16:01
  • Thanks for reply. I understand that you have emphasized the fact that with HashMap there may be problems with the order. In my case the order are ok but do you have any idea of the reason why I have a blank row in the table when I delete? Thanks! – Luca Sep 08 '12 at 20:25
  • Sorry, nothing stands out; you might look for a `null` key and check the returned values from `put()` and `remove()`, looking for unexpected results. – trashgod Sep 08 '12 at 23:49
  • @Luca: For reference, I added a simple delete button to my example. Range checking left as an exercise. :-) – trashgod Sep 09 '12 at 00:55
  • Many thanks. I will now working on it to change the implementation to preserve the oerder (I saw that DefaultTableModel use the Vector type to store the data, It' s good solution to use that in my custom table model?) and and that makes the elimination working. Thansk! – Luca Sep 10 '12 at 10:57
  • I have not explained well. For my custom table model I extends `AbstractTableModel` but to store data i saw that in the implementation of `DefaultTableModel` is used Vector. I tried an implementation with `ArrayList>` I don' t know if this is the best and easier solution. Thanks! – Luca Sep 10 '12 at 13:01
  • `Vector` is all but deprecated. I think `AbstractTableModel` is well worth the small extra effort to invoke `fireXxx()` as needed. I sometimes use `List`, where the fields of `Row` are mapped to columns. – trashgod Sep 10 '12 at 13:39
  • The `Row` object is an object you created to hold the value of the column of that row? thanks! – Luca Sep 10 '12 at 14:06
  • Right, `Row` holds the values of the columns of a particular row. – trashgod Sep 10 '12 at 16:11