The simple answer is to create your own, based on something like AbstractTableModel
For example...
public abstract class AbstractGenericTableModel<R> extends AbstractTableModel {
protected ArrayList<R> rows;
protected List columnIdentifiers;
public AbstractGenericTableModel() {
this(0, 0);
}
public AbstractGenericTableModel(int rowCount, int columnCount) {
this(new ArrayList(columnCount), rowCount);
}
public AbstractGenericTableModel(List columnNames, int rowCount) {
setData(new ArrayList<>(rowCount), columnNames);
}
public AbstractGenericTableModel(List<R> data, List columnNames) {
setData(data, columnNames);
}
public List<R> getRowData() {
return rows;
}
private List nonNullVector(List v) {
return (v != null) ? v : new ArrayList();
}
public void setData(List<R> data, List columnIdentifiers) {
this.rows = new ArrayList<>(nonNullVector(data));
this.columnIdentifiers = nonNullVector(columnIdentifiers);
fireTableStructureChanged();
}
public void addRow(R rowData) {
insertRow(getRowCount(), rowData);
}
public void insertRow(int row, R rowData) {
rows.add(row, rowData);
fireTableRowsInserted(row, row);
}
/**
* Removes the row at <code>row</code> from the model. Notification of the row being removed will be sent to all the listeners.
*
* @param row the row index of the row to be removed
* @exception ArrayIndexOutOfBoundsException if the row was invalid
*/
public void removeRow(int row) {
rows.remove(row);
fireTableRowsDeleted(row, row);
}
public void setColumnIdentifiers(List columnIdentifiers) {
setData(rows, columnIdentifiers);
}
@Override
public int getRowCount() {
return rows.size();
}
@Override
public int getColumnCount() {
return columnIdentifiers.size();
}
@Override
public String getColumnName(int column) {
Object id = null;
// This test is to cover the case when
// getColumnCount has been subclassed by mistake ...
if (column < columnIdentifiers.size() && (column >= 0)) {
id = columnIdentifiers.get(column);
}
return (id == null) ? super.getColumnName(column)
: id.toString();
}
}
public class ArrayListTableModel extends AbstractGenericTableModel<ArrayList> {
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
List<ArrayList> rows = getRowData();
return rows.get(rowIndex).get(columnIndex);
}
}
This creates two classes, an "abstract generics" based model, which allows you to specify the physical data which backs a row and a ArrayListTableModel
which allows you to use a ArrayList
for the individual data.
What this assumes though, is each row has the same number of elements, but it makes no checks
I suggest you have a closer look at How to Use Tables for more details