# Tabelle erzuegen mit TableModel



## Googlehupf (5. Oktober 2013)

Hallo,

ich habe eine Frage zu JTable und MyTableModel.

Hier mal ein Programm, dass nur JTable verwendet:

```
public static final int MAX_ROWS = 100;
public static final int MAX_COLS = 6;

private String[][] data = new String[MAX_ROWS][MAX_COLS];
private String[] columnNames = new String[MAX_COLS];


for (int i = 0; i < MAX_ROWS; ++i) {
for (int j = 0; j < MAX_COLS; ++j)
data[i][j] = Integer.toString(i * MAX_COLS + j);
}

for (int i = 0; i < MAX_COLS; ++i) {
columnNames[i] = new String("Spalte " + (i + 1));
}
myTable = new JTable(data, columnNames);
JScrollPane scrollpane = new JScrollPane(myTable);
contentPane.add(scrollpane);
```

Natürlich fehlen hier jetzt die Klassen, die das Fenster etc. generieren, aber das ist hier nicht wichtig. Aufjedenfall verwendet dies nur JTable, d.h. man übergibt ein 2-dimensionales Array, das man weiß wo die Daten hingehören und dann noch ein 1-dimensionales Array für die Spaltennamen.

Kurze Frage zum 2-dimensionalen Array: Also in i und j stehen immer die selben Daten oder? Wenn man die JTable benutzt müssen ja immer in i und j die selben daten stehen? Also: i=5, j=5 --> stehen dieselben daten usw.
Stimmts?

Hier das 2te Programm, das TableModel verwendet:

MyTableModel.java:

```
package JTable_Demo;

import java.awt.*;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;

public class MyTableModel extends AbstractTableModel {
	int row_cnt, col_cnt;

	public MyTableModel(int rows, int cols) {
		row_cnt = rows;
		col_cnt = cols;
	}

	public int getColumnCount() {
		return col_cnt;
	}

	public int getRowCount() {
		return row_cnt;
	}

	public String getColumnName(int colnum) {
		return new String("Spalte " + (colnum + 1));
	}

	public Object getValueAt(int row, int col) {
		return Integer.toString(row * col_cnt + col);
	}

}
```

MainFrame.java

```
package JTable_Demo;

import java.awt.*;
import javax.swing.*;

public class MainFrame extends JFrame {
  private JPanel contentPane;
  public static final int MAX_ROWS= 100;
  public static final int MAX_COLS= 100;
  private JTable myTable;
  public MainFrame() {
    try {
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      FrameInit();
    }
    catch (Exception exception) {
      exception.printStackTrace();
    }
    
    myTable= new JTable (new MyTableModel(MAX_ROWS,MAX_COLS));
    JScrollPane scrollpane = new JScrollPane(myTable);
    contentPane.add(scrollpane);
  }
  
  private void FrameInit() throws Exception {
    contentPane = (JPanel) getContentPane();
    contentPane.setLayout(new BorderLayout());
    setSize(new Dimension(400, 300));
    setTitle("Frame Title");
  }
}
```

Hier fehlt auch wieder die Fenster-generierung, was ja egal ist.

Ich verstehe nicht was TableMode genau macht. MyTableModel ist ja eine selbstgenerierte Klasse. Aber "extends AbstractTableModel" verleiht dem ganzen erst warschl. die "spezielle" Fähigkeit, oder?

Am Ende sollte doch dieselbe Tabelle rauskommen, wie im ersten Programm, richtig? Aber tut es nicht, also fehlt irgendwas. 

Z.b. die get-funktionen in MyTableModel muss ich doch auch aufrufen oder? Kann mir einer das TableModel ev. näher erklären bitte? Hab auch leider im Inet nichts nützliches gefunden.

mfg

Googlehupf


----------



## zerix (5. Oktober 2013)

Hallo,

ich finde das hier erklärt ziemlich treffend was die JTable und das TableModel macht
http://wiki.byte-welt.de/wiki/JTable_(Java_API)
http://wiki.byte-welt.de/wiki/TableModel_(Java_API)

Viele Grüße

Sascha


----------



## sheel (5. Oktober 2013)

Googlehupf hat gesagt.:


> Kurze Frage zum 2-dimensionalen Array: Also in i und j stehen immer die selben Daten oder? Wenn man die JTable benutzt müssen ja immer in i und j die selben daten stehen? Also: i=5, j=5 --> stehen dieselben daten usw.
> Stimmts?


Keine Ahnung, was damit gemeint ist.



Googlehupf hat gesagt.:


> Ich verstehe nicht was TableMode genau macht. MyTableModel ist ja eine selbstgenerierte Klasse. Aber "extends AbstractTableModel" verleiht dem ganzen erst warschl. die "spezielle" Fähigkeit, oder?


Die "Spezielle Fähigkeit" nennt sich Vererbung.
Es gibt ein Standard-Tablemodel (eben das AbstractTM);
die Methoden davon machen nicht viel sinnvolles bzw. teilweise auch gar nichts.
Der Sinn der Klasse ist: Sie _hat_ die Methoden immerhin,als Vorlage
zB. getColumnCount, keine Parameter, Returnwert int.

Vom ATM kann man jetzt selbst eine Klasse ableiten,
die die Dummymethoden von ATM durch Methoden mit sinnvollem Inhalt ersetzt.

(bzw., da ATM abstract ist hat es Methoden, die überhaupt keinen Code haben.
Nicht mal ein leeres {}. Daher ist man gezwungen,
diese Methoden in der eigenen Klasse selbst bereitzustellen,
wenn man eine ordentliche verwendbare Klasse haben will.
Falls man das nicht/unvolsltändig macht: Compilerfehler)



Googlehupf hat gesagt.:


> Z.b. die get-funktionen in MyTableModel muss ich doch auch aufrufen oder? Kann mir einer das TableModel ev. näher erklären bitte? Hab auch leider im Inet nichts nützliches gefunden.


Du selbst rufst davon gar nichts auf.

In der ersten Variante hast du ein ein zweidim. Array, was in der Tabelle stehen soll.
Jetzt gibt es aber Situationen wo ein Array unpraktisch bzw. sogar unmöglich wäre.
(Beispiel weiter unten).

Daher die Alternative, dass man der Table sagt: Hier ist mein Tablemodel,
und was du anzeigen sollst erfährst du, wenn du getXY aufrufst.
Die Table ist die einzige Stelle, die etwas aus dem TM braucht.
(Man kann es schon selbst verwenden, aber muss nicht).
Und wenn die Table wissen will, was in Zeile 3 Spalte 4 steht
oder wieviel Spalten es eigentlich gibt ruft sie Methoden aus deinem TM auf.
Die geben dann den Wert zurück -> Woher die den haben ist dann deine Sache.


Ein Beispiel, wann die Array-Variante überhaupt nicht geht:
Wenn zB. die anzuzeigenden Daten in einer Datei auf der Festplatte sind
und dort insgesamt 20GB haben.
Für ein Array müsste man alles zur selben Zeit im Hauptspeicher haben,
was oft durch Speichermangel einfach nicht geht.
Mit TM holt sich die Table nur das, was sie laut Position der Scrollleiste gerade braucht,
und dein TM kann dann die paar geforderten Zeilen aus der Datei holen.


----------



## Googlehupf (5. Oktober 2013)

Ich hab hier mal ein Bild. Links ist die zweite Variante und rechts die erste. Laut meiner .pdf steht da, dass die zweite variante genauso aussehn müsste wie die erste.

Ich verstehe es nicht. Ich muss doch irgendwie sagen, was jetzt da in der Tabelle steht oder?. 

JTable fragt ja ATM wegen der Werte, oder? Aber wie weise ich Werte der ATM zu?


----------



## sheel (5. Oktober 2013)

Googlehupf hat gesagt.:


> Ich verstehe es nicht. Ich muss doch irgendwie sagen, was jetzt da in der Tabelle steht oder?.
> JTable fragt ja ATM wegen der Werte, oder? Aber wie weise ich Werte der ATM zu?


Die JTable fragt nicht das AbstractTableModel, sondern deine davon abgeleitete Klasse
(solange du der JTable eine Instanz davon beim Erstellen auch gibst)

Und wo deine Klasse die Werte hernimmt ist, wie gesagt, ganz egal.
Deine klasse könnte in sich wieder ein Array haben, oder aus Dateien lesen,
oder die Werte je nach Bedarf on-the-fly ausrechnen, oder...

Das Soll sind also 6 Spalten, 100 Zeilen, und von links oben bis rechts unten
fortlaufende Werte beginnend bei 0. Dein TableModel willst du so machen, dass die
Zeilen-/Spaltenanzahl per Konstruktorparameter festgelegt wird, gut.

Problem in MainFrame.java:
Du hast die MAX_ROWS und MAX_COLS beide auf 100.
Die übegibst du dann auch als Zeilen-/Spaltenanzahl zum Tablemodel.
Sollte der Col-Teil nicht 6 sein?

Weil du zurzeit 100 Spalten hast ist der Platz für deine angezeigte JTable so klein,
dass die Spalten zu schmal für zwei-, drei...stellige Zahlen sind.
Deshalb ... als Platzhalter

Das Tablemodel selbst schaut auf den ersten Blick gut aus.
Also einfach die Cols runterdrehen.


----------



## Googlehupf (6. Oktober 2013)

Ah ok jetzt gehts!


Aber wie läuft das genau ab? Wenn ich die Instanz von ATM an JTable übergeben, wird ja zumal der Konstruktor von ATM aufgerufen, da werden ja jetzt Spalten- und Zeilenanzahl gespeichert. 

Dann wird der Konstruktor von JTable aufgerufen und dann holt sich JTable durch diese Methoden, also ganz automatisch die ganzen Informationen, was ich in den Methoden geschrieben habe.

Hab ich das in etwa so richtig verstanden?


----------



## sheel (6. Oktober 2013)

Ungefähr richtig.
Ja, die JTable verwendet deine Methoden aus dem Tablemodel,
um Infos über das Anzuzeigende zu sammeln.

Aber nochmal deutlicher: Du hast kein "A"-TM.
Nachhilfe in Vererbung ist wohl angesagt, unabhängig von der Tablesache hier.
...aber das hat Zeit bis morgen (äh, heute, aber später )


----------



## Googlehupf (9. Oktober 2013)

Schreibst du noch etwas dazu @sheel ?


----------



## Googlehupf (12. Oktober 2013)

sheel hat gesagt.:


> Nachhilfe in Vererbung ist wohl angesagt, unabhängig von der Tablesache hier.
> ...aber das hat Zeit bis morgen (äh, heute, aber später )




Ich dachte du wolltest noch etwas dazu schreiben? Kannst du das bitte machen, sheel ?


----------



## Writtscher (14. Oktober 2013)

Ich denke er wollte was zu Vererbung sagen:

http://openbook.galileodesign.de/javainsel5/javainsel06_006.htm#Rxx747java06006040001E71F019100

Vererbung ist eines der Methoden der objektorientierung. But careful! Vererbung ist ein Antipattern!
https://www.google.de/search?q=inhe...&ie=UTF-8#q=composition+over+inheritance+java


----------



## Googlehupf (19. Oktober 2013)

Ja, eigentlich weiß ich ja was eine Vererbung kann. Z.b. die Klasse MainFrame erbt von der Klasse JFrame, d.h. MainFrame kann alle Methoden von JFrame benützen bzw. MainFrame ist ein JFrame?

Wie hängt das jetzt mit diesem ATM zusammen? Warum muss ich da diese Methoden in MyTableModel trotzdem rausschreiben?


----------



## Googlehupf (22. Oktober 2013)

Hmm, hat denn jemand Zeit mir weiter zu helfen bitte?


----------



## zerix (26. Oktober 2013)

Was genau ist dein Problem?

Viele Grüße

Sascha


----------



## Googlehupf (27. Oktober 2013)

Naja, ich verstehe noch nicht so wirklich, wie nun so ein TableModel genau funktioniert. Schauen wir uns doch mal bei meinem Post #1, das 2te Programm an. Hier wird ja dieses ATM verwendet.

ATM ist also eine Klasse, von der man ableiten kann. Diese Klasse enthält schon vorgegebene, aber abstrakte Methoden. Abstrakte Methoden sind einfach  vorgegeben Methoden ohne Parameter etc., also einfach leer. 
Und darum muss ich eine eigene Klasse machen und die Methoden von ATM erben. Und diese Methoden kann ich dann wie ich will verändert, also x parameter hinzufügen z.B.

Stimmt das?

Aber ich könnte ja theretisch einfach so eine Klasse erstellen(ohne diese von ATM abzuleiten) und einfach methoden machen. Naja gut das bringt dann wieder nix, da die Methoden, dann net mit meinem JTable verbunden sind. 

Hab ich recht?

Hm naja vielleicht kann mir jemand bitte das noch etwas genauer erklären, wie das nun genau funktioniert. Wie funktioniert der Vorgang z.b. mit den Daten in die Tabelle einfügen?

Z.b. beim getValueAT, woher nimmt er jetzt nun die Daten? getValueAt heißt ja er soll die Daten von zeile 3 und spalte 4 z.b. holen, aber von wo soll er die holen, wenn noch keine Tabelle da ist?
Vielleicht erübrigt sich die Frage, wenn ich die Fragen oben beantwortet werden.


Ein 3tes Beispiel:

MainFrame.java:

```
package JTable_Demo;

import java.awt.*;

import javax.swing.*;

public class MainFrame extends JFrame {
  private JPanel contentPane;
  public static final int MAX_ROWS= 100;
  public static final int MAX_COLS= 6;
  private JTable myTable;
  public String[][] data = new String[MAX_ROWS][MAX_COLS];
	
  public MainFrame() {
    try {
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      FrameInit();
    }
    catch (Exception exception) {
      exception.printStackTrace();
    }
    
    
    for (int i = 0; i < MAX_ROWS; ++i) {
    	for (int j = 0; j < MAX_COLS; ++j)
    	data[i][j] = Integer.toString(i * MAX_COLS + j);
    }
    myTable= new JTable (new MyTableModel(MAX_ROWS, MAX_COLS, data));
    JScrollPane scrollpane = new JScrollPane(myTable);
    contentPane.add(scrollpane);
  }

  /**
   * Component initialization.
   *
   * @throws java.lang.Exception
   */
  
  
  private void FrameInit() throws Exception {
    contentPane = (JPanel) getContentPane();
    contentPane.setLayout(new BorderLayout());
    setSize(new Dimension(400, 300));
    setTitle("Frame Title");

  }
}
```

MyTableModel.java:

```
package JTable_Demo;

import java.awt.*;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;

public class MyTableModel extends AbstractTableModel {
	int row_cnt, col_cnt;
	public String[][] data = new String[row_cnt][col_cnt];
	String data1 [][];

	public MyTableModel(int rows, int cols, String data[] []) {
		row_cnt = rows;
		col_cnt = cols;
		data1 = data;
	}

	public int getColumnCount() {
		return col_cnt;
	}

	public int getRowCount() {
		return row_cnt;
	}

	public String getColumnName(int colnum) {
		return new String("Spalte " + (colnum + 1));
	}

	public Object getValueAt(int row, int col) {
		return data1[row][col];
	}

}
```

Der Einzige Unterschied vom dem hier zum 2ten Beispiel in Post #1 ist, dass bei getValueAt ein Array verwendet wird, dass im MainFrame erzeugt wird.

Aber was macht das für einen Unterschied? Ausgabe ist ja gleich. Aber die Rechnung in Bsp2 bei getValueAt ist mir noch nicht ganz klar.


----------



## zerix (27. Oktober 2013)

Da ich gerade etwas beschäftigt, habe ich deinen Text nicht ganz gelesen. 
Was ich rausgelesen habe ist, dass du nicht weißt, wie die JTable mit dem TableModel zusammenarbeitet. 

Das ist eigentlich recht einfach.

Man muss der Tabelle ein TableModel geben. (setModel oder Konstruktur)
Tut man dies nicht nutzt die Tabelle ein Objekt der  Klasse DefaultTableModel.

Die Tabelle selbst hat keine Ahnung, wieviele Spalten oder Zeilen sie anzeigen soll, sie weiß auch nicht was in den Zellen drin steht. Da fragt sie das TableModel. 
Beispielsweise, wenn die Tabelle gezeichnet werden soll (also dargestellt wird), fragt sie das TableModel nach der Spalten- und Zeilenzahl (getRowCount, getColumnCount). Da sie jetzt weiß wie groß sie sein soll fragt sie das TableModel nach den Inhalten (getValueAt). Jedes mal, wenn sie das Ergebnis für eine Zelle hat, geht sie damit zum TableCellRenderer und gibt ihm die Daten und verlangt von ihm ein grafisches Objekt (meist JLabel). Damit hat die Tabelle ein grafisches Objekt für die jeweilige Zelle, welches sie nur noch an der richtigen Stelle zeichnet.

Wenn du jetzt selbst ein TableModel schreiben möchtest, musst du mindestens das Interface implementieren. Da viele Methoden da meistens gleich implementiert werden, wurde eine Klasse geschrieben, die das Interface schon implementiert und einige Methoden schon ausprogrammiert hat. Das wäre das AbstractTableModel. 
Hier sind nur noch nie Methoden zu implementieren, die meistens selbst implementiert werden. Natürlich kann man die anderen Methoden überschreiben. Mehr Parameter geben, funktioniert aber nicht, wie du es oben angedeutet hast.

Ich hoffe es ist jetzt etwas klarer geworden.

Viele Grüße

Sascha


----------

