Swing TableModel fireTableDataChanged führt zu IndexOutOfBoundsException

ergin

Mitglied
Hi,
ich habe ein Problem beim Zusammenspiel von den Klassen JTable, TableModel und TableRowSorter. In meiner Applikation verwende ich eine von JTable abgeleitete Klasse und eine vom DefaultTableModel. In meinem TableModel wird in der SetValueAt Methode eine Zeile gelöscht und ein fireTableDataChanged() aufgerufen. Das ganze endet mit einer IndexOutOfBoundsException oder ArrayIndexOutOfBoundsException Fehlermeldung. Nachdem dem Aufrufen von fireTableDataChanged wird die getRowCount Methode vom TableModel nicht aufgerufen. In der von JTable abgeleiteten Klasse wird ein TableRowSorter verwendet. Wenn ich den TableRowSorter aus dem Code entferne, funktioniert alles. Alternativ, wenn ich dem TableModel eine Referenz vom TableRowSorter übergebe und vor dem fireTableDataChanged() die Methode rowsDeleted vom TableRowSorter aufrufe funktioniert es auch. Hat jemand eine Idee?
 
Hätte ich gemacht, aber das ganze ist etwas aufwändiger und erfordert eine entsprechende DB.
Wenn du DB sagst, hoffe ich mal das du die DB nicht im Event Dispatcher Thread ansprichst.
Wenn du also (wie ich vermuten würde) mindestens 2 Threads hast (EDT und DB Thread), dann ist dir hoffentlich klar dass du dein Table Model nicht aus dem DB Thread aktualisieren kannst weil Swing nicht threadsicher ist.
Meine Glasskugel sagt das du das an mindestens einer Stelle nicht beachtet hast und daher threading issues hast.
 
Ich habe nur ein Thread.

Das TableModel sollte doch den TableRowSorter mitbenachrichtigen oder? Was mich wundert, dass die Methode getRowCount nach fireTableDataChanged nicht aufgerufen wird.
 
Abgesehen von der Frage nach den Threads klingt es schon nach strukturellem Murks, wenn man eine DB braucht, um ein GUI starten zu können. Kann man den DB-Teil nicht irgendwie rausschälen und stattdessen irgendwelche Dummy-Daten verwenden?
 
Table
Java:
import javax.swing.JTable;
import javax.swing.table.TableRowSorter;

@SuppressWarnings("serial")
public class DbTable extends JTable {
	private DbTableModel tableModel = new DbTableModel();

	private final TableRowSorter<DbTableModel> rowSorter = new TableRowSorter<DbTableModel>();

	/**
	 * @return the rowSorter
	 */
	public TableRowSorter<DbTableModel> getRowSorter() {
		return rowSorter;
	}


	/**
	 * Initialize table model and row sorter
	 */
	public void initTableModel() {
		tableModel.fillModel();
		setModel(tableModel);
	}

	public void setInitialSort() {
		rowSorter.setModel(tableModel);
		
		rowSorter.toggleSortOrder(0);

	}

	public void updateModel() {
		initTableModel();
		setInitialSort();
	}

}

TableModel
Java:
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

@SuppressWarnings("serial")
public class DbTableModel extends AbstractTableModel {

	private String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" };

	private Vector<Vector<Object>> rowVector = new Vector<Vector<Object>>();
	private Vector<Object> columnVector = new Vector<Object>();

	public DbTableModel() {
		super();
	}

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

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

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

	@Override
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		deleteEntry(rowIndex);
	}

	@Override
	public String getColumnName(int column) {
		return columnNames[column];
	}

	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return true;
	}

	@Override
	public Class<?> getColumnClass(int columnIndex) {
		return getValueAt(0, columnIndex).getClass();
	}

	public void fillModel() {
		columnVector = new Vector<Object>();
		columnVector.add("Max");
		columnVector.add("Mustermann");
		columnVector.add("Lernen");
		columnVector.add(new Integer(3));
		columnVector.add(new Boolean(true));
		rowVector.add(columnVector);

		columnVector = new Vector<Object>();
		columnVector.add("Peter");
		columnVector.add("Müller");
		columnVector.add("Badminton");
		columnVector.add(new Integer(5));
		columnVector.add(new Boolean(false));
		rowVector.add(columnVector);

		fireTableDataChanged();

	}

	public boolean deleteEntry(int index) {
		rowVector.remove(index);
		fireTableDataChanged();

		return true;
	}
}

BeispielAppl.
Java:
import javax.swing.JFrame;


public class TableTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		JFrame frame = new JFrame("Table Test");
		DbTable table = new DbTable();
		table.updateModel();
		frame.add(table);
		frame.setSize(400, 300);
		frame.pack();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);

	}

}

Wenn man die Zeile "rowSorter.toggleSortOrder(0);" auskommentiert oder die Methode "public TableRowSorter<DbTableModel> getRowSorter()" weglässt funktioniert es.
 
EDIT: Ja, das war dann wohl egal...

Das hilft zumindest etwas weiter... In setValueAt wird eine Zeile gelöscht - ist das Absicht? Das macht IMHO keinen Sinn ...
1. setValueAt(1,1) aufrufen (dabei die Zeile 1 löschen)
2. Den Event verarbeiten, der sagt, dass (1,1) sich geändert hat
-> (1,1) gibt's nicht mehr -> Crash

Falls das nur für das Beispiel war: Wie und wo und wann tritt den die Exception im echten Fall auf?
 
EDIT: Ja, das war dann wohl egal...

Das hilft zumindest etwas weiter... In setValueAt wird eine Zeile gelöscht - ist das Absicht? Das macht IMHO keinen Sinn ...
1. setValueAt(1,1) aufrufen (dabei die Zeile 1 löschen)
2. Den Event verarbeiten, der sagt, dass (1,1) sich geändert hat
-> (1,1) gibt's nicht mehr -> Crash

Falls das nur für das Beispiel war: Wie und wo und wann tritt den die Exception im echten Fall auf?

Anmerkung: Löschen von Tabelleneinträgen in der "setValueAt" Methode führt nicht zum Absturz.
 

Zurück
Oben