# JTable aktualisieren



## Kenan89 (7. Feb 2012)

Hallo, jetzt muss ich eine Frage bezüglich JTable ausgeben: Ich habe eine Tabelle und darunter Eingabefelder, um die Werte oben in der Tabelle zu updaten.

Die Daten werden eingetragen und auch beim neustart des Programms angezeigt. Aber ich will, dass man sie gleich sieht. Jetzt habe ich über eine Funktion fireTableDataChanged() gelesen und meinem TableModel hinzugefügt (tm.fireTableDataChanged())
Leider aktualisiert sich Tabelle nicht.

Danke für Antworten.


----------



## KrokoDiehl (7. Feb 2012)

Du musst in deinem TableModel nach einem setValueAt()  -bzw. nach jeder Änderung des Modells- selbst ein fireTableXXXX() aufrufen. Idealerweise kannst du vom AbstractTableModel erben, was dir diese Methoden bereits bereitstellt.


----------



## Kenan89 (7. Feb 2012)

Da liegt ein Missverständnis vor 
Ich habe die Daten in eine Tabelle in einer Datenbank eintragen lassen und sie in einer JTable ausgegeben

Sprich der Befehl setValueAt kommt bei mir gar nicht vor, sondern nur execute("update...")


----------



## SlaterB (7. Feb 2012)

du könntest Missverständnisse durch Code oder längere Beschreibungen als "Die Daten werden eingetragen" vermeiden,
WO werden sie eingetragen, nur in der DB oder auch im Model einer JTable?


----------



## Kenan89 (7. Feb 2012)

In der Datenbank sind sie auf jedenfall eingetragen, denn ich habe nachgesehen und nach dem Neustart sieht man die neuen Eingaben ja auch.

Es funktioniert folgendermaßen:

Die Tabelle wird einem TableModel zugewiesen.
Die Tabelle wird angezeigt.
Du gibst Daten in die Eingabefelder ein.
Klickst ein Button.
Obwohl nach dem statement.execute("update...)-Block fireTableDate... Event aufgerufen wird, wird die
Tabelle nicht neu gezeichnet(bzw. aktualisiert).
Erst nach einem Neustart des Programms sieht man die Veränderungen, weil da die Tabelle neu geladen wird.


----------



## SlaterB (7. Feb 2012)

fireTableData.. läßt nur in der JTable geänderte Daten des Models anzeigen,

die Frage ist jetzt ob das Model aktualisiert wird, das muss dein Code vorher schon selber leisten,
von alleine passiert da nix

du könntest entweder die neue Zeile einzeln einfügen oder auch generell alles durch den neuen Stand aus der DB ersetzen


----------



## Kenan89 (7. Feb 2012)

Okay danke


----------



## Kenan89 (7. Feb 2012)

Gleich die nächste Frage hinterher 

Ich habe eine Klasse die von JTable erbt. 
Jetzt möchte ich mit changeSelection erreichen, dass die Zelle markiert wird, die ich eingebe.

Das Problem ist, auf ein JTable lässt sich changeSelection anwenden, aber eine Klasse die zugleich ein JTable ist.. Da macht es Probleme, sprich er kann changeSelection nicht auf eine Klasse anwenden, die von JTable erbt.

Irgendwelche Ratschläge? Danke im voraus.


----------



## DanZ (7. Feb 2012)

Das muss funktionieren. changeSelection ist public in JTable, wenn deine Klasse von JTable erbt kannst du auf eine Instanz dieser Klasse definitiv auch changeSelection aufrufen. Das ist irgendein Problem mit deiner IDE oder das Vererben ist falsch oder so etwas in der Richtung. (Bzw. auf die Klasse kannst du changeSelection natürlich nicht anwenden, nur auf die Instanzen der Klasse, aber ich denke mal das meintest du auch)


----------



## Kenan89 (8. Feb 2012)

Hmm okay danke ich habe den Fehler erkannt.

Jetzt ein neues Problem. Ich muss die Datenbank aktualisieren und mit fireTableCanged klappt es nicht,denn meine Funktion läuft so ab:

Du schreibst etwas in ein Feld, drückst Hinzufügen und es wird in die Datenbank gespeichert. Aber davor hatte ich meine Tabelle bereits anzeigen lassen. Das heisst nach dem Hinzufügen muss wieder auf die Datenbank zugegriffen werden um alle Zeilen nochmal neu zu laden(momentan reicht das, später gehe ich in die Performance Phase und dann soll nur die neue Zeile nachgeladen werden).
Das Problem ist, wnn ich die Tabelle neu erstelle, erstellt sich direkt neben der alten Tabelle die neue Tabelle. Das heisst, die neu überschreibt nicht, sondern setzt sich nur neben die alte. 
Wie kann ich die alte Tabelle löschen und die neue an ihren Platz platzieren bzw. überschreiben?


----------



## Michael... (8. Feb 2012)

Kenan89 hat gesagt.:


> Das Problem ist, wnn ich die Tabelle neu erstelle, erstellt sich direkt neben der alten Tabelle die neue Tabelle.


Man erstellt auch nicht die Tabelle neu sondern ändert einfach nur die Daten im TableModel (ein geeignetes TableModel vorausgesetzt.

Mein Vorschlag: Die Änderungen werden zu erst ins TableModel übertragen (Standardverhalten einer JTable) und per Listener auf das Model in die Datenbank übertragen. Dann spart man sich die Aktualisierung aus der Datenbank, muss dafür aber sicher stellen, dass der neue Wert in die DB übertragen wird bzw. ggf. auf Fehler reagieren.


----------



## SlaterB (8. Feb 2012)

> Wie kann ich die alte Tabelle löschen und die neue an ihren Platz platzieren bzw. überschreiben? 

auf korrekte Weise,
was soll man dazu ohne deinen Code sagen?
je nach Layout an richtiger Stelle einfügen usw.

viel besser ist aber, die JTable überhaupt nicht auszutauschen, setze bei der vorhandenen JTable ein neues Model


----------



## Kenan89 (8. Feb 2012)

ich will es mal mit der tablemodel variante versuchen:
Mein Code läuft so ab:

Klasse J_Table erbt von JTable und hat ein DefaultTableModel. Dem Konstruktor von J_Table werden aus einer anderen Klasse die spalten und zeilenwerte mitgegeben und diese nimmt der DefaultTableModel.

So jetzt habe ich beim Start des Programms eine feste Tabelle, mit allen werten aus der Datenbank.

Unter dem JTable ist die Klasse J_Panel, welche von JPanel erbt und Eingabefelder besitzt, mit der man Daten löschen, oder hinzufügen kann.

Nach Eingabe kommen die Daten in die DB. Jetzt muss das DefaultTableModel angepasst werden, sprich die spalten undzeilenwerte müssen dem bereits definierten TableModel zugewiesen werden und dann muss das TableModel mit fireTableDataChanged aktualisiert werden.

(Ich zeige deswegen kein Code, weil es verwirren könnte. Ich arbeite mit ca 30 Klassen in verschiedenen Packages und wenn ich da eine kleinigkeit vergesse, weglasse, löst das nur Verwirrung bei den Usern aus. Ich will auch nur grob wissen, wie man das macht. Anwenden schaffe ich es hoffentlich auf mein Problem)


----------



## Michael... (8. Feb 2012)

Kenan89 hat gesagt.:


> Klasse J_Table erbt von JTable


Das halte ich für einen Designfehler. Gibt es einen Grund dafür warum die Klasse von JTable erben muss?


Kenan89 hat gesagt.:


> und hat ein DefaultTableModel.


Besser wäre es in diesem Fall einen eigenes TableModel zu definieren (das ja von DefaultTableModel erben kann). Aber grundsätzlich bietet auch das DefaultTableModel Möglichkeiten Daten "nachträglich" zu manipulieren, z.B. removeRow, insertRow... auch ein setValueAt wäre denkbar.


Kenan89 hat gesagt.:


> dann muss das TableModel mit fireTableDataChanged aktualisiert werden.


Das würde bei der Verwendung der o.g. Methoden des DefaultTableModels automatisch passieren.


----------



## Kenan89 (21. Feb 2012)

Ich habe heute mein altes Projekt ausgegraben. Leider weiss ich immer noch nicht wie ich mein JTable aktualisieren kann.

Die Frage ist einfach, wie man es anstellt, dass sich die Tabelle neu generiert, also auch die alte überschreibt, nachdem der User auf *eintragen* klickt.

Ich stelle mal mein Code rein:


```
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class Connection1 {   //zeigt die Tabelle beim Programmstart an

	public static String[] columnspan;
	public static String[][] rowspan;
	
	public Connection1(){
		String uN = "lig";
		String pW = "lig";
		String conURL = "jdbc:postgresql://10.10.10.242:5432/brain";
		
		Connection conn = null;
		
		try{
			int rows=0;
			int cols=0;
			
			Class.forName("org.postgresql.Driver");
			conn = DriverManager.getConnection(conURL, uN, pW);
			
			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("select count(*) from users2");
			rs.next();
			rows = rs.getInt(1);
			rs.close();
			
			rs = stmt.executeQuery("select id, username from users2");
			cols = rs.getMetaData().getColumnCount();
			
			columnspan = new String[cols];
			rowspan = new String[rows][cols];
			
			for(int i=1; i<=cols;i++){									//Namen der Spalten
				columnspan[i-1] = rs.getMetaData().getColumnName(i);
			}
			
			int row=0;
			while(rs.next()){											//Inhalt der Zeilen
					for(int column = 0; column<cols; column++){
						rowspan[row][column] = rs.getString(column+1);
					}
					row++;
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
}
```


```
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;


public class EintragenUndAktualisieren{   //ist dafür gedacht die Tabelle zu aktualisieren und den Wert einzutragen, der im TextFeld eingegeben wurde
	
	public EintragenUndAktualisieren(String username){
		try{
			Connection conn = null;			
			String uN = "lig";
			String pW = "lig";
			String conURL = "jdbc:postgresql://10.10.10.242:5432/brain";
			
			Class.forName("org.postgresql.Driver");
			conn = DriverManager.getConnection(conURL, uN, pW);
			
			Statement stmt = conn.createStatement();
			
			ResultSet rs = stmt.executeQuery("select max(id) from users2");
			rs.next();
			int id = rs.getInt(1)+1;
			rs.close();
			System.out.println("ID: "+id);
			
			stmt.executeUpdate("insert into users2(id, domain_id, username) values("+id+", 1, '"+username+"')");
			System.out.println("Eingetragen");
		
			new J_Table();
		}
		catch(Exception e){
			System.out.println("Fehler beim Eintragen!");
		}	
	}

}
```


```
import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;


public class J_Frame extends JFrame{

	public static void main(String[] args){
		new J_Frame();
	}
	
	public J_Frame(){
		
		setLayout(new BorderLayout());
		setTitle("Tabellentest");
		setVisible(true);
		setSize(500,500);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	
		
		add(new JLabel("Tabellentest"), BorderLayout.NORTH);
		add(new J_Panel(), BorderLayout.CENTER);
		add(new RegisterUser(), BorderLayout.EAST);
		add(new JLabel("Tabellentest Ende"), BorderLayout.SOUTH);
	}
		
}
```


```
import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.JPanel;
import javax.swing.border.LineBorder;


public class J_Panel extends JPanel{
		
	public J_Panel(){
		setLayout(new BorderLayout());
		setBorder(new LineBorder(Color.BLUE));
		
		add(new J_Table(), BorderLayout.CENTER);
	}
	
}
```


```
import javax.swing.JScrollBar;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;


public class J_Table extends JTable{

	public J_Table(){
		new Connection1();
				
 		DefaultTableModel model = new DefaultTableModel(Connection1.rowspan,Connection1.columnspan);
		this.setModel(model);

	}

}
```


```
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;


public class RegisterUser extends JPanel implements ActionListener{
	
	JButton eintragen = new JButton("Eintragen");
	JTextField name = new JTextField(20);	
	
	public RegisterUser(){
		add(new JLabel("<html><body><p style='font-size: 21px;'>Werte eingeben, um neuen User einzutragen!</p></body></html>"));
		add(new JLabel("Vorname:"));
		add(name);
		add(eintragen);
		eintragen.addActionListener(this);
		
	}
	
	public void actionPerformed(ActionEvent e){
		Object obj = e.getSource();
		if(obj.equals(eintragen)){
			new EintragenUndAktualisieren(name.getText());
		}
	}

}
```

Danke im voraus.


----------



## Camino (21. Feb 2012)

Du hast 
	
	
	
	





```
EintragenUndAktualisieren
```
 als eigene Klasse angelegt. Aber eigentlich ist dies eher eine Methode. Bei jedem Klick erzeugst du davon ein neues Objekt. Ebenso ein neues Objekt deiner JTable.

Dein JTable und auch dein TableModel legst du einmal an und änderst dann einfach nur die Daten im TableModel, welches die Daten in der Tabelle dann aktualisiert.

Ich würde für die JTable keine eigene Klasse anlegen, sondern die Tabelle in deinem JFrame bzw. dem entsprechenden JPanel erstellen und dort auch ein TableModel, welches dann der JTable gesetzt oder übergeben werden kann.

Ich würde die Klassen auch nicht J_Frame, J_Panel oder J_Table nennen, da diese Namen ähnlich der Ursprungsklassen sind und so eher zur Verwirrung beitragen.


```
setVisible(true);
```
 beim JFrame kommt als letztes und nicht irgendwo mittendrin.


----------



## SlaterB (21. Feb 2012)

schon 25 Themen, überwiegend zu GUI-Themen, da lohnt sich ja einmal ein Hinweis, ist es so schwer? :
es gibt eine eigene Area für Fragen zur JTable & Co., das hat mit Java-Basics nichts zu tun, komplett unabhängig von deiner eigenen Einstufung deiner Fähigkeiten,
verschoben

--------

zu einer so breit verwendeten Komponente wie JTable kann man durchaus viele Turorials/ Beispiele finden und lesen,
eine neue JTable zu erstellen ist dabei unüblich,
man kann ein neues Model der vorhandenen JTable zuweisen oder im gleichbleibenden Model die Daten austauschen

(edit: oh, Posting wurde wohl in einen alten Thread verschoben oder nur vorher nicht gesehen, 
diese Grundinformation schon bekannt..)


----------



## Kenan89 (22. Feb 2012)

Daten hinzufügen funktioniert jetzt.
Nun muss ich auch wissen, welche Zelle momentan ausgewählt ist. Welcher Listener wäre am besten geeignet dafür?


----------



## Camino (22. Feb 2012)

Zum Beispiel 
	
	
	
	





```
tabelle.getSelectedRow()
```
 bzw. 
	
	
	
	





```
tabelle.convertRowIndexToModel(tabelle.getSelectedRow())
```
 wenn die Tabelle noch sortiert oder gefiltert wurde.


----------



## SlaterB (22. Feb 2012)

oder mit geringer Überraschung ein ListSelectionListener,
muss man nicht wissen, ist aber kaum zu überlesen wenn man sich irgendwie über JTable informiert, etwa
How to Use Tables (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Swing Components)
welches auf
How to Write a List Selection Listener (The Java™ Tutorials > Creating a GUI With JFC/Swing > Writing Event Listeners)
verlinkt


----------



## Kenan89 (22. Feb 2012)

Okay ich habe nun das Problem dass ich eine Zeile automatisch selektieren lassen möchte.
Das klappt auch mit changeSelection wunderbar. Jedoch ist es so, dass, wenn ich in die Tabelle klicke, ich dann erst eine Exception bekomme und erst beim zweiten Klick die Tabelle benutzen kann. Ausserdem wird bei changeSelection die selektierte Zeile nicht eingefärbt.
Danke im voraus für Antworten.

Die Exception:

```
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
```


----------



## SlaterB (22. Feb 2012)

-1 ist der Index im Event, das passiert mindestens bei Delesektion, vielleicht gibt es auch generell mehrere Events,
einmal für die vorherige, dann für die neue Spalte..,
ein Thema ist auf jeden Fall 'isAdjusting', siehe meinen Link,

schaue dir also generell immer an, was da so passiert, nicht auf alles musst du stur nach Schema F reagieren,
sondern z.B. -1 für 'keine Selektion' gesondert behandeln


----------

