# komplette Objekte in JTable einfügen



## Ratzer (6. Sep 2011)

Hallo!
Ich habe ein Problem mit JTables und zwar sieht mein TableModel bisher so aus, dass ich alle Eigenschaften des Objekts der addRow Methode übergebe und dann anzeigen lasse. Jetzt habe ich aber eine Eigenschaft, die nicht als Wert in die JTable gezeichnet werden soll, sondern welche einfach unsichtbar vorhanden sein müsste, damit ich darauf zugreifen kann. Also bisher siehts so aus:

```
public void addRow(Objekt o) {		
	addRow(new Object[]{o.getEigenschaft1(), o.getEigenschaft2(), o.getEigenschaft3()});
}
```
Jetzt habe ich aber noch ein int-Array, welches ich irgendwie durch Zugriff auf das JTable auslesen muss. Wie könnte das gehen, wenn von dem int-Array nichts in der Tabelle drin steht?


----------



## Marco13 (6. Sep 2011)

Manche Leute wollen einfach nur die Antwort. Falls das hier auch der Fall ist, ignorier' diesen Post.

Das macht keinen Sinn. Das TableModel beschreibt das, was in der Tabelle ist. Es ist nicht da, um irgendwelche (für die Table nicht relevanten) Daten "zwischenzuspeichern". Wenn es im Model steht, zeigt die Tabelle es auch an. Es klingt grob nach einer fehldenen Trennung zwischen eigenem Business-Modell und View (also JTable - auch wenn die selbst wieder ein Model enthält...). Beschreib' vielleicht mal, was dagegen spricht, die echten Objekte (einschließlich der int-Arrays) irgendwo so zu speichern, dass man dort, wo du jetzt auf deine "unsichtbaren" Daten zugreifen würdest, auch direkt auf die "echten" Daten zugreifen kann.


----------



## Ratzer (6. Sep 2011)

Naja, das, was in dem int-Array steht, ist schon für die Tabelle gedacht. In dem Array stehen Nullen und Einsen drin. Eine Eins bedeutet, dass für die Zelle der Rahmen eine andere Farbe bekommen soll. Ich wüsste gerade nicht, wie ich das anders machen könnte, anstatt es dem Objekt direkt mitzugeben und von da aus zur JTable.


----------



## Marco13 (6. Sep 2011)

Hm... wird diese Information dann an einen eigenen TableCellRenderer weitergereicht? Wie wird die da denn verwendet, bzw. wer erstellt, verwaltet und verwendet dieses Array allgemein?


----------



## Ratzer (6. Sep 2011)

Ja, das Array müsste dann vom TableCellRenderer verarbeitet werden. Darüber habe ich mir allerdings noch nicht so Gedanken gemacht. Vielleicht müsste ich das Array dann doch global machen, wenn es mit dem TableCellRenderer nicht funktionieren sollte.


----------



## Marco13 (6. Sep 2011)

Global klingt erstmal nicht gut  Ich meinte nur, dass wenn dieses Array vielleicht ohnehin schon z.B. direkt IN den Objekten liegen würde, und die Objekte vielleicht sowieso schon in einer Liste oder so, man evtl. sowohl das TableModel als auch den CellRenderer direkt auf diese Liste zugreifen lassen könnte. Mir ist bisher nicht klar, welche Rolle dieser Array hat. Ist das was rein visuelles, oder irgendeine Eingeschaft der Objekte, die sowieso schon irgendwo gespeichert ist?


----------



## Ratzer (6. Sep 2011)

Also meine Objekte haben verschiedene Strings und da können unter Umständen falsche Daten drinne stehen. In der Tabelle sollen diese Zellen dann rot markiert werden. Deswegen sollen die Objekte ein int-Array bekommen, in dem dann an mehreren Positionen i eine Eins stehen kann, was dann bedeutet, dass die Zelle beim Index "i" (wo eine Eins steht) rot gefärbt wird. Ich übergebe ja dem TableModel das komplette Objekt, das bedeutet aber nicht, dass der CellRenderer auch das komplette Objekte bekommt, oder?
Könnte man eventuell auch von meinem Objekt ein anderes Objekt ableiten, was z.B. die Schnittstelle "Colored" implementiert? Würde mir das helfen?


----------



## Marco13 (6. Sep 2011)

Nicht direkt. Dem TableModel wird ja nicht das Objekt selbst übergeben, sondern nur seine Eigenschaften (einzeln, als ein Array, der die neue Zeile ergibt). Der CellRenderer bekommt natürlich erstmal nur diese Werte, und weiß nicht mehr, zu welchem Objekt sie gehören. Das mit den Arrays ist mir aber immernoch nicht klar. 

Es gibt ähnliche Fälle, wo diese Entscheidung direkt im CellRenderer getroffen wird, im Sinne von

```
Component getCellRendererComponent(....Object value...)
{
    if (value==null) setBackground(Color.RED);
    else setBackground(Color.WHITE);
    ...
```
oder so... Aber vielleicht ist das hier nicht so direkt anwendbar. Du hättest also stattdessen eine Klasse

```
class SomeClass
{
    String getEigenschaft0() { ... }
    int getEigenschaft1() { ... }
    float getEigenschaft2() { ... }

    int[] getDiesesGültigkeitsDing() { ... }
}
```
und die Letzte Methode würde dann einen array wie [0,1,1] zurückgeben, wenn die Eigenschaften 1 und 2 "ungültig" sind? Das klingt irgendwie seltsam (mangels Information kann man aber nur sagen, dass es seltsam _klingt_, und nicht ob es das auch _ist_ - vielleicht ist es sinnvoll :bahnhof: ). Ist das so gedacht?


----------



## Ratzer (6. Sep 2011)

Ja, genauso ist das Array gedacht. Also ich brauche ja ein Tupel aus Zellenindex und Richtig/Falsch. Deswegen dachte ich mir, dass ein Array die beste Lösung ist. Der Arrayindex bezeichnet, welche Spalte gemeint ist und 0 sowie 1 stehen dann für Richtig/Falsch.


----------



## bERt0r (6. Sep 2011)

Hmm da würd ich sagen, du machst dir ein TableModel, dem übergibst du deine int-arrays mit den Fehlerhaften Zellen. 
Das TableModel speichert die in einer ArrayList und machst eine Methode getCellColor(int row,int col) die die Werte aus der ArrayList zurückgibt.
Deinem CellRenderer musst du wohl oder übel dein TableModel übergeben, und bei jedem getTableCellRendererComponent prüfst du mit getCellColor welche Farbe du benötigst.


----------



## Marco13 (7. Sep 2011)

Hmja, das wäre SEHR pragmatisch ... was mir da (so aus der Distanz) ein paar Bauchschmerzen macht, ist nicht zuletzt, dass da mit einem Array (was oft nicht gut ist) die Tabelle und die eigentlichen Daten vermischt werden. Oder anders gefragt: Wäre dieser Array auch in den Objekten, wenn sie NICHT in einer Tabelle angezeigt würden? Und... was passiert mit den Arrays, wenn jemand die Reihenfolge der Spalten in der Tabelle mal anders haben will....?!


----------



## bERt0r (7. Sep 2011)

Das Array habe ich als gegeben betrachtet, würde ich dahinter sitzen hätte ich das auch mit einer ArrayList gemacht. Also eine ArrayList<ArrayList<Boolean/Integer/Color>>.
Und ja, so wie ich das verstanden habe, gehört dieses Array zu diesem TableModel weil es eben genau für diesen Zweck (Anzeige der fehlerhaften Zellen) erstellt wurde. Dass das int array in der Datenhaltung, also den Objekten, gespeichert wird hab ich nie gesagt. Anzunehmen wäre, dass dieses ominöse int array entweder vom Objekt selbst oder irgendeinem Validator mit einer Funktion erzeugt wird.


----------



## Pepe Rohny (7. Sep 2011)

Hi,

ich hab' auch 'nen Vorschlag:
 - mach ein TableModel (Creating a Table Model) mit einer Liste (z. B. Vector) die die Daten-Objekte enthält - das TableModel enthält eine Methode namens getValueAt(int row, int col) die vom View (JTable) benutzt wird; dazu denn noch ein Custom Renderer (Using Custom Renderers) der ... aber das ist ja klar
 - erweiter die Daten-Klasse um eine HashMap die Tupel bestehend aus Tabellenkoordinate und Farbe enthält; der Custom Renderer kann dann hier die notwendige Information bekommen
'is nur so 'ne Idee von mir

Pepe

P.S.
es gibt vielleicht einen besseren Listen-Datentyp als Vector dem man einen Observer (Listener) anhängen kann. In dem Fall kann sich das TableModel als Observer an der Liste anhängen und Informationen bekommen, wenn sich die Liste verändert. Das TableModel informiert dann wiederum den View (JTable)


----------



## Ratzer (8. Sep 2011)

Mir ist noch folgendes eingefallen. Man könnte ja in der ersten Spalte der JTable mein ganzen Objekt ablegen, indem ich dem Objekt eine toString() Methode gebe, die dann genau den Wert ausspuckt, der in der ersten Spalte verlangt wird. Im CellRenderer hätte ich dann Zugriff auf das ganze Objekt und wüsste auch, welche Zellen fehlerhaft sind. Das Problem ist nur, dass der CellRenderer ja immer dann aufgerufen wird, wenn eine Zelle gerade gezeichnet wird. Was ist, wenn der Fehler in einer Zelle ist, die noch gar nicht vorhanden ist?


----------



## Pepe Rohny (8. Sep 2011)

Ratzer hat gesagt.:


> Was ist, wenn der Fehler in einer Zelle ist, die noch gar nicht vorhanden ist?



habe ich das richtig verstanden: du willst eine Tabelle aus nicht vorhandenen Daten/Zellen ... :noe:

Pepe


----------



## Ratzer (9. Sep 2011)

Um das hier jetzt mal aufzulösen. Ich habe nun einfach alle meine Eigenschaften zu Objekten gemacht. Vorher waren das entweder Strings oder einfach nur Ints. Nun ist auch ein "int" ein Objekt mit der zusätzlichen Eigenschaft, dass es eine boolesche Variable enthält, die angibt, ob fehlerhafte Daten in das Objekt eingegeben wurden. Das kann ich nun sehr einfach durch den CellRenderer abfragen.


----------



## Marco13 (9. Sep 2011)

WER entscheidet WANN auf welcher Basis, ob die Daten falsch oder richtig sind? Ändert sich das noch, nachdem die Daten in die Tabelle gelegt wurden?


----------



## Ratzer (10. Sep 2011)

Vor dem Erstellen eines Objekts wird direkt abgefragt, ob fehlerhafte Daten vorhanden sind und dann kriegt eine Eigenschaft des Objekts eben ein passendes Flag (boolean), was anzeigt, dass in dieser Eigenschaft ein Fehler ist. Es ist möglich, dass man die Daten nachträglich in der Tabelle korrigieren kann.


----------



## Marco13 (10. Sep 2011)

OK. Die Beschreibungen waren bisher dünn und schwammig, aber bisher klingt das für mich, als wäre es günstiger, NICHT dem OBJEKT selbst solche "Eigenschaften mit Flag" zu geben. 

Du hast jetzt also

```
class SomeClass
{
    public String getProperty0() { ... }
    public boolean isProperty0Valid() { ... }
```
geändert in

```
class SomeClass
{
    public StringWithBoolean getProperty0() { ... }
```

Und dann die "StringWithBoolean"-Objekte in die Table gelegt. Vielleicht wäre es günstiger, diese "StringWithBoolean"-Objekte nicht direkt im Objekt zu speichern, sondern lokal und anonym zu erstellen und in die Tabelle zu legen, sowas wie

```
public void addRow(final Objekt o) 
{      
    Object[] row = new Object[3];

    // Anonymes StringWithBoolean-Objekt erstellen, das die 
    // Aufrufe an das 'Objekt' weiterreicht
    row[0] = new StringWithBoolean() {
        public String getString() { return o.getEigenschaft1(); }
        public boolean getStringValid() { return o.getValid1(); }
    };
    ....
    addRow(row);
}
```

Ich finde, dass die Tatsache, dass das Objekt in einer Table dargestellt werden soll, keinen Einfluß auf die eigentliche Sruktur des Objektes haben sollte.


----------

