Hello,
I have the following problem with JTable: I'm using it to display and edit a list of objects. The objects may be edited via the cells in the JTable. More specifically I have an object ShapeTableModel that implements TableModel and extends ArrayList. I've overridden the add and remove methods to also signal any registered TableModelListeners (see the first code below). I've also implemented a removal Action (second bit of code below) which removes the selected elements of the JTable.
All this works fine except for the case where I am removing a ShapeHandler object that is also currently being edited in the JTable. The underlying ShapeHandler object in the TableModel will be removed, as well as the corresponding row in the table. The problem occurs when I now try to change the selection of the JTable. Before the valueChanged method of the ListSelectionListener is fired the JTable produces an IndexOutOfBounds exception because as far as I can make out it thinks it ought to finish the editing process. The edited object has been removed however causing the IOOBE. My question now is, how can I avoid this (if this is at all possible).
Kind Regards,
Lukas
public class ShapeTableModel extends ArrayList<ShapeHandler> implements TableModel, ShapeChangeListener {
private static Logger log = Logger.getLogger(ShapeTableModel.class.getName());
String[] headers = { "Type", "Mass", "Centre X", "Centre Y", "Radius/Rotation", "Width", "Height", "Fix" };
Class<?>[] classes = {String.class, Float.class, Float.class, Float.class, Float.class, Float.class, Float.class, Boolean.class};
/**
* Used to determine table dimensions
*/
public Object[] longValues = {"Circle",1000, 1000,1000,1000,1000,1000,false};
@Override
public Class<?> getColumnClass(int columnIndex) {
return classes[columnIndex];
}
@Override
public int getColumnCount() {
return headers.length;
}
@Override
public String getColumnName(int columnIndex) {
return headers[columnIndex];
}
@Override
public int getRowCount() {
return size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return get(rowIndex).getValueAt(columnIndex);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
//first column is not editable
if (columnIndex == 0) return false;
return true;
}
@Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
get(rowIndex).setValueAt(columnIndex, value);
}
@Override
public boolean add(ShapeHandler e) {
super.add(e);
e.addSCL(this);
TableModelEvent tme = new TableModelEvent(this);
signalListeners(tme);
return true;
}
@Override
public ShapeHandler remove(int index) {
ShapeHandler r = super.remove(index);
TableModelEvent tme = new TableModelEvent(this);
signalListeners(tme);
return r;
}
// -------Listener relevant code-----------------
Set<TableModelListener> listeners = new HashSet<TableModelListener>(1);
private void signalListeners(TableModelEvent e) {
for (TableModelListener l : listeners) {
l.tableChanged(e);
}
}
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
@Override
public void shapeChanged(Shape s) {
int i = indexOf(s);
TableModelEvent tme = new TableModelEvent(this, i);
signalListeners(tme);
}
}
JTable table = new JTable();
ShapeTableModel model;
...initialised in constructor
...
private class RemAction extends AbstractAction {
public RemAction() {
super("Remove");
}
@Override
public void actionPerformed(ActionEvent e) {
removeSelected();
}
}
...
public void removeSelected() {
int[] inds = table.getSelectedRows();
removeShapes(inds);
}
private void removeShapes(int[] indices) {
Arrays.sort(indices);
int mod = 0;
for (int i = 0; i < indices.length; i++) {
model.remove(indices[i] - mod);
mod++;
}
}
...