# AbstractTableModel



## brunso (14. Juli 2007)

Hallo zusammen,

ich taste mich so langsam an das TableModel heran,

ich lade ein resultSet aus meiner DB, schmeisse den ganzen Kram in die Tabelle, alles wunderbar. Ich habe die Möglichkeit über ein JTextField ein neues Query zu bauen und abzuschicken, funktzioniert alles wunderbar.

 Nur wenn ich jetzt die Zellen editieren will wird der geänderte Wert nicht angezeigt. 

In 
	
	
	



```
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		  
		aValue = (Object) data[rowIndex][columnIndex];

	      

		  
		  

	  }
```

habe ih probleme, glaube, da mein data ja ein Vector ist und ich da nicht die Koordinaten korrkt rausbekomme.

Hier ma die ganze Class:


```
public class PXTableModel extends AbstractTableModel{

	/**
	 * 
	 */
	private static final long serialVersionUID = 7505358431169338941L;
	public Vector data;
	private Vector columnNames;

	
	public PXTableModel( Vector data, Vector columNames) 
	   { 
	      this.columnNames = columNames; 
	      this.data = data; 
	   } 
	    
	   public void setData( Vector data ) { 
	       this.data = data; 
	       fireTableDataChanged(); 
	   }
	   
	   public Vector getData() { 
	    return data; 
	   } 
	    
	   public int getRowCount() { 	
	      // TODO Automatisch erstellter Methoden-Stub 
	    return data.size(); 
	   }
	   
	   public int getColumnCount() { 
	      // TODO Automatisch erstellter Methoden-Stub 
	    return columnNames.size(); 
	   }
	   
	   public String getColumnName(int col) { 
		return columnNames.elementAt(col).toString(); 
	   }
	   
	   public Object getValueAt(int rowIndex, int columnIndex) {
		return ((Vector) getData().get(rowIndex)).get(columnIndex);	
	}

	  public boolean isCellEditable(int row, int col) {
		  
		return true;
		  
	  }
	  public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		  
		aValue = (Object) data[rowIndex][columnIndex];

	      

		  
		  

	  }

}
```


Gruss
brunso


----------



## celph_titled (14. Juli 2007)

Hallo,

Wieso benutzt du nicht das DefaultTableModel? Das funktioniert genauso, du kannst auch den Constructor mit zwei Vectoren benutzen.


----------



## brunso (14. Juli 2007)

okay, aber das ändert an meinem Problem nichts!

bekomme es trotzdem nicht hin, dass der geänderte wert angezeigt wird!


----------



## MeinerEiner_80 (15. Juli 2007)

Moin!


brunso hat gesagt.:


> ```
> public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
> 
> aValue = (Object) data[rowIndex][columnIndex];
> ...


Falsche Richtung. Du weist dem neuen Wert aValue hier deinen Wert aus deinen Daten zu. Anderum wäre sinnvoller...

```
data[rowIndex][columnIndex] = aValue
```

PS: Auch drank denken, alle TableModelListener über die Veränderung zu informieren

*grüssle*
MeinerEiner


----------



## brunso (15. Juli 2007)

ähh,

vielleicht steh ich ja jetzt total auf dem Schlauch. welche TableModelListener? bis jetzt brauchte ich keine, die Table hat alles gemacht!

sorry, auch andersrum, wie du es schreibst, geht esnicht. eclipse meckert. data ist ja mein Vector und data[][] ja ein Array!


----------



## RealHAZZARD (15. Juli 2007)

Hallo,

diese Listener können von dir, jemannd anderes (der dein Model benutzt) oder sogar von Swing selbst genutzt werden. Dies ist die Informationsquelle für alle, wenn es um Veränderungen am TableModel geht. Also nicht denken "ich hab keine Listener hinterlegt. Also brauch ich keine Listener informieren". Denn all zu oft hängt Swing schon Listener an Komponenten. Daher ist es wichtig diese zu informieren.
Das ist ein allgemeiner Tip zu Swing.
Die Methoden Add,Get und Remove - TableModelListener findest du schon im AbstractTableModel, das du also dank DefaultTableModel schon mit an Bord hast. Die GetMethode liefert dir einen Array an Listenern zurück, und du brauchst ja nur mit einer for-Schleife alle durch gehen und ein Event abfeuern.


----------



## brunso (15. Juli 2007)

Hmm,

wo soll ich den Listener denn dranschrauben? Ma ganz blöd gefragt!

Okay, aber ich kann in der Methode setValueAt() die neuen Werte Auslesen, NUR ich bekomme sie nicht zurückgeschrieben, WEIL ja, keine Ahnung warum nicht. es hat wohl was mit dem Vector zutun.

Also die Frage ist doch, wie komme ich in Bezug auf meinen Datenvektor an die x- und y-Koordinate um dann zu sagen schieb value bitte da rein.


----------



## RealHAZZARD (15. Juli 2007)

Ich bin mir auch nicht ganz sicher, ob es Not tut diese Methode zu überschreiben. Warum verwendest du nicht einfach dein Model. Beim DefaultTableModel gibt es eine Methode setDataVector(Vector data,Vector columnIdent). Nimm die doch einfach an der Stelle, an der du das Ergebnis einer neuen Query bekommst. data ist ein Vector mit Vectoren, die jeweils eine Zeile darstellen (wie du es schon von der Instanzierung des Models kennst). Naja und den Rest brauch ich eigentlich nicht vorkauen, da es ja in der Api steht. Schau dir da mal die Methode an.


----------



## brunso (15. Juli 2007)

Sorry, aber auch das geht nicht! Bekomme so langsam die kriese. 

In setDataVector wird ja der komplette kram der Tabelle ins Table geschrieben. wie soll ich denn dann damit exakt eine zelle ändern

Sorry, kapiers nicht!


----------



## RealHAZZARD (15. Juli 2007)

Achso. Sry das hab ich überlesen. Dann nutzte einfach die Methode setValueAt(...). Also nicht überschreiben, sondern einfach nur nutzen. Wieder an der Stelle, an der du das Ergebnis deines neuen Querys bekommst.


----------



## brunso (15. Juli 2007)

ich glaube wir reden aneinander vorbei.

Ich schilder noch einmal:

Also ich habe eine JTable, die ich vorab mit einerm query aus der DB fülle (und anzeige). Dann habe ich die Möglichket über ein Textfeld ein neues query an die DB zu jagen und meine Tabelle wird auch neu geladen. Soweit-sogut.

Nun klicke ich auf irgendeine Zelle und schreibe was rein. Nun Drück ich enter oder klicke woanders hin, dann bleibt der wert aber nicht Der Alte wird angezeigt. 

Also muss ich ja den neuen wert in meinen DATENVEKTOR schreiben, komme aber nicht dran

Gruss
brunso


----------



## RealHAZZARD (15. Juli 2007)

Einen neuen Wert brauchst du nicht in deinen Vector schreiben. Den übergibst du nur einmal, den Rest macht die Table. Die hält sich die Daten nach der Übergabe selbst. Sie fragt nicht jedes Mal den Vector, den du übergeben hast, sondern die Kopie die sie sich gemacht hat. 
Erster Tip auf jeden Fall nicht mehr die Methode setValueAt überschreiben. Denn die wird aufgerufen, wenn einer den Wert einer Zelle ändert. Und du füllst ja bisher in dieser Methode nur deinen Vector. Das nützt der Table aber nichts. Wenn sie dennoch in der Methode den neuen Wert übernehmen soll, dann musst du super.setValueAt(...) aufrufen. ABER du scheinst das Überschreiben nicht zu brauchen, also lass das.
Wenn das nicht hilft:
Schau dir mal das Standartverhalten der Table an. Normalerweise nimmt sie neue Werte auf. Also muss es ja etwas sein, das du da rein gebaut hast...Eine falsch gesetzte Option, oder eben eine Methode die du falsch überschreibst. Kommentiere also nach ein ander mal verschiedene Sachen aus, und probier obs dann geht.
Aber mein Tip ist wie schon geschrieben: lösche Folgendes einfach raus:
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {

		aValue = (Object) data[rowIndex][columnIndex];






	  }


----------



## brunso (15. Juli 2007)

Okay, hab ich gemacht, dann bekomme ich eine NullPointerException. Aus dem weiterne Fehlercode nehme ich an, dass ich meinem Model auch noch einen CellEditor implementieren lassen muss. Sehe ich das richtig ?

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at javax.swing.table.DefaultTableModel.setValueAt(Unknown Source)
	at javax.swing.JTable.setValueAt(Unknown Source)
	at javax.swing.JTable.editingStopped(Unknown Source)
	at javax.swing.AbstractCellEditor.fireEditingStopped(Unknown Source)
	at javax.swing.DefaultCellEditor$EditorDelegate.stopCellEditing(Unknown Source)
	at javax.swing.DefaultCellEditor.stopCellEditing(Unknown Source)
	at javax.swing.JTable$GenericEditor.stopCellEditing(Unknown Source)
	at javax.swing.plaf.basic.BasicTableUI$Handler.mousePressed(Unknown Source)
	at java.awt.AWTEventMulticaster.mousePressed(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)


----------



## RealHAZZARD (16. Juli 2007)

Poste bitte nochmal deinen Code wie er jetzt ist. 
EDIT: Kann es sein, dass dein Query irgendwo null dabei hat? Wenn ja hast du jetzt einen Grund die Methode setValueAt(...) zu überschreiben ;-).
Das sähe dann so aus:

```
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {          
   if (aValue==null)aValue=new String();
   super.setValueAt(aValue,rowIndex,columnIndex);
}
```


----------



## brunso (16. Juli 2007)

Moin,

auch mit deiner Methode bekomme ich eine NullPointerException.

hier mein Model

```
import java.util.Vector;

import javax.swing.table.DefaultTableModel;



public class PXTableModel extends DefaultTableModel{

	/**
	 * 
	 */
	private static final long serialVersionUID = 7505358431169338941L;
	private Vector data;
	private Vector columnNames;

	
	public PXTableModel( Vector data, Vector columnNames) 
	   { 
		this.columnNames = columnNames; 
	    this.data = data;
	   
	    System.out.println(this.columnNames);
	    System.out.println("++++++++++++++++++++++++++++++++++++++");
	    System.out.println(this.data);
	   
	   } 
	    
	   public void setDataVector( Vector data, Vector columnNames ) { 
		   	this.columnNames = columnNames; 
		    this.data = data; 
	        
	   }
	   
	   public Vector getDataVector() { 
	    return data; 
	   } 
	  
	   public int getRowCount() { 	
	      // TODO Automatisch erstellter Methoden-Stub 
	    return data.size(); 
	   }
	   
	   public int getColumnCount() { 
	      // TODO Automatisch erstellter Methoden-Stub 
	    return columnNames.size(); 
	   }
	   
	   public String getColumnName(int col) { 
		return this.columnNames.elementAt(col).toString(); 
	   }
	   
	   public Object getValueAt(int rowIndex, int columnIndex) {
		return ((Vector) getDataVector().get(rowIndex)).get(columnIndex);	
	}

	   public boolean isCellEditable(int row, int col) {
		  
		return true;
		  
	  }
	  
	
}
```

Hier das Panel, wo es instanziiert wird (achte nicht auf den teilweise doch rechten wirrwarr,, das Layout ist nich nicht fertig, dies dient mehr noch dem testen)

```
package de.bwa.projektx.GUI;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import de.bwa.projektx.DB.DBHelper;
import de.bwa.projektx.MODELS.PXTableModel;

public class QueryPanel implements ActionListener, TableModelListener{

	public JScrollPane scrollPane;
	private JPanel queryPanel, setQuery;
	private JTable table;
	public DBHelper db;
	private String query = "select * from artikel_kategorie";
	private JButton fire;
	private JTextField in;
	private PXTableModel tModel;
	private Vector newData;
	
	public JPanel createQueryPanel() {

		
		
		queryPanel = new JPanel();
		queryPanel.setBackground(Color.gray);
		queryPanel.setLayout(new BorderLayout());
		queryPanel.add(BorderLayout.NORTH,setQuery());
		
			
			db = new DBHelper();
			db.Connect(query);
			//db.listTables();
			tModel = new PXTableModel(db.resultData, db.resultColumnNames);
			table = new JTable(tModel);
			//tModel.addTableModelListener(this);
			
		
			scrollPane = new JScrollPane();	
			scrollPane.getViewport().add(table);
		
		
		
			queryPanel.add(BorderLayout.CENTER,scrollPane);

		
	return queryPanel;
	}
	
	public JPanel setQuery() {
		db = new DBHelper();
		db.Connect(query);
		setQuery = new JPanel();
		
		GridBagLayout gbl = new GridBagLayout();
		setQuery.setLayout(gbl);
		GridBagConstraints gbc=new GridBagConstraints();

		//		 Festlegen, dass die GUI-Elemente die Gitterfelder in 
        // waagerechter Richtung ausfüllen:
		gbc.fill=GridBagConstraints.HORIZONTAL;

		// Die Abständer der einzelnen GUI-Elemente zu den gedachten 
        // Gitterlinien festgelegen:
		gbc.insets = new Insets(5,5,5,5);  

		gbc.gridx = 0;  // x-Position im gedachten Gitter
		gbc.gridy = 0;  // y-Position im gedachten Gitter
		gbc.gridheight = 5;  // zwei Gitter-Felder hoch


		
		gbc.gridx=1; 
		gbc.gridy=1;
		gbc.gridheight = 1;
		in = new JTextField(50);
		gbl.setConstraints(in, gbc);
		setQuery.add(in);
		
		gbc.gridx=2; 
		gbc.gridy=3;
		gbc.gridheight = 1;
		
		//gbl.setConstraints(db.listTables(), gbc);
		//setQuery.add(fire);
		
		gbc.gridx=0; 
		gbc.gridy=5;
		gbc.gridheight = 1;
		in = new JTextField(50);
		gbl.setConstraints(in, gbc);
		setQuery.add(in);
		
		gbc.gridx=1; 
		gbc.gridy=5;
		gbc.gridheight = 1;
		fire = new JButton("Finden 0/5");
		gbl.setConstraints(fire, gbc);
		setQuery.add(fire);
		
		

		gbc.gridx=0; 
		gbc.gridy=0;
		gbc.gridheight = 1;
		Button btClose = new Button("0/0");
		btClose.addActionListener(this);
		gbl.setConstraints(btClose, gbc);
		setQuery.add(btClose);


		
		
		
		fire.addActionListener(this);
		
		return setQuery;
	}



	public Vector result(String query) {
			
			db = new DBHelper();
			db.Connect(query);
			newData = db.resultData;
			
			System.out.println(newData);
	return newData;
		
	}
	
	


	public void actionPerformed(ActionEvent arg0) {
		if (arg0.getSource().equals(fire)) {
			
			System.out.println("You´r fired");
			
			if((!(in.getText()=="")))
			{
			
			
			query = in.getText();
			
	
			this.tModel.setDataVector(result(query), db.resultColumnNames);
			this.tModel.fireTableDataChanged();
			
			
		} else {
				System.out.println("Must schon was eingeben");
				}
			
		}
	}

	public void tableChanged(TableModelEvent arg0) {
		
		
	}
	
	
}
```

und dann noch der DB Helper, wo ich mir die Daten Ziehe (auch hier im Moment nur Connect() zu betrachten)


```
package de.bwa.projektx.DB;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

public class DBHelper {
	
	 
	
    
     String hostname="xxxxxxx"; 
     String port="3306"; 
     String dbname="xxxx"; 
     String user="xxxx"; 
     String pw="xxxxx"; 	
     Connection conn = null;
     String sql;
     
     public Vector<Vector<Object>> resultData;
     public Vector<String> resultColumnNames;
     
     public Vector<Vector<Object>> Connect(String sql) {
    	 
    	 	resultColumnNames = new Vector<String>(); 
    	 	resultData = new  Vector<Vector<Object>>(); 
    	 	this.sql = sql;
     
     try 
     { 
         Class.forName("com.mysql.jdbc.Driver").newInstance(); 
         String url="jdbc:mysql://"+hostname+":"+port+"/"+dbname; 
         conn=DriverManager.getConnection(url,user,pw); 	
      
         
         Statement stmt=conn.createStatement(); 
         
         ResultSet rs=stmt.executeQuery(sql); 
         ResultSetMetaData rsmd=rs.getMetaData(); 
         
         int columns=rsmd.getColumnCount(); 
        
         
         for (int i = 1; i <= columns; i++) 
         { 
        	
             resultColumnNames.add( rsmd.getColumnName(i) ); 
         } 
         while (rs.next()) 
         { 
             Vector<Object> row = new Vector<Object>(columns); 
             for (int i = 1; i <= columns; i++) 
             { 
            	
                 row.addElement( rs.getObject(i) ); 
             } 
            
                          
             resultData.addElement( row ); 
             
         } 
        
         rs.close(); 
         
         stmt.close(); 
     } 
     catch(Exception e) 
     { 
         System.out.println( e ); 
     }
     
	return resultData;     

     }
     
     public void listTables() {
    	 
    	 try {

    		DatabaseMetaData rsmd = conn.getMetaData();
			ResultSet rs = rsmd.getCatalogs();//getTables(dbname, null, null, null);
			
			  ResultSetMetaData rsmr =rs.getMetaData(); 
			  int counter = rsmr.getColumnCount();
			  
			  System.out.println(counter);
			while (rs.next()) {
				for(int i=1; i<counter ; i++) {
				System.out.println(rs.getObject(i));
				}
			}
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	 
    	 
     }
     
}
```


Gruss
brunso


----------



## brunso (16. Juli 2007)

Falscher Text eingegeben


----------



## RealHAZZARD (16. Juli 2007)

:suspekt: Mir ist immer noch nicht klar, warum du so viele Methoden in deinem DefaultTableModel überschreibst, in denen du gerade so viel tust wie nötig, oder sogar zu wenig. Ich kann mich ja irren, aber ich sehen keinen Sinn in den Methoden: 
- getDataVector
- setDataVector
- getRowCount
- getColumnCount
- getColumnName
- getValueAt
...kommentier die mal aus. 

Noch lustiger ist, dass die Methode fehlt, die ich oben geschrieben habe ;-)


----------



## brunso (16. Juli 2007)

Du,

das habe ich so aus den Büchern/Internet usw. Lach, Deine Methode, Du hast doch geschrieben ich solls gar nicht überschreiben, deshalb habe ich die auch wieder rausgenommen.

naja, vielleicht muss ich auch erstmal in mich gehn und drüber nachdenken 

gruss

brunso


----------



## RealHAZZARD (16. Juli 2007)

Ok. Sry. Das war ein bisschen viel hin und her. 
Also... was ich jetzt probieren würde:
- Die besagten Methoden auskommentieren.
- Die setValueAt so wie ich sie oben beschrieben habe reinnehmen. (ich bin mir dessen bewüsst dass ich erst sagte "nicht überschreiben, weil es keinen Sinn macht", aber jetzt macht es ja Sinn, weil du so auf den Fall aValue==null reagieren kannst, und dafür einen neuen leeren String übergeben kannst (an die super.setValueAt(...)) )


----------



## brunso (16. Juli 2007)

Wärste ne Frau, würd ich Dich jetzt knutschen 

IT WORKS.

Mann Mann Mann. Also ich bin der Meinung, ich hab schon recht viel an Literatur(die ich mir auch reinpfeife) Auch wird hier immer bei sowas das Dicke Buch von SunPress empfohlen "JFC beherrschen" - wo es auch extremst ausführlich beschriben ist, aber sehr unverständlich, wie ich finde. 

Denn ganz nachvollziehen kann ich das nicht.

Mal sehen, jetzt muss ich nämlich den neu gesetzten wert auch wieder zurückbekommen und in die DB schreiben.

Gruss
brunso


----------



## RealHAZZARD (16. Juli 2007)

Ok.


> Wärste ne Frau, würd ich Dich jetzt knutschen


Danke dass du davon absiehst.



> Denn ganz nachvollziehen kann ich das nicht.


Wenn es etwas ist, was die Lösung angeht, frag ruhig.



> Mal sehen, jetzt muss ich nämlich den neu gesetzten wert auch wieder zurückbekommen und in die DB schreiben.



Dafür ist so ein TableModelListener ideal. Da bekommst du die Exakten Koordinaten aller betroffenen Zellen. 

Um diese Überlegung (falls sie dir durch den Kopf ging) :


> Ich hab doch einmal die Methode setValueAt(...) überschrieben, da kann ich das Update auf die DB auch gleich da durchfüren.!?


gleich mal aus zu schließen: Kann man...ja...aber sollte man nicht. Die Methode verrät ja schon was sie macht. Alles anderes sollte auch wo anders gemacht werden. Auf Änderung reagieren z.B ganz Swing-typisch durch Listener eben.


----------



## brunso (16. Juli 2007)

Okay, danke bis hierhin und für 



> Wenn es etwas ist, was die Lösung angeht, frag ruhig.



selbst schuld 

Wie gesagt, ich bekomme keine Exception mehr, auch wenn ich bei der initialisierung nichts lade, das ist schön. 

Nur wir gesagt, wo soll ich den Listener anhängen? Denn in meinem QueryPanel gehts nicht oder muss noch eine Klasse noch ein Listener Interface implementieren.

Schön wäre ein verständliches Klassendiagramm um den Zusammenhang wirklich zu verstehen in Bezug auf JTables. Hast vielleicht einen Link oder Tipp für mich.

merci und gruß

brunso


----------

