Swing: JTable
Dieses Beispiel zeigt, wie ein JTable angelegt wird.
Das Projekt befindet sich unter "SwingJTable" in Gitlab: https://gitlab.cs.hs-rm.de/knauf/swt-ws19-knauf/tree/master/SwingJTable
Der Code ist auch hier zu finden: SwingJTable.zip
Erzeugen der Tabelle
Wie bei der JList aus dem vorherigen Tutorial muss auch hier zuerst ein "Scroll Pane" auf dem Fenster platziert werden. Auf dieses wird ein "Table" gesetzt:
Ich konnte die erzeugte Tabelle im Designer nachträglich nicht mehr anklicken, es wurde immer das ScrollPane ausgewählt.
Lösung: links unten befindet sich ein Fenster "Navigator". Dort kann man sich durch die Control-Hierarchie klicken und dort die Tabelle auswählen. Jetzt ist sie im Designer-Fenster gewählt und auch rechts
unten in den Properties.
Befüllen der Tabelle
Ich will in der Tabelle Objekte vom Typ Student
anzeigen, wobei die Spalten "Matrikelnummer", "Nachname" und "Vorname" angezeigt werden sollen.
Wie beim vorherigen ComboBox- und List-Beispiel wurde ein Default-Model generiert, das uns hier nur stört.
Hier der Auszug aus initComponents
:
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null, null, null},
{null, null, null, null},
{null, null, null, null},
{null, null, null, null}
},
new String [] {
"Title 1", "Title 2", "Title 3", "Title 4"
}
));
Dieser generierte Code zeigt, wie man ein Model auf Basis eines zweidimensionalen Arrays erzeugen kann.
Dieses Model muss zuerst zurückgesetzt werden. Dazu die Tabelle wählen und in den Properties bei "model" per
Rechtsklick die Funktion "Restore Default Value" aufrufen. Die gleiche Funktion habe ich im CombBox-Beispiel über den Ellipsis-Button des "Properties"-Fensters erreicht.
Jetzt legen wir uns ein eigenes TableModel an, das eine Liste von Student
-Objekten enthält.
public class TableModelStudent extends javax.swing.table.AbstractTableModel {
private List<Student> studenten;
public TableModelStudent(List<Student> studenten) {
this.studenten = studenten;
}
public Student getStudentAt (int index)
{
return this.studenten.get(index);
}
Die Klasse ist eine Subklasse von javax.swing.table.AbstractTableModel
. Im Konstruktor wird ihr eine Liste von Studenten übergeben - man könnte sie aber auch mit einer Methode
setStudenten
von außen setzen. Außerdem habe ich die Methode getStudentAt
zugefügt - diese wird weiter unten beim Abrufen der Auswahl nötig sein.
Wir müssen diverse Methoden aus AbstractTableModel
implementieren:
@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Matrikelnummer";
case 1:
return "Nachname";
case 2:
return "Vorname";
default:
throw new IllegalArgumentException("Spaltenindex " + column + " ist ungültig");
}
}
@Override
public int getRowCount() {
return this.studenten.size();
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public java.lang.Class<?> getColumnClass(int column) {
switch (column) {
case 0:
case 1:
case 2:
return String.class;
default:
throw new IllegalArgumentException("Spaltenindex " + column + " ist ungültig");
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Student studi = this.studenten.get(rowIndex);
switch (columnIndex) {
case 0:
return studi.getMatrikelnummer();
case 1:
return studi.getNachname();
case 2:
return studi.getVorname();
default:
throw new IllegalArgumentException("Spaltenindex " + columnIndex + " ist ungültig");
}
}
Diese Methoden werden allesamt vom JTable
aufgerufen, um die Tabelle zu befüllen.
Im Detail:
getRowCount
liefert die Anzahl an Tabellenzeilen (also die Anzahl an Studenten in der Liste)
getColumnCount
liefert die Anzahl an Tabellenspalten - hier fest "3"
getColumnName(index)
liefert den Spaltennamen (bzw. den Anzeigetext in der Titelzeile) zurück.
getColumnClass(index)
liefert den Datentyp für die Werte einer Spalte zurück. Hier habe ich nur String-Werte.
getValueAt(row, column)
liefert den Wert für eine Tabellenzelle zurück. Hier muss anhand des Spaltenindex die entsprechende Property des Studenten abgerufen werden.
Dieses TableModel wird im Konstruktor meines Fensters erzeugt und in die Tabelle gesteckt:
ArrayList<Student> listData = new ArrayList<Student>();
Student stud1 = new Student();
stud1.setMatrikelnummer(1234567);
stud1.setVorname("Hans");
stud1.setNachname("Meier");
listData.add(stud1);
...
//Erzeugen des TableModell:
this.modelStudenten = new TableModelStudent(listData);
//Befüllen der Tabelle:
this.jTableStudenten.setModel(modelStudenten);
Auswahl
Ein JTable
unterstützt im Default Mehrfachauswahl (mit "Strg+Click" kann man beliebig viele Zeilen wählen). In den "Properties" kann z.B. auf Einfachauswahl umgestellt werden:
Das Beispielprogramm lauscht auf eine Auswahländerung der Tabelle und zeigt die gewählten Datensätze in einem Textfeld an. Für die Auswahländerung gibt es leider kein Event im JTable
, das
wir per Designer registrieren könnten. Stattdessen muss man das selbst programmieren:
this.jTableStudenten.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
jTableStudentenSelectionChanged(e);
}
});
Die Methode jTableStudentenSelectionChanged
sieht so aus:
private void jTableStudentenSelectionChanged (ListSelectionEvent e)
{
String studentenSelected = "";
int[] selectedRows = this.jTableStudenten.getSelectedRows();
for(int rowSelected : selectedRows)
{
Student student = this.modelStudenten.getStudentAt(rowSelected);
if (studentenSelected.length() > 0)
{
studentenSelected += ", ";
}
studentenSelected += student.toString();
}
this.jTextFieldSelected.setText(studentenSelected);
}
Der JTable
liefert uns nur die gewählten Zeilen-Indizes (getSelectedRows
). Anhand dieser Indizes müssen wir die Studenten aus dem Model holen (über getStudentAt
).
Umgekehrt können wir die Auswahl so setzen (das macht der Button "Müller wählen"):
//...Student namens "Müller" in TableModel suchen...
this.jTableStudenten.getSelectionModel().setSelectionInterval(indexMueller, indexMueller);
Stand 27.11.2019
Historie:
22.11.2019: Erstellt
27.11.2019: Screenshot für SelectionMode korrigiert.