Spaltennamen jeweils der angezeigten Tabelle anpassen

tsitra

Bekanntes Mitglied
Hallo allerseits,

Die Situaton:
Über eine JComboBox löse ich jeweils einen Zugriff auf
die entsprechend ausgewählte MySQL-Tabelle aus, erhalte eine ResultSet, lese es aus,
und je nach Tabelle mit entsprechende Spalten und deren Datentypen
rufe ich dann verschiedene dtm.setValueAt(...) auf einem DefaultTableModel-Objekt
namens dtm z.B.:
Java:
dtm.setValueAt(Integer.parseInt(rs.getString("pk_ArtId")), row, 0);
auf um die daten aus dem ResultSet in die JTable zu kriegen.
Mein Code, konkret setValueAt(...) Aufrufe, sind also auf die Datentypen der einzelnen Tabellen
angepasst.

Das klappt soweit gut, jedenfalls macht es einen guten Eindruck, denn die
Daten aus den verschiedenen Tabellen werden schön in die JTable eingetragen und angezeigt.
Aber die Spaltennamen bleiben konstant, also unpassend
Wie kann ich jetzt dafür sorgen, dass auch die Tabellenzeilen passen?
Ich nehme an, dass ich die auch "zu Fuss" anpassen muss!
Aber wie gehe ich da ran?
Wie aktualisiere ich jetzt am einfachsten die Tabellenzeilen?
Sind die eigentlich im ResultSet mit drin? Muss ich die da "rausholen"?

-----------------------------
Exkurs Start:
Mit dem DefaultTableModel habe ich mich schon etwas beschäftigt, aber
so ganz klar ist mir das nicht.
Generell seltsam ist es halt schon:
Es geschieht soviel implizit, also automatisch im Hintergrund, dass
es schwierig ist den Überblick zu behalten.
getColumnCount() kann auch explizit auf TabelModel-Objekt aufgerufen werden.
Aber der Aufruf ist getColumnCount() irgendwie automatisch, bzw. unsichtbar im Hintergrund:
Wenn im Programmcode nur eine DEFINITION von getColumnCount() zu finden ist und
kein expliziter Aufruf so erfolgt ein Aufruf dennoch!

Aufruf ist setValueAt(...) kann explizit auf TabelModel-Objekt aufgerufen werden.
Wird aber zusätzlich noch irgendwie automatisch, bzw. unsichtbar im Hintergrund
aufgerufen, wenn ein Wert einer Zelle geändert wird und der Mauszeiger die Zelle verlässt.
Im Programmcode nur diese DEFINITION von getColumnCount() zu finden, aber nichts
was auf einen Aufruf von setValueAt(...)hindeutet.
Exkurs Ende
-------------------------------------------

So wird das DefaultTableModel-Objekt dtm als Inner class da innerhalb ActionPerformed()
erezugt.
DefaultTableModel dtm = new DefaultTableModel(new String[] {"A","B","C","D","E","F","G"}, 2) {...}

-----------------------------------------------------------
Zur Zeit habe ich, egal welche Tabelle angezeigt wird, immer die Spalten "A","B","C","D","E","F","G.

Muss ich mit public String getColumnName(int columnIndex){ ...} etwas machen,
um die Spaltennamen der jeweils angezeigten Tabelle anzupassen?

Viele Grüße,
tsitra
 

Michael...

Top Contributor
Java:
dtm.setValueAt(Integer.parseInt(rs.getString("pk_ArtId")), row, 0);
auf um die daten aus dem ResultSet in die JTable zu kriegen.
Heisst das Du befüllst die Tabelle Zelle für Zelle? Das erzeugt eine Menge Akutalisierungsaufwand bei der JTable.
Wie kann ich jetzt dafür sorgen, dass auch die Tabellenzeilen passen?
Ich nehme an, dass ich die auch "zu Fuss" anpassen muss!
Bedarf genauerer Erläuterung? Anzahl der Zeilen oder was ist nicht passend?
Aber der Aufruf ist getColumnCount() irgendwie automatisch, bzw. unsichtbar im Hintergrund
wird z.B. von der JTable aufgerufen, um an die Zeilenanzahl des Models zu kommen.
Aufruf ist setValueAt(...) kann explizit auf TabelModel-Objekt aufgerufen werden.
Wird aber zusätzlich noch irgendwie automatisch, bzw. unsichtbar im Hintergrund
aufgerufen, wenn ein Wert einer Zelle geändert wird und der Mauszeiger die Zelle verlässt.
setValueAt(...) ist die Methode mit der ein Editor Daten eine Tabelle manipuliert. Das passiert also auch nicht "unsichtbar", sondern sie wird vom jeweiligen Editor über die JTable am Model aufgerufen.
Zur Zeit habe ich, egal welche Tabelle angezeigt wird, immer die Spalten "A","B","C","D","E","F","G.

Muss ich mit public String getColumnName(int columnIndex){ ...} etwas machen,
um die Spaltennamen der jeweils angezeigten Tabelle anzupassen?
Das wäre eine Möglichkeit die Methode des TableModel entsprechend zu überschreiben. DefaultTableModel besitzt Methoden, um die Spaltennamen neu zu setzen.

Generell ist JTable und das Zusammenspiel zwischen TableModel, Renderen und Editoren ein recht komplexes Thema. Für etwas komplexere Anwendungen macht es Sinn sich ein eigenes TableModel zu schreiben.
 

tsitra

Bekanntes Mitglied
Verzeiht, bitte, ich habe geschlampt.

Ich (tsitra) schrieb:
"Wie kann ich jetzt dafür sorgen, dass auch die Tabellenzeilen passen?
Ich nehme an, dass ich die auch "zu Fuss" anpassen muss!"

Bedarf genauerer Erläuterung? Anzahl der Zeilen oder was ist nicht passend?

Sollte statt "Tabellenzeilen", "Tabellenspalten" heißen!
 

tsitra

Bekanntes Mitglied
Danke, Michael.

Erstmal muss wohl noch etwas geklärt werden, denn ich weiß immer noch nicht wie es gehen soll.

Heisst das Du befüllst die Tabelle Zelle für Zelle? ...

Ja, ist wohl so, denn beim Durchlauf des ResultSet, wo auch die (wie) dtm.setValueAt(Integer.parseInt(rs.getString("pk_ArtId")), row, 0);
sind ist auch row++;

setValueAt(...) ist die Methode mit der ein Editor Daten eine Tabelle manipuliert. Das passiert also auch nicht "unsichtbar", sondern sie wird vom jeweiligen Editor über die JTable am Model aufgerufen.

In welcher .java-Datei des Java-Framework ist denn dieser Aufruf notiert?

Gruß
tsitra
 

hdi

Top Contributor
In welcher .java-Datei des Java-Framework ist denn dieser Aufruf notiert?

JTable.java - an diversen Stellen:
Source for javax.swing.JTable (GNU Classpath 0.95 Documentation)

Was Michael angesprochen hat mit dem Editieren steht in Zeile 2910++ (editingStopped)

Du darfst übrigens die Methode JTable#setValueAt nicht mit TableModel#setValueAt verwechseln. JTable wrappt da quasi drüber.

Muss ich mit public String getColumnName(int columnIndex){ ...} etwas machen,
um die Spaltennamen der jeweils angezeigten Tabelle anzupassen?
Ja, du musst ein passendes TableModel implementieren:

Java:
class MyTableModel extends DefaultTableModel{

     // override von getColumnCount(), getColumnName(), usw usw siehe Interface TableModel
}
 
Zuletzt bearbeitet:

tsitra

Bekanntes Mitglied
Ja, du musst ein passendes TableModel implementieren:
Java:
class MyTableModel extends DefaultTableModel{
     // override von getColumnCount(), getColumnName(), usw usw siehe Interface TableModel
}

Wie bereits berichtet verwende ich eins.

Java:
class clsTableModel extends DefaultTableModel{
...
 String[] spaltenNamen = {"A","B","C","D","E"};// Diese werden genommen als Tabellenspalten-Bezeichner
...
   public String getColumnName(int columnIndex){ //gemaeß Spaltenanzhl mehrfach Aufruf:
            return spaltenNamen[columnIndex];
        }
...}
            clsTableModel tableDao = new clsTableModel();

Müsste ich dann den String-Vektor "spaltenNamen" irgendwie gemäß der neu angelieferten Tabellenspalten anpassen, oder wie?

-----------
Welche Rolle spielt void setColumnIdentifiers(Object[] newIdentifiers) ?

Gruß
tsitra
 

hdi

Top Contributor
Wenn du dir das aus dem Model (zB über getColumnCount()) ableiten kannst*, wäre das wohl das einfachste. Wenn nicht, reicht ein TableModel alleine nicht mehr aus. Du brauchst nur eine JTable, das hast du auch korrekt überlegt, aber du solltest nicht verschiedene (logische) Tabellen in ein Model zwängen. Also mach dir einfach mehrere TableModels und wechsle die einfach per table.setModel().

*edit: Was du wohl nicht kannst, weil du dafür ja wahrscheinlich auch deine statiche Variable spaltenNamen(.length) verwendest?!
 

tsitra

Bekanntes Mitglied
.... aber du solltest nicht verschiedene (logische) Tabellen in ein Model zwängen. Also mach dir einfach mehrere TableModels und wechsle die einfach per table.setModel().
...

Hallo,
das könnte eine gute Idee sein doch ich habe gerade eben in eine andere Richtung experimentiert
und habe den Eindruck fast die Spaltenbezeichner auch in der JTable ändern zu können.
In dem DefaultTableModel Objekt "objDefTablMod" habe ich sie DURCH .setColumnIdentifiers(ob1)
IMMERHIN schonmal geändert, doch jetzt muss das nur noch auf der JTable auf der GUI erscheinen.
Wie geht das?

Muss dazu nochmal eine Art refresh gemacht werden?

Java:
clsTableModel objDefTablMod = new clsTableModel();
JTable table1 = new JTable(objDefTablMod);// 

// Hier die alten Werte, die über ein String[] spaltenNamen = {"....} innerhalb der DefaultTableModel-class gesetzt werden
System.out.println("1 objDefTablMod.getColumnName(0) : "+objDefTablMod.getColumnName(0));
System.out.println("1 objDefTablMod.getColumnName(1) : "+objDefTablMod.getColumnName(1));
System.out.println("1 objDefTablMod.getColumnName(2) : "+objDefTablMod.getColumnName(2));

 // Hier werden neue  Spaltennamen gestzt         
            Object [] ob1 = {"Apfel","Birne","Citrone","Dattel","Erdbeere"};
            objDefTablMod.setColumnIdentifiers(ob1); //  geht!
// Kontroll-TEST: Es weden die nun die ersten drei aus Object [] ob1 geliefert:
System.out.println("objDefTablMod.getColumnName(0) : "+objDefTablMod.getColumnName(0));
System.out.println("objDefTablMod.getColumnName(1) : "+objDefTablMod.getColumnName(1));
System.out.println("objDefTablMod.getColumnName(2) : "+objDefTablMod.getColumnName(2));

Viele Grüße
tsitra
 

Michael...

Top Contributor
IMMERHIN schonmal geändert, doch jetzt muss das nur noch auf der JTable auf der GUI erscheinen.
Wie geht das?

Muss dazu nochmal eine Art refresh gemacht werden?
Wenn Du ein DefaultTableModel verwendest ist dieser "refresh" schon implementiert und die Spaltennamen sollten direkt in der JTable angezeigt werden.
Denn das DefaultTableModel feuert bei Änderungen an Daten oder Spaltennamen ein entsprechendes Event an alle Listener zu denen auch die JTable gehört.
 

tsitra

Bekanntes Mitglied
Hallo Michael, und Danke.

diese Zeilen aus meinem code
Java:
class clsDefTableModel extends DefaultTableModel{...}
...
clsDefTableModel objDefTablMod = new clsDefTableModel();
...
JTable table1 = new JTable(objDefTablMod);
bewirken wohl, dass ein DefaultTableModel korrekt verwendet wird, oder?

Leider kann ich Deine Einschätzung
...die Spaltennamen sollten direkt in der JTable angezeigt werden...
nicht bestätigen!

Ich habe dann nochmal aus Ratlosigkeit, bestimmt redundant, nochmal dahinter (siehe voriger post)
table1.setModel(objDefTablMod); plaziert, was aber auch nicht
dazu führte, dass diese neuen Spaltennamen in der JTable auf der GUI zu sehen waren.

Mir stellt es sich dar, als ob nur in dem DefaultTableModel-Objekt objDefTablMod
die Spaltennamen

(das ging offenbar mit
Java:
Object [] ob1 = {"Apfel","Birne","Citrone","Dattel","Erdbeere"};
            objDefTablMod.setColumnIdentifiers(ob1);
)

geändert werden, aber das NICHT in die JTable auf die GUI übertragen wird.

Viele Grüße

tsitra
 

tsitra

Bekanntes Mitglied
Wenn Du ein DefaultTableModel verwendest ist dieser "refresh" schon implementiert und die Spaltennamen sollten direkt in der JTable angezeigt werden.
Denn das DefaultTableModel feuert bei Änderungen an Daten oder Spaltennamen ein entsprechendes Event an alle Listener zu denen auch die JTable gehört.
Daraus nochmal speziell diese Äußerung:
...das DefaultTableModel feuert bei Änderungen an Daten oder Spaltennamen...

Also auch dann bei Änderungen an dem String-Array "spaltennamen" , wenn, wie bereits erwähnt, das String-Array "spaltennamen" innerhalb des DefaultTableModel deklariert ist?

Java:
 class clsDefTableModel extends DefaultTableModel{
...
 String[] spaltenNamen = {"A","B","C","D","E"}; 
...
}

Fakt ist, dass ich die Werte in "spaltenNamen" von außerhalb erfolgreich ändere, das auch überprüfe
und TROTZDEM NICHTS in der entsprechenden assoziierten JTable zu sehen ist.

"Michael..." meinte ja, dass ich die neuen Spaltennamen auch auf der JTable SEHEN MÜSSTE
und sowas wie ein "refresh" nicht notwendig ist.
Mache ich was verkehrt?
Gruß
tsitra
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Also bei mir werden, wenn ich in folgendem Code den Button drücke die Spaltennamen (einmalig) ausgetauscht und in der JTable angezeigt. Einzig durch den Aufruf der Methode
Code:
setColumnIdentifiers(...)
an einem
Code:
DefaultTableModel
. Eventuell hast Du mehrere Instanzen oder der Fehler liegt sonst irgendwo...
Java:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class ColumnIdentifierChange extends JFrame {
	private DefaultTableModel model;
	
	public ColumnIdentifierChange() {
		model = new DefaultTableModel(new String[] {"Alt A", "Alt B"}, 0);
		this.add(new JScrollPane(new JTable(model)), BorderLayout.CENTER);
		JButton button = new JButton("Change Identifier");
		this.add(button, BorderLayout.SOUTH);
		
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				model.setColumnIdentifiers(new String[] {"Neu A", "Neu B", "Ganzneu C"});				
			}
		});
	}
	
	public static void main(String[] args) {
		JFrame frame = new ColumnIdentifierChange();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 

tsitra

Bekanntes Mitglied
Hallo Michael...,
der eben von Dir gesendete Code klappt bei mir, tut also das was gewünscht ist:)
Auf den ersten Blick trifft er auch die Problemstellung...

Nur frage ich mich jetzt in wie weit der eben von Dir gesendete Code der gleiche ist,
oder zumindest prinzipiell, also in wesentlichen Merkmalen, gleich ist.???:L

Der code von Dir ist sehr kurz und effizient gefasst.
Du nimmst ein direktes vordefiniertes DefaultTableModel-Objekt
und nimmst einen speziellen Konstruktor der die Spaltennamen über einen Parameter entgegennimmt:
Java:
model = new DefaultTableModel(new String[] {"Alt A", "Alt B"}, 0);

Ich verwende hingegen ein indirektes DefaultTableModel-Objekt objDefTablMod
Java:
clsDefTableModel objDefTablMod = new clsDefTableModel();
mit
class clsDefTableModel extends DefaultTableModel{...

Innerhalb dieser clsDefTableMode ist, wie erwähnt, das
String[] spaltenNamen = {"A","B","C","D","E"}; für die Spaltennamen
Kann das eine Rolle spielen?

Gruß
tsitra
 

Michael...

Top Contributor
Innerhalb dieser clsDefTableMode ist, wie erwähnt, das
String[] spaltenNamen = {"A","B","C","D","E"}; für die Spaltennamen
Kann das eine Rolle spielen?
Warum speicherst Du die in einem eigenen Objekt Array? Das DefaultTableModel besitzt bereits ein Array bzw. Vector, um die Spaltennamen zu verwalten. Meiner Meinung spricht nichts dagegen diesen zu nutzen.

In Deinem Fall hast Du dann aber auch die
Code:
public String getColumnName(int column)
des DefaultTableModels überschrieben und die fertige Methode zum Ändern der Namen kann so nicht funktionieren. Falls man das wirklich so umsetzen will muss auch die zwei setColumnIdentifiers(...) und die zwei setDataVector(...) Methoden überschreiben. Per
Code:
fireTableStructureChanged()
wird die JTable dann darüber informiert, dass sich an der Struktur etwas geändert hat.
 

tsitra

Bekanntes Mitglied
Warum speicherst Du die in einem eigenen Objekt Array? Das DefaultTableModel besitzt bereits ein Array bzw. Vector, um die Spaltennamen zu verwalten. Meiner Meinung spricht nichts dagegen diesen zu nutzen.

Du meinst sicher "protected Vector columnIdentifiers"

In Deinem Fall hast Du dann aber auch die
Code:
public String getColumnName(int column)
des DefaultTableModels überschrieben und die fertige Methode zum Ändern der Namen kann so nicht funktionieren. Falls man das wirklich so umsetzen will muss auch die zwei setColumnIdentifiers(...) und die zwei setDataVector(...) Methoden überschreiben.... .

Das hatte ich gemacht, aber wohl nicht korrekt oder vollständig!?

Deine Antwort scheint mir sehr plausibel. Ich prüfe das mal und gebe später Rückmeldung.
(syntaktisch weiß ich sehr viel bzgl. Überschreiben von Meth., semantisch anscheinend wenig :oops:)

Viele Grüße
tsitra
 

André Uhres

Top Contributor
soll das so gemacht werden?
Java:
 TableColumnModel tcm = new TableColumnModel();
table1.setModel(tcm);

Die Übergabe geschieht entweder im Konstrutor:
[c]JTable(TableModel dm, TableColumnModel cm) [/c]
oder mit [c]setColumnModel(TableColumnModel columnModel) [/c]

Weitere nützliche Methoden: [c]TableColumnModel.addColumn[/c], [c]TableColumnModel.getColumn[/c], [c]TableColumn.setHeaderValue[/c], [c]TableColumnModel.removeColumn[/c], ...

Gruß,
André
 

tsitra

Bekanntes Mitglied
... Das DefaultTableModel besitzt bereits ein Array bzw. Vector, um die Spaltennamen zu verwalten. ...

Meinst Du "protected Vector columnIdentifiers" ?

... Falls man das wirklich so umsetzen will muss auch die zwei setColumnIdentifiers(...) und die zwei setDataVector(...) Methoden überschreiben...

Ich gehe mal, davon aus, dass Du es zwar umständlich und unnötig, aber doch für möglich
hälst ein sub-class von DefaultTableModel als Table-Model zu nutzen und damit dann
dynamisch die in der GUI angezeigten JTable Spaltennamen zu ändern.

Ich soll also die zwei setColumnIdentifiers(...) und die zwei setDataVector(...) Methoden
überschreiben!?

Soll ich in denen dann mein internes Array "String[] spaltenNamen = {...}"
mit den gewünschten Spaltennamen überschreiben, weil die überschriebene getColumnName()
bei mir so aus sieht? :

public String getColumnName(int columnIndex){
return spaltenNamen[columnIndex];
}

Gruß
tsitra
 

Ähnliche Java Themen

Neue Themen


Oben