Java Anwendungsentwicklung – Tag 4 von 10
Von Franz-Martin, CTO bei Java Fleet Systems Consulting
Schwierigkeit: 🟡 Fortgeschritten
Dauer: ~6-8 Stunden
Voraussetzungen: Tag 1-3 abgeschlossen
🗺️ Deine Position im Kurs
| Tag | Thema | Niveau | Status |
|---|---|---|---|
| 1 | Die Desktop-Ära: Warum GUIs? | 🟢 Grundlagen | ✅ Abgeschlossen |
| 2 | AWT & Swing Grundlagen | 🟢 Grundlagen | ✅ Abgeschlossen |
| 3 | Layouts & Event-Handling | 🟢 Grundlagen | ✅ Abgeschlossen |
| → 4 | Komplexe Swing-Komponenten | 🟡 Fortgeschritten | 👉 DU BIST HIER! |
| 5 | JavaFX: Die „moderne“ Alternative | 🔴 KOPFNUSS | 🔜 Kommt als nächstes |
| 6 | JDBC Grundlagen | 🟢 Grundlagen | 🔒 Gesperrt |
| 7 | JDBC Best Practices | 🟡 Fortgeschritten | 🔒 Gesperrt |
| 8 | JPA Einführung | 🟢 Grundlagen | 🔒 Gesperrt |
| 9 | JPA CRUD & Queries | 🟡 Fortgeschritten | 🔒 Gesperrt |
| 10 | Integration & Ausblick | 🔴 KOPFNUSS | 🔒 Gesperrt |
Legende: 🟢 Einsteiger-freundlich | 🟡 Erfordert Grundlagen | 🔴 Optional/Anspruchsvoll
⚡ Das Wichtigste in 30 Sekunden
Heute lernst du:
- ✅ JTable für tabellarische Daten
- ✅ Das Model-View-Konzept (wie React State!)
- ✅ DefaultTableModel vs. eigenes TableModel
- ✅ JTree für hierarchische Daten
- ✅ Selection Handling und Sortierung
Die Kernregel:
Trenne IMMER Daten (Model) von Darstellung (View)!
Das macht dein Code testbar, wiederverwendbar und sauber.
🟢 GRUNDLAGEN: JTable
Das Model-View-Konzept

Abbildung 1: Model und View sind getrennt – wie in React!
JTable funktioniert nach dem Model-View-Prinzip:
- Model (TableModel): Enthält die DATEN
- View (JTable): Zeigt die Daten AN
// Model = Daten
DefaultTableModel model = new DefaultTableModel();
model.addColumn("Name");
model.addColumn("Alter");
model.addRow(new Object[]{"Max", 25});
// View = Darstellung
JTable table = new JTable(model);
Warum ist das gut?
- Daten ändern → View aktualisiert automatisch
- Model ist testbar ohne GUI
- Sortieren/Filtern ohne Daten zu ändern
- Eine Datenquelle, mehrere Views möglich
💡 React-Entwickler aufgepasst: Das ist genau wie State und Komponente! Der State (Model) hält die Daten, die Komponente (View) rendert sie.
JTable mit DefaultTableModel
// Spalten definieren
String[] spalten = {"ID", "Name", "Alter"};
// Model erstellen
DefaultTableModel model = new DefaultTableModel(spalten, 0);
// Zeilen hinzufügen
model.addRow(new Object[]{1, "Max", 25});
model.addRow(new Object[]{2, "Lisa", 30});
// Tabelle erstellen
JTable table = new JTable(model);
// WICHTIG: In ScrollPane packen (für Header!)
add(new JScrollPane(table));
Wichtige JTable-Konfiguration
// Einzel-Selektion table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Zeilenhöhe table.setRowHeight(25); // Spalten nicht verschiebbar table.getTableHeader().setReorderingAllowed(false); // Spaltenbreiten table.getColumnModel().getColumn(0).setPreferredWidth(50); // Automatische Sortierung aktivieren! table.setAutoCreateRowSorter(true);
Selection Handling
table.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) { // Nur bei finaler Auswahl
int row = table.getSelectedRow();
if (row >= 0) {
// WICHTIG bei aktivem Sorter!
int modelRow = table.convertRowIndexToModel(row);
String name = (String) model.getValueAt(modelRow, 1);
System.out.println("Ausgewählt: " + name);
}
}
});
⚠️ WICHTIG: Bei aktiviertem RowSorter ist die View-Zeile nicht gleich der Model-Zeile! Immer
convertRowIndexToModel()verwenden!
🟡 PROFESSIONALS: Eigenes TableModel
Warum ein eigenes TableModel?
DefaultTableModel hat Nachteile:
- Verwendet
Object[][]– keine Typsicherheit - Schwer mit eigenen Klassen zu integrieren
- Keine Kontrolle über Datentypen
Lösung: Eigenes TableModel von AbstractTableModel ableiten!
public class ProduktTableModel extends AbstractTableModel {
private final List<Produkt> produkte = new ArrayList<>();
private final String[] spalten = {"ID", "Name", "Preis"};
// PFLICHT: Wie viele Zeilen?
@Override
public int getRowCount() {
return produkte.size();
}
// PFLICHT: Wie viele Spalten?
@Override
public int getColumnCount() {
return spalten.length;
}
// PFLICHT: Was steht in Zelle (row, col)?
@Override
public Object getValueAt(int row, int col) {
Produkt p = produkte.get(row);
return switch (col) {
case 0 -> p.getId();
case 1 -> p.getName();
case 2 -> p.getPreis();
default -> null;
};
}
// OPTIONAL aber empfohlen: Spaltenname
@Override
public String getColumnName(int col) {
return spalten[col];
}
// OPTIONAL aber WICHTIG: Datentyp pro Spalte
@Override
public Class<?> getColumnClass(int col) {
return switch (col) {
case 0, 1 -> String.class;
case 2 -> Double.class; // Für korrekte Sortierung!
default -> Object.class;
};
}
// OPTIONAL: Welche Zellen sind editierbar?
@Override
public boolean isCellEditable(int row, int col) {
return col != 0; // ID nicht editierbar
}
// Eigene Methode: Produkt hinzufügen
public void addProdukt(Produkt p) {
produkte.add(p);
fireTableRowsInserted(produkte.size()-1, produkte.size()-1);
}
}
Vorteile:
- ✅ Typsicherer Zugriff:
model.getProduktAt(row) - ✅ Korrekte Sortierung durch
getColumnClass() - ✅ Boolean zeigt automatisch Checkbox!
- ✅ Saubere Integration mit Domain-Objekten
🟢 GRUNDLAGEN: JTree
Hierarchische Daten darstellen

Abbildung 2: JTree für Baumstrukturen
// Wurzelknoten
DefaultMutableTreeNode root =
new DefaultMutableTreeNode("Projekt");
// Kindknoten
DefaultMutableTreeNode src =
new DefaultMutableTreeNode("src");
root.add(src);
// Blätter
src.add(new DefaultMutableTreeNode("Main.java"));
src.add(new DefaultMutableTreeNode("Utils.java"));
// JTree erstellen
JTree tree = new JTree(root);
add(new JScrollPane(tree));
Tree Selection Listener
tree.addTreeSelectionListener(e -> {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (node == null) return;
Object userObject = node.getUserObject();
System.out.println("Ausgewählt: " + userObject);
});
Lazy Loading (für große Bäume)
// Platzhalter beim Erstellen
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode("Laden..."));
}
// Beim Expandieren nachladen
tree.addTreeWillExpandListener(new TreeWillExpandListener() {
@Override
public void treeWillExpand(TreeExpansionEvent e) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode) e.getPath().getLastPathComponent();
// Echte Kinder laden...
}
@Override
public void treeWillCollapse(TreeExpansionEvent e) {}
});
💬 Real Talk: Nova und die 10.000 Zeilen
Java Fleet Büro, Donnerstagmittag.
Nova: „Franz-Martin, meine Tabelle ist MEGA langsam. 10.000 Zeilen, und das Scrollen ruckelt.“
Franz-Martin: „Zeig mal den Code.“
Nova:
for (Produkt p : produkte) {
Object[] row = {p.getId(), p.getName(), p.getPreis()};
model.addRow(row); // 10.000 mal!
}
Franz-Martin: „Da ist dein Problem. Jedes addRow() löst ein Event aus. 10.000 Events.“
Nova: „Und wie mache ich es richtig?“
Franz-Martin: „Zwei Optionen. Einfach: Alle Daten auf einmal setzen.“
Object[][] data = new Object[produkte.size()][3];
for (int i = 0; i < produkte.size(); i++) {
data[i] = new Object[]{...};
}
model.setDataVector(data, spaltenNamen);
Nova: „Und die bessere Option?“
Franz-Martin: „Eigenes TableModel. Dann gibt’s gar keine Kopie der Daten – die Tabelle fragt direkt deine Liste.“
Nova: „Aber das ist mehr Aufwand…“
Franz-Martin: „Einmal. Danach ist es schneller, sauberer und du hast volle Kontrolle.“
Nova: „Okay, ich probier’s.“
Eine Stunde später.
Nova: „Wow. Von 5 Sekunden auf instant. Und der Code ist auch schöner.“
Franz-Martin: (grinst) „Willkommen im Club der Leute, die ihre eigenen TableModels schreiben.“
✅ Checkpoint
📝 Quiz
Frage 1: Warum sollte man JTable IMMER in ein JScrollPane packen?
A) Für bessere Performance
B) Damit der Header (Spaltennamen) angezeigt wird
C) Für automatische Sortierung
D) Ist nicht nötig
Frage 2: Was macht table.convertRowIndexToModel(viewRow)?
A) Konvertiert den View-Index zum Model-Index (wichtig bei Sortierung!)
B) Sortiert die Tabelle
C) Konvertiert Datentypen
D) Löscht eine Zeile
Frage 3: Warum ist getColumnClass() in einem eigenen TableModel wichtig?
A) Für die Spaltenbreite
B) Für korrekte Sortierung und Darstellung (Boolean → Checkbox!)
C) Für die Hintergrundfarbe
D) Ist optional und unwichtig
Frage 4: Was ist der Hauptvorteil von Model-View-Trennung?
A) Schnellere Ausführung
B) Daten und Darstellung sind unabhängig – testbar und wiederverwendbar
C) Weniger Code
D) Bessere Farben
📝 Quiz-Lösungen
Frage 1: ✅ B – Damit der Header angezeigt wird
Ohne JScrollPane fehlt der Tabellenkopf mit den Spaltennamen!
Frage 2: ✅ A – Konvertiert View-Index zu Model-Index
Bei aktiviertem Sorter zeigt Zeile 0 in der View nicht unbedingt Zeile 0 im Model!
Frage 3: ✅ B – Für korrekte Sortierung und Darstellung
Double sortiert numerisch (1, 2, 10), String alphabetisch (1, 10, 2). Boolean zeigt Checkbox!
Frage 4: ✅ B – Unabhängig, testbar, wiederverwendbar
Du kannst das Model ohne GUI testen. Mehrere Views können dasselbe Model nutzen.
🎨 Challenge
🟢 Level 1 – Einfache Tabelle
- [ ] JTable mit 3 Spalten und 5 Beispielzeilen
- [ ] Sortierung aktivieren
- [ ] Bei Klick: Ausgewählte Zeile in Console ausgeben Zeit: 20-30 Minuten
🟡 Level 2 – CRUD-Tabelle
- [ ] Zeilen hinzufügen, bearbeiten, löschen
- [ ] Eingabefelder für neue Daten
- [ ] Bestätigung vor Löschen Zeit: 45-60 Minuten
🔵 Level 3 – Custom TableModel
- [ ] Eigene Klasse (z.B. Buch mit Titel, Autor, Jahr, Preis)
- [ ] Eigenes TableModel implementieren
- [ ] Boolean-Spalte „Gelesen“ mit Checkbox Zeit: 1-2 Stunden
📦 Downloads
| Projekt | Inhalt | Download |
|---|---|---|
| java-anwendungsentwicklung-tag4.zip | PersonenTabelle, DateiBrowser, CustomModel | ⬇️ Download |
Quick Start:
mvn exec:java # PersonenTabelle mvn exec:java -Ptree # DateiBrowser (JTree) mvn exec:java -Pcustom # Custom TableModel Demo
❓ FAQ
Wie mache ich Zellen nicht editierbar?
Im TableModel isCellEditable(row, col) überschreiben und false zurückgeben.
Meine Sortierung sortiert Zahlen falsch (1, 10, 2)?getColumnClass() implementieren und Integer.class oder Double.class zurückgeben!
Wie färbe ich bestimmte Zeilen?
Eigenen TableCellRenderer implementieren. Fortgeschrittenes Thema!
JTree ist langsam bei vielen Knoten?
Lazy Loading implementieren – Kinder erst laden wenn Knoten expandiert wird.
🔗 Weiterführende Links
| Ressource | Beschreibung |
|---|---|
| How to Use Tables | Oracle Tutorial |
| How to Use Trees | Oracle Tutorial |
| Custom TableModel | Eigenes Model |
🎉 Tag 4 geschafft!
Was du heute gelernt hast:
✅ JTable erstellen und konfigurieren
✅ Model-View-Trennung verstehen
✅ DefaultTableModel vs. eigenes TableModel
✅ JTree für hierarchische Daten
✅ Selection Handling und Sortierung
Morgen – Tag 5: JavaFX
Die „moderne“ Alternative zu Swing. CSS-Styling, FXML, Properties. Aber auch: Warum es sich nie durchgesetzt hat.
© 2025 Java Fleet Systems Consulting | java-developer.online

