Datenspeicherung im AbstractTableModel

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hi,

ich stehe gerade vor folgendem Problem und stelle mich wahrscheinlich einfach nur zu doof an:
Hier mein Gerüst für mein eigenes AbstractTableModel:
Code:
public class MyTableModel extends AbstractTableModel{
	private ArrayList<String> columnnames;
	
	public MyTableModel(){

	}

	public Object getValueAt(int row, int column){

	}
	
	public int getRowCount(){

	}
	
	public int getColumnCount(){
		return columnnames.size();
	}
	
	public String getColumnName( int columnIndex ){
		return columnnames.get(columnIndex);
	}
	
	public void addColumn(String columnname, Object[] newdata){
		columnnames.add(columnname);
	}
}
Was ich tun möchte ist folgendes:
Über die Methode addColumn sollen der Tabelle dynamisch neue Spalten hinzugefügt werden.

Problem:
Die Anzahl der Zeilen variiert, das heisst ab und zu werden Spalten mit 4 Zeilen hinzugefügt, und ab und zu welche mit 5 oder 6.
Und das gibt dann Probleme bei der Methode getValueAt() weil die Tabelle ja davon ausgeht, dass die Zeilenanzahl in jeder Spalte gleich ist.
Nur wie speichert man die Daten dann im AbstractTableModel. Nehme ich
Code:
ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>(); //erste liste für spalten, zweite für Zeilen
dann habe ich das Problem, dass pro Spalte ja eine unterschiedliche Zeilenanzahl existieren kann.

Hier ein Beispielbild:
demore5.png

Meinetwegen kann die Tabelle intern beispielsweise die Zellen in Spalte C unter Markus auch speichern aber halt ohne Inhalt.

Ich hoffe ich konnte mein Problem klar machen. Falls nicht bitte einfach nachfragen!
 
G

Guest

Gast
Ich bin mir nicht ganz sicher ob eine Tabelle für deinen Anwendungszeck überhaupt das richtige ist. Was willst du denn eigentlich mit den Daten machen bzw. wieso müssen die so "komisch" gespeichert werden?
 

daNny

Aktives Mitglied
Ich hatte mal ein ähnliches Problem, das ich ungefähr so gelöst habe:

Alle "Zeilen" werden als String-Arrays in einer Collection gespeichert. Zusätzlich wird die information gespeichert, wie groß diese Arrays sind, also welche Länge sie haben. War die "Dimension" der Tabelle, also sind vorher nur Arrays mit der Länge 4 gespeichert worden, und soll nun eine neue Zeile hinzugefügt werden, können folgende Situationen auftreten:

Die neue Zeile hat eine kleinere Anzahl als 4 SPalten. Also erweitere dieses einzelne Array so, dass es 4 Spalten hat und füge es hinzu.
Hat die neue Zeile auch 4 Spalten, dann füge sie einfach so hinzu.
Hat die neue Zeile mehr als 4 Spalten, kann man unterschiedlich vorgehen: Entweder, man schneidet alles ab der 4. Spalte ab und fügt so einen evtl. unvollständigen Datensatz ein, oder man fügt die neue Spalte ein, erhöht die DImension der Tabelle entsprechend und iteriert über alle vorhandenen Datensätze und erweitert sie.

arraycopy() ist da oft dein Freund ;)

So hatte ich das mal zumindest gelöst.
 

Wildcard

Top Contributor
Ich verstehe dein Problem mit getValueAt nicht. Wenn da nichts ist, dann ist da eben nichts und du gibst null zurück.
 
H

hey-ho

Gast
Vielleicht solltest du dir wirklich nochmal Gedanken über die Struktur der Datenbank machen - oder mal erklären, warum die Spalten unterschiedliche Längen haben sollen. Normalerweise kenne ich es von Datenbanken, dass in jeder Zeile 1 Datensatz steckt, welcher verschiedene Felder (Spalten) hat, in denen entweder was drinsteht oder auch nicht.
 
G

Guest

Gast
Vielleicht versuche ich das nochmal zu erklären:

Die Spalten der Tabelle stellen jeweils einen Tag dar. Pro Tag kann eine unterschiedliche Anzahl an Personen anwesend sein, also muss eine unterschiedliche Anzahl an Personen dargestellt werden.

Montag, 1.1.2008:
Hans
Dirk
Claudia

Am nächsten Tag sind möglicherweise 4 Personen darzustellen.

Die Tabelle hat beispielsweise den Button "Zeige nächsten Tag". Bei Klick darauf soll zur bestehenden Tabelle eine Spalte hinzugefügt werden.
Nur wie verklickere ich das meinem Model? Das muss ja irgendwie intern die Daten speichern, per getValueAt() den Wert der jeweiligen Zelle zurückgeben, die Anzahl der Zeilen kennen...

Angenommen beim ersten Darstellen der Tabelle hat sie nur eine Spalte mit 4 Zeilen. Drücke ich auf den Button "Zeige nächsten Tag" so wird eine Spalte angehängt. Die hat möglicherweise jedoch mehr Zeilen als die erste Spalte. Dann gibt das eine NullPointerException, weil getValueAt auch versucht auf diese Zeilennummer in der ersten Spalte zuzugreifen.
 

Eminent

Bekanntes Mitglied
Wildcard hat gesagt.:
Ich verstehe dein Problem mit getValueAt nicht. Wenn da nichts ist, dann ist da eben nichts und du gibst null zurück.

Da kann ich nur Wildcard wiederholen, ich verstehe das Problem nicht. Wenn getValueAt(int,int) auf einen Wert zugreifen will der nicht da ist wird eben null oder von mir aus ein Leerstring zurück gegeben was ist das kompliziert dran?
 
H

hey-ho

Gast
Dann würde ich die Datenbank anders strukturieren: in jedem Datensatz (Zeile) eine Spalte für den Namen und eine für den Tag. Dann kannst du ja auch auslesen, wer an welchem Tag anwesend war...
 
G

Guest

Gast
Hm,
hat noch nie jemand eine Tabelle gebastelt, bei der manche Zellen leer bleiben und Daten dynamisch hinzugefügt werden.
Um mein Problem zu verdeutlichen, hab ich mal diese kleine Demo geschrieben:
Code:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

public class DemoTest extends JFrame{
	private MyTableModel mtm;
	private int counter = 1;
	public DemoTest(){
		setLayout(new BorderLayout());
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JTable table = new JTable();
		mtm = new MyTableModel();
		table.setModel(mtm);
		
		JButton button = new JButton("add column");
		button.addActionListener(new MyActionListener());
		
		add(table,BorderLayout.CENTER);
		add(button,BorderLayout.SOUTH);
		pack();
		setSize(400,300);
		setVisible(true);
	}
	
	
	public static void main(String[] args) {
		new DemoTest();

	}
	
	class MyActionListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			if(counter == 1){
				ArrayList<Object> data = new ArrayList<Object>();
				data.add("Michael");
				data.add("Dirk");
				data.add("Susanne");
				mtm.addColumn("01.01.2008", data);
			}
			else if(counter == 2){
				ArrayList<Object> data = new ArrayList<Object>();
				data.add("Markus");
				data.add("Julia");
				data.add("Anna");
				data.add("Maria");
				mtm.addColumn("02.01.2008", data);
			}
			else if(counter == 3){
				ArrayList<Object> data = new ArrayList<Object>();
				data.add("Marie");
				data.add("Andreas");
				data.add("Josephine");
				data.add("Clara");
				data.add("Sandra");
				mtm.addColumn("03.01.2008", data);
			}
			counter++;
		}
	}
	
	
	class MyTableModel extends AbstractTableModel{
		private ArrayList<String> columnnames = new ArrayList<String>();
		private ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>();


		public Object getValueAt(int row, int column){
			return data.get(column).get(row);
		}
		
		public int getRowCount(){
			if(data.isEmpty()){
				return 0;
			}
			else{
				int max = 0;
				for(int i=0;i<data.size();i++){
					if(max < data.get(i).size()){
						max = data.get(i).size();
					}
				}
				return max;
			}
		}
		
		public int getColumnCount(){
			return columnnames.size();
		}
		
		public String getColumnName( int columnIndex ){
			return columnnames.get(columnIndex);
		}
		
		public void addColumn(String columnname, ArrayList<Object> onecolumn){
			columnnames.add(columnname);
			data.add(onecolumn);
			fireTableStructureChanged();
			fireTableDataChanged();
		}
	}
}

Hier fliegt eine IndexOutOfBoundsException weil ich eine verschachtelte ArrayList verwende und bei getRowCount immer die maximale Zeilenanzahl zurückliefere.
Nur wie macht man das anders?
 
H

hey-ho

Gast
Was hast du gegen meinen Vorschlag? Da kannst du doch dynamisch neue Tage hinzufügen. Halte ich für die einfachste Möglichkeit. Und dann hast du auch dein beschriebenes Problem nicht mehr...
 
M

Michael...

Gast
Um mal den Vorschlag von weiter oben aufzunehmen, die Methode getValueAt im Model anpassen:
Code:
public Object getValueAt(int row, int column){ 
    if (data.get(column).size()-1<row)
    return null;
    return data.get(column).get(row); 
}
!!!Achtung Code ist nicht geprüft!!!
 

Eminent

Bekanntes Mitglied
Michael... hat gesagt.:
Um mal den Vorschlag von weiter oben aufzunehmen, die Methode getValueAt im Model anpassen:
Code:
public Object getValueAt(int row, int column){ 
    if (data.get(column).size()-1<row)
    return null;
    return data.get(column).get(row); 
}
!!!Achtung Code ist nicht geprüft!!!

Sollte funktioniert bzw. kann man in allergrößter Not ja auch noch n try-catch rum machen und bei einer Exception Leerstring oder null zurück geben.

Wie gesagt an sich verstehe ich das Probem hier nicht.
 
G

Guest

Gast
Eminent hat gesagt.:
Sollte funktioniert bzw. kann man in allergrößter Not ja auch noch n try-catch rum machen und bei einer Exception Leerstring oder null zurück geben.

Wie gesagt an sich verstehe ich das Probem hier nicht.
Du meinst so:
Code:
		public Object getValueAt(int row, int column){
			Object value = null;
			try{
				value = data.get(column).get(row);
			}
			catch(IndexOutOfBoundsException e){
				
			}
			return value;
		}
 
G

Guest

Gast
Wildcard hat gesagt.:
Böse böse :noe:
Wieso denn?

Lieber so?:
Code:
public Object getValueAt(int row, int column){
    if (data.get(column).size()-1<row)
    return null;
    return data.get(column).get(row);
}
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben