fireTableDataChanged -> IndexOutOfBoundsException

hesk

Erfahrenes Mitglied
Hallo!

Ich verzweifle gerade ein wenig.

Ich hab eine JTable mit einem eigenen Model welches von AbstractTableModel ableitet.
Wenn in der Table etwas gelöscht wird, dann wird in der DB(MySql) ein Flag gesetzt,
anschließend alle Daten neu geholt, und im Model die Daten gesetzt:

Java:
/**
     * Setzt die Daten neu
     * 
     * @param artikelList
     */
    public void setData(List<Artikel> data)
    {
      
        this.data.clear();
        this.data.addAll(data);
        this.fireTableDataChanged();
    }

Nun tritt manchmal, aber nicht immer, folgender Fehler auf:

Java:
java.lang.IndexOutOfBoundsException: Index: 1161, Size: 1161
	at java.util.LinkedList.checkElementIndex(Unknown Source)
	at java.util.LinkedList.get(Unknown Source)
	at xxx.xxx.objects.jTableFilterHeader.ArtikelTableModel.getValueAt(ArtikelTableModel.java:157)
	at javax.swing.JTable.getValueAt(Unknown Source)
	at javax.swing.JTable.prepareRenderer(Unknown Source)
	at javax.swing.plaf.synth.SynthTableUI.paintCell(Unknown Source)
	at javax.swing.plaf.synth.SynthTableUI.paintCells(Unknown Source)
	at javax.swing.plaf.synth.SynthTableUI.paint(Unknown Source)
	at javax.swing.plaf.synth.SynthTableUI.update(Unknown Source)
	at javax.swing.JComponent.paintComponent(Unknown Source)
	at javax.swing.JComponent.paint(Unknown Source)
	at javax.swing.JComponent.paintToOffscreen(Unknown Source)
	at javax.swing.BufferStrategyPaintManager.paint(Unknown Source)
	at javax.swing.RepaintManager.paint(Unknown Source)
	at javax.swing.JComponent._paintImmediately(Unknown Source)
	at javax.swing.JComponent.paintImmediately(Unknown Source)
	at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.access$700(Unknown Source)
	at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
	at java.awt.event.InvocationEvent.dispatch(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

Fällt jemanden etwas dazu ein?
 

schlagi123

Grünschnabel
Hallo Hesk,

ich habe es nicht ausprobiert, aber reicht es nicht einfach fireTableDataChanged() wegzulassen und die Tabelle zu repainten.

API:
Code:
void fireTableDataChanged()
          Notifies all listeners that all cell values in the table's rows may have changed.

Ich glaube das er alle Zeilen durchgeht die auch vorher da waren (also eine zu viel). Probiere es man mit einem fireTableRowsDeleted(index, index).

AbstractTableModel
 

hesk

Erfahrenes Mitglied
Hallo!

Soweit ich es verstanden habe:

fireTableDataChanged() alamiert alle Listener dass die Daten sich geändert haben.
Jetzt holen sich alle Listener die Daten neu.

Hierfür holen sie sich zuerst einmal die size:

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

Und irgendein Listener dürfte hier eines zu viel bekommen, und ich weiß nicht ganz warum.



Etwas zum Verständnis:

Alles was die GUI betrifft soll ja im EDT ausgeführt werden. Alles was länger dauert(Daten holen zb) in einem extra Thread.

Wenn in meinem Programm eine Zeile aus der Tabelle gelöscht wird, so wird ein Flag in MySql gesetzt und anschließend ein UpdateData ausgeführt:

Java:
private class UpdateData extends Task<Void, Void>
    {
        /**
         * Konstruktor
         */
        public UpdateData()
        {
            super(Application.getInstance());
        }

        @Override
        protected Void doInBackground() throws Exception
        {
            List<Artikel> data = mySqlManager.getAllArtikel();

            ((ArtikelTableModel)table.getModel()).setData(data);
            
            table.updateComboBoxes();
            table.updateFilter();
            
            return null;
        }
        
        @Override
        protected void finished()
        {
            super.finished();
            System.out.println("update finished");
            updateComponents();
        }
    }

updateComponents macht nichts anderes als ein paar CheckBoxes anhand der neuen Daten zu setzen.

In doBackground hole ich mir zuerst alle Daten neu und setzte sie dann im Model.

Kann es nun sein dass wegen der oben genannten Logik fireTableDataChanged() erst im finished()-Teil ausgeführt werden soll? Da dadurch ja die GUI verändert wird, und die finished()-Methode im EDT läuft?
 
Zuletzt bearbeitet von einem Moderator:

Fabio Hellmann

Erfahrenes Mitglied
Hi,
also rein aus Performancegründen würde ich auch eher die Methode fireTableRowsDeleted(int index, int index) aufrufen. So muss nicht die komplette (0-unendlich) neu geladen werden, sondern lediglich ein Listener/Row gelöscht werden. Das geht viel schneller.

Gruß

Fabio
 

hesk

Erfahrenes Mitglied
Nach der Logik dass alles was die GUI betrifft im EDT ausgeführt werden soll, hab ich die updateData-Methode nun folgendermaßen geändert:

Java:
private class UpdateData extends Task<Void, Void>
    {
        private List<Artikel> data;
        
        /**
         * Konstruktor
         */
        public UpdateData()
        {
            super(Application.getInstance());
            data = new ArrayList<Artikel>();
        }

        @Override
        protected Void doInBackground() throws Exception
        {
            data = mySqlManager.getAllArtikel();

            return null;
        }
        
        @Override
        protected void finished()
        {
            super.finished();
            
            ((ArtikelTableModel)table.getModel()).setData(data);
            
            table.updateComboBoxes();
            table.updateFilter();
            
            System.out.println("update finished");
            updateComponents();
        }
    }

Der Fehler tritt nun nicht mehr auf.

Kann mir jemand vielleicht eine Erklärung liefern:)?
 

hesk

Erfahrenes Mitglied
Hi,
also rein aus Performancegründen würde ich auch eher die Methode fireTableRowsDeleted(int index, int index) aufrufen. So muss nicht die komplette (0-unendlich) neu geladen werden, sondern lediglich ein Listener/Row gelöscht werden. Das geht viel schneller.

Gruß

Fabio


Das mag wohl stimmen. Aber da das Programm von mehreren Personen benutzt wird(mehrere PC's), schadet hier kein neuholen der gesamten Daten, weil dadurch auch gleich Änderungen von anderen geholt werden.
 
Zuletzt bearbeitet: