TableModel auslesen => Bessere Implementierung möglich?

blub11

Mitglied
So da bin ich nochmal :D

Alsoooo..ich gebe über die GUI Aufträge ein (4 Spalten), die 1. Spalte ist ein String die restlichen drei sind ints.
Wenn ich diese jetzt aus dem Tablemodel auslesen möchte (um sie z.B. in einem neuen Auftrags-Objekt zu speichern, da sie noch weiterverarbeitet werden müssen), habe ich mir folgendes überlegt.

Was aber ziemlich hässlich ist.

Code:
auftraege.add(new Auftrag(eingabeTableModel.getValueAt(0, 0).toString(), 
                 Integer.parseInt(eingabeTableModel.getValueAt(0, 1).toString()), 
                 Integer.parseInt(eingabeTableModel.getValueAt(0, 2).toString()), 
                 Integer.parseInt(eingabeTableModel.getValueAt(0, 3).toString()) ));

Ich kann hier für die letzten drei "Auslesungen" keine for-Schleife benutzen, da die Werte ja direkt in ein neues Auftrags-Objekt in unterschiedliche Attribute kommen..

Gibst da was besseres? :)
 
Zuletzt bearbeitet:

schlagi123

Grünschnabel
Du kannst auch ein eigenes TableModel schreiben, bei dem es noch zusätzslich zu der Funktion getValueAt(int,int) weitere Funktionen wie z.B. getInt1AtRow(int), getInt2AtRow(int),...
 

Akeshihiro

Erfahrenes Mitglied
Oder man geht die Sache sinnig an und implementiert ein eigenes TableModel, das mit solche Sachen umgehen kann. Ich benutze dafür eigentlich immer das DefaultTableModel als Grundlage, dann muss ich nicht alles neu machen. Man muss dem neuen TableModel dann einfach beibringen mit neuen Datenstrukturen zu arbeiten, wie eigenen Klassen. Das würde sich auch hier anbieten.

Die Klasse bekommt die Eigenschaften, die man braucht (in diesem Fall ein String und drei int-Werte) und muss dem TableModel dann beibringen, wie es damit umzugehen hat, sprich welcher Wert kommt wohin. Und genauso einfach kann man dann auch gleich das komplette Objekt wieder rausholen, das für Zeile x zuständig ist. So spart man sich dieses ganze Herumgeparse und hat auch noch eine saubere Grundlage, mit der man super arbeiten kann.
 

blub11

Mitglied
Könntest du das vielleicht noch mal ein wenig konkretisieren? Soll ich diesen Code verallgemeinern und in das TableModel als eigene Methode hineinschreiben, die dann jede Zeile aus dem Tablemodel ausliest und ein Auftrag returned? (Was ja schon so ungefähr in meinem ersten post steht, halt nur auf die erste Zeile bezogen..)
Wie soll ich mir das geparse sparen? (getValueAt returned ja immer ein Object..natürlich könnte ich die Methode überschreiben..). Stehe grad nen bisschen aufm Schlauch..
 

Akeshihiro

Erfahrenes Mitglied
Hmm... Ja, das Problem ist ja, dass ich gar nicht weiß, was du da eigentlich vorhast. Aber das hier
Java:
auftraege.add(new Auftrag(eingabeTableModel.getValueAt(0, 0).toString(), 
Integer.parseInt(eingabeTableModel.getValueAt(0, 1).toString()), 
Integer.parseInt(eingabeTableModel.getValueAt(0, 2).toString()), 
Integer.parseInt(eingabeTableModel.getValueAt(0, 3).toString()) ));
könnte so aussehen:
Java:
auftraege.add(eingabeTableModel.getAuftrag(0));
Die Idee dahinter ist die, dass das TableModel selber weiß welche Daten wie aussehen, welchen Typ sie haben und wie diese zu verarbeiten sind. Die einfachste Form mit dem TableModel zu arbeiten wäre also diesem als Input einen Auftrag zu geben und das TableModel weiß selber, was es damit anstellen soll. Genauso auch der umgekehrte Weg. Man sagt dem TableModel, man will den Auftrag in der Zeile XY und das TableModel liefert den entsprechenden Auftrag. Das ganze Geparse usw. fällt weg, man hat weniger Stress, muss sich kein Kopf drum machen, der Code ist deutlich lesbarer, sauberer und wesentlich besser wartbar, da man dann bei Änderungen (z.B. weil eine Spalte einen anderen Datentyp hat) nicht mehr an zig Stellen die Änderungen nachimplementieren muss, sondern nur im TableModel.

Das Scheint sich ja noch auf den anderen Thread zu beziehen und da habe ich dir ja geschrieben, dass man Tabellen üblicherweise nur zur Darstellung nutzt und meist nicht um diese als Input-Schnittstelle zu nutzen. Es kommt aber auch drauf an. Kann sein, dass es in deinem Fall auch Sinn macht.

Ich muss gestehen, ich hab gerade etwas wenig Lust das alles nochmal zu machen. Ich habe bereits in diesem Beitrag ein gutes Beispiel angehängt. Die Jar-Datei kannst du runterladen und testweise ausführen (ist nicht mein Projekt). In der Jar sind auch die Sources enthalten, also einfach entpacken und reinschauen. Am interessantesten ist für dich die Klasse MitarbeiterTableModel. Da ist das implementiert, was ich dir vorhin gesagt hab, nur eben mit einer Mitarbeiter-Klasse. Und in der Klasse DialogMitarbeiterEinfuegen kannst du dann sehen, wie einfach es ist mit so einem TableModel umzugehen.

Du kannst auch den ganzen Thread lesen, ist sicherlich auch interessant. Es kann aber auch sein, dass das zu oversized ist für deinen Fall. Wie gesagt, ich weiß nicht, was du da machst.
 
Zuletzt bearbeitet:

blub11

Mitglied
Ja danke für deine Hilfe, so habe ich mir das jetzt auch vorgestellt..die Methode dann einfach in das TableModel zu integrieren.
Jedoch brauch ich den ganzen Aufruf nur 1x...also würde außer der "Schönheit" & evtl. Erweiterbarkeit wegen keinen Unterschied machen, ob sie nun innerhalb des TablesModels oder außerhalb ist. Hab ich ja nicht erwähnt :p, packe sie trotzdem ins Model mit rein..

Aaaaber wenn ich sie im TableModel integriere:

Code:
class MyTableModel extends DefaultTableModel{
........
public Auftrag getAuftrag(int row){
          new Auftrag(tableEingabeModel.getValueAt(row, 0).toString(),
                        Integer.parseInt(tableEingabeModel.getValueAt(row, 1).toString()), 
                        Integer.parseInt(tableEingabeModel.getValueAt(row, 2).toString()), 
                        Integer.parseInt(tableEingabeModel.getValueAt(row, 3).toString()) ));
}
.......
}
Wie kann ich mir das Geparse sparen?(Oder meintest du das "wiederholte" Parsen, falls ich dieses Codestück noch öfter in meinem Code (redundant) erwähnen würde? - was natürlich das DRY-Prinzip verletzen würde..)
 

Akeshihiro

Erfahrenes Mitglied
Kompilier den Code mal ^^ Ich fürchte, das wird nicht so ganz klappen.

Es ist nich egal, ob es innerhalb oder außerhalb des TableModels steht. Sowas nennt man Kapselung und geht weit über Schönheit hinaus und das sollte auch so oft wie möglich angewandt werden. Du wirst mit der Zeit lernen, dass eine modulare Programmierung sehr sinnvoll ist, denn dann kann jedes Modul als Blackbox betrachtet werden, die ein Input bekommt und auch ein Output liefert. Die Aufgaben, die ein Modul zu erledigen hat, sollten von dem Modul erledigt werden und nicht irgendwo Außerhalb.

Und das mit dem Parsen sparst du dir im Grunde bereits, weil das nur im TableModel stattfindet und sonst nirgends. Aus deinem ersten Post habe ich nämlich nicht herausgelesen, dass dafür eine separate Methode implementiert wurde und ging daher davon aus, dass das überall so aussieht. Wobei du selbst dabei nix parsen musst. Das sind int-Werte und die gehen nicht verloren, sondern sind in dem Fall nur in Form des Object-Datentyps vorhanden, weil getValue() Object als Rückgabetyp hat. Von dem Objekt rufst du die Methode toString() auf. In dem Fall geht das gut, in vielen anderen Fällen aber nicht, denn toString() liefert nicht immer das, was man erwarten könnte. Richtig wäre eigentlich ein Cast in den jeweils gebrauchten Datentyp, in dem Fall int.
 

blub11

Mitglied
Jaaa statt "tableEingabeModel" natürlich "this"..habe das nur kurz ausm Gedächtnis hier aufgeschrieben ;). Auf die Datenkapselung muss ich noch besser aufpassen.
Nein, das sieht nicht überall so aus :), das wär ja schlimm! War aber auch natürlich mein Fehler, das unerwähnt zu lassen.

Gut, dann mache ich einfach nur einen direkten Cast in die entsprechenden Datentypen ohne .toString().

Ich danke dir für das Strapazieren deiner grauen Zellen meinerseits ;)