# Der Anfänger und das AbstractTableModel



## dat_vin (11. Sep 2014)

Heyho 

Ich muss ehrlich sagen das ich in Java jetzt fast neu einsteige und nur Programmiergrundkenntnisse habe.
Deswegen nehmt es bitte nicht so hart und seid gnädig 

*Zu meinem Problem:*
Ich habe ein AbstractTableModel mit einer JTable, die mit einer Datenbank(MySQL) verbunden ist. Jetzt möchte ich über einen JButton in die Tabelle schreiben, aber mein Problem besteht darin das die JTable sich nicht aktuallisiert.

*Meine Frage:*
Wie realisiere ich das? und wie würde der Code genau aussehen.

Hier der Code:

```
package mappe;

import daten.Fahrer;
import daten.Manager;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class FahrerTableModel extends AbstractTableModel {

    Manager Man = new Manager();
    List<Fahrer> fahrerliste = Man.getAlleFahrer();

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

    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Fahrer f = fahrerliste.get(rowIndex);
        switch (columnIndex) {
            case 0:
                return f.getFahrerId();
            case 1:
                return f.getFahrerVn();
            case 2:
                return f.getFahrerNn();
            default:
                return null;
        }
    }
}
```
Code vom Manager:

```
package daten;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Manager {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("FahrtverwaltungPU");
    EntityManager em = emf.createEntityManager();
    
    
    
    public List<Fahrer> getAlleFahrer(){
        List<Fahrer> fahrerliste = new ArrayList<Fahrer>();
        fahrerliste = em.createNamedQuery("Fahrer.findAll").getResultList();
        
        return fahrerliste;
    }
    
    public Fahrer setNewFahrer(String vorname, String nachname){
        Fahrer f = new Fahrer();
        f.setFahrerVn(vorname);
        f.setFahrerNn(nachname);
        
        em.getTransaction().begin();
        em.persist(f);
        em.getTransaction().commit();
        return f;
    }

}
```

Für jede Hilfe wäre ich sehr dankbar und genaue Erläuterungen sind gerne gesehen^^ 

MfG
Nils


----------



## kaoZ (11. Sep 2014)

> Jetzt möchte ich über einen JButton in die Tabelle schreiben, aber mein Problem besteht darin das die JTable sich nicht aktuallisiert.



Das liegt daran das du entweder der JTable das Modell neu setzen musst damit diese sich aktualisiert. oder du nutzt das Observer pattern und arbeitest mit notify(); und informierst quasi den View das das darunter liegende model sich geändert hat und der View sich aktualisieren soll.


----------



## dat_vin (12. Sep 2014)

kaoZ hat gesagt.:


> Das liegt daran das du entweder der JTable das Modell neu setzen musst damit diese sich aktualisiert.



Hatte daran gedacht beim Button (jButtonNeuFahrerActionPerformed) mit fireTableDataChanged() zu arbeiten aber es funktioniert einfach nicht....

So sieht es dann bei mir aus:

```
private void jButtonNeuFahrerActionPerformed(java.awt.event.ActionEvent evt) {                                                 
        Man.setNewFahrer(jTextFieldFahrerVorname.getText(), jTextFieldFahrerNachname.getText());
        ftm.fireTableDataChanged();
    }
```


----------



## Harry Kane (12. Sep 2014)

Die Fahrerliste aus deinem TableModel ist noch unverändert. Dein TableModel muss eine neue Fahrerliste aus dem Manager anfordern und dann seinerseits mit fireTableDataChanged() ihre Observer (wie z. B. die JTable) darüber informieren, daß sich ihr Inhalt geändert hat.
Stellt sich nur die Frage, wie das TableModel wissen kann, daß es eine neue Fahrerliste anfordern muss. Hierzu würde ich dem TableModel eine Methode refresh() verpassen, die du aufrufen kannst, nachdem du einen neuen Fahrer angelegt hast.


----------



## kaoZ (12. Sep 2014)

Was genau funktioniert denn nicht ? zeigt er dir die neu hinzugefügten Daten nicht in der Tabelle an ?

Vielleicht hilft dir das hier weiter wenn dem so ist:


```
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;



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

	int row;
	int col;
	Object[][] data;
	
	public TableModel(int r, int c){
		data = new Object[row = r][col = c];
	}
	
	@Override
	public int getRowCount(){
		return row;
	}

	@Override
	public int getColumnCount(){
		return col;
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex){
		if(rowIndex > row || columnIndex > col) {
			throw new ArrayIndexOutOfBoundsException();
		}
		return data[rowIndex][columnIndex];
	}
	
	public void addString(String s, int r, int c){
		data[r][c] = s;
		fireTableDataChanged(); // <----
	}

	public static void main(String[] args){
		TableModel model = new TableModel(5, 5);
		
		JFrame f = new JFrame();
		f.setDefaultCloseOperation(2);
		f.setSize(300,300);
		
		JPanel panel = new JPanel();
		panel.add(new JTable(model));
		
		f.add(BorderLayout.CENTER, panel);
		
		JButton btn = new JButton("add");
		btn.addActionListener(new ActionListener(){

			Random rdm;
			
			@Override
			public void actionPerformed(ActionEvent e){
				
				
				rdm = new Random();
				
				int row = rdm.nextInt(model.getRowCount() - 1);
				int col = rdm.nextInt(model.getColumnCount() - 1);
				
				System.out.println(row + " " + col);
				
				model.addString("test", row, col);
			}
			
		});
		f.add(BorderLayout.PAGE_END, btn);
		
		f.setLocationRelativeTo(null);
		f.setVisible(true);
	}
}
```

Wenn du daten am model änderst und fireTableDataChanged aufrufst, werden alle Listener darüber informiert, ebenso auch der Renderer der für die Darstellung der JTable zuständig ist, dies veranlasst ein neuzeichnen der bestimmten abschnitte, und oder der ganzen tabelle.

zudem stimme ich Harry zu , dein Modell muss wissen das du einen neuen Fahrere angelegt hast, sonst können sich daraufhin auch dessen Observer nicht aktualisieren.


----------



## dat_vin (12. Sep 2014)

Ja die JTable aktualisiert sich nicht, der Datensatz ist aber in der DB.

Habe jetzt eine neue Methode in der Klasse FahrerTableModel angelegt:

```
public void setValueAt(){
        Man.getAlleFahrer();
        fireTableDataChanged();       
    }
```

und in der Hauptklasse unter dem Button diese aufgerufen um die Observer zu informieren:

```
private void jButtonNeuFahrerActionPerformed(java.awt.event.ActionEvent evt) {                                                 
        Man.setNewFahrer(jTextFieldFahrerVorname.getText(), jTextFieldFahrerNachname.getText());
        FahrerTableModel ftm = new FahrerTableModel();
        ftm.setValueAt();
        
        
    }
```

Leider weiß ich nicht wie das refresh() aussehen muss.


----------



## kaoZ (12. Sep 2014)

Naja bei der Refresh methode musst du die Aktuellen Daten aus deiner Datenbank nachladen und dann dem Model bekannt machen, das modell hat ja sonst keine Kenntnis davon das sich daten in deiner DB geändert haben.


----------



## dat_vin (12. Sep 2014)

Hab nochmal das ganze Projekt angehangen:
https://www.dropbox.com/s/505gyu29ccrn923/Fahrtverwaltung.zip?dl=0


----------



## dat_vin (12. Sep 2014)

Oh man...


```
private void jButtonNeuFahrerActionPerformed(java.awt.event.ActionEvent evt) {                                                 
        Man.setNewFahrer(jTextFieldFahrerVorname.getText(), jTextFieldFahrerNachname.getText());
        FahrerTableModel ftm = new FahrerTableModel();
        jTableFahrerliste.setModel(ftm);
    }
```

Nach kopfzerbrechenden Stunden bin ich auf den Befehl setModel() gestoßen....

Ich danke euch trotzdem für die Hilfsbereitschaft und das ihr euch wirklich euren Kopf darüber zerbrochen habt


----------



## kaoZ (12. Sep 2014)

setModel ist genau das was ich schon ansprach, auch wenn ich mich ungern selbst zitiere : 



> Das liegt daran das du entweder der JTable das Modell neu setzen musst



dies verfolgt allerdings nicht den ansatz des Observer patterns über fireTableDatachanged, sondern du zwingst hier die JTable dazu mit einem Neu eingelesenen Model zu arbeiten 

Es ist der einfachere weg , das ist wohl wahr, aber es funktioniert auch über fireTableDatachanged()


----------



## dat_vin (12. Sep 2014)

wozu schwer machen wenn es auch einfach geht?^^
Ich kenne doch die ganzen Möglichkeiten in Java noch nicht etwas umzusetzen, einfach befehl genau hinschreiben hätte zum direkten Erfolg geführt


----------



## Harry Kane (12. Sep 2014)

Man sollte es sich angewöhnen, auf das unnötige Erzeugen von Objekten zu verzichten. Ich würde sehr dazu raten, das alte TableModel beizubehalten und ihm nur einen neuen Inhalt zu geben.
Dein vorhin gezeigter Ansatz mit der setValueAt-Methode hat zwei Nachteile:
1. Der Name der Methode. Sie liest sich so ähnlich wie eine Methode aus dem TableModel interface. Warum nicht einfach refresh()?
2. Die Logik: Du rufst in deiner methode zwar Man.getAlleFahrer() auf, verwendest den Rückgabewert der Methode aber gar nicht.

Hier der Inhalt eine refresh()-Methode von deinem TableModel:

```
public void refresh(){
    fahrerliste = Man.getAlleFahrer();
    fireTableDataChanged(); 
}
```


----------



## kaoZ (12. Sep 2014)

Mal abgesehen davon das diese Forum genau nicht dafür gedacht ist Stumpf Lösungen vorzugeben,  hätten wir dir keinen gefallen damit getan, denn der Lerneffekt wäre gleich null gewesen,  das ganze sieht jetzt etwas anders aus da du auch mal einen Blick hinter die Kulissen geworfen hast,  ich finde sowas wichtig anstatt sich immer nur auf "it's magic" zu berufen und keinen Schimmer zu haben was im Hintergrund passiert und wie es passiert  
Zumindest weißt du nun das immer mehrere Wege gibt sein Ziel zu erreichen 

Außerdem ist ein Satz wie "du musst entweder das Model neu setzen. .."

Schon quasi der verweis auf die einfachste / schnellste Lösung gewesen xD

Was natürlich nicht heißt das es der schönste und oder innovativste Weg ist.


----------

