Falconbyte unterstüzen
Betrieb und Pflege von Falconbyte brauchen viel Zeit und Geld. Um dir auch weiterhin hochwertigen Content anbieten zu können, kannst du uns sehr gerne mit einem kleinen "Trinkgeld" unterstützen.
Schnelles Code-Beispiel
ListView<String> listview = new ListView<>();
listview.getItems().addAll("Eins", "Zwei", "Drei", "Vier");
VBox layout = new VBox();
layout.getChildren().addAll(listview);
Scene scene = new Scene(layout, 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
Inhaltsverzeichnis
Was ist eine ListView?
Mit dem JavaFX Control-Node ListView kannst du Objekte einer Datensammlung optisch in Listenform darstellen. Es wird durch die Klasse javafx.scene.control.ListView repräsentiert.
Im Gegensatz zu einem Menu ermöglicht die ListView sowohl eine Mehrfachauswahl als auch das Editieren der Elemente durch Doppelklick.
In JavaFX sieht eine ListView so aus:
ListView und ObservableList
Die einzelnen Elemente werden aber nicht in der ListView selbst gespeichert. Stattdessen ist in der ListView eine ObservableList verbaut, die für die eigentliche Verwaltung der einzelnen Elemente zuständig ist.
Die ListView ist dabei das GUI-Steuerungselement: Sobald über die ListView ein Element hinzugefügt, geändert oder gelöscht wird, erkennt das die ObservableList und führt die entsprechende Änderung dann auch tatsächlich in der Sammlung durch.
Insofern "überwacht" (engl. "observe") die ObservableList die ListView.
Die Klasse ListCell
Zur Darstellung der einzelnen Zellen und Repräsentation der Elemente aus der ObservableList verwendet die ListView die Klasse ListCell. Die jeweiligen ListCell-Objekte werden wiederum durch eine cell factory erstellt.
Die ListView im Einsatz
ListView erstellen
Die ListView ist eine generische Klasse. Das bedeutet, dass wir einen Typ-Parameter in spitzen Klammern angeben müssen. Der Typ-Parameter legt fest, welche Art von Elementen die ListView aufnehmen kann.
Für unser Beispiel wählen wir eine ListView aus Strings:
ListView<String>listview = new ListView<>();
Objekte hinzufügen
Mit der Methode add() lassen sich der Liste Elemente hinzufügen. Hier ein Beispiel:
listview.getItems().add("Eins");
listview.getItems().add("Zwei");
listview.getItems().add("Drei");
listview.getItems().add("Vier");
Mit der Methode addAll() kannst du Elemente in nur einer Anweisung hinzufügen:
listview.getItems().addAll("Eins", "Zwei", "Drei", "Vier");
Mehrfachauswahl aktivieren
Die ausgewählten Elemente werden von einem SelectionModel verwaltet. Dabei erlaubt die ListView auch die Auswahl von mehreren Elementen gleichzeitig (STRG auf Windows, CMD auf MacOS). Standardmäßig ist der Auswahlmodus (SelectionMode) aber auf SINGLE gestellt.
Um die Mehrfachauswahl zu aktivieren, holst du dir das SelectionModel mit getSelectionModel() und änderst den SelectionMode auf MULTIPLE:
listview.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Selektierte Elemente auslesen
Um die vom User selektierten Elemente auszulesen, rufen wir auf dem SelectionModel die Methode getSelectedItems() auf. Der Rückgabetyp der Methode ist eine ObservableList mit allen Elementen der Sammlung:
ObservableList<String> auswahl = listview.getSelectionModel().getSelectedItems();
Mit einer for-Schleife können wir nun durch die einzelnen Elemente iterieren. Hier der entsprechende Code inklusive einem Button, der das Prozedere in Gang setzt:
Button btn = new Button("Was ist ausgewählt?");
btn.setOnAction( e -> {
ObservableList<String> auswahl = listview.getSelectionModel().getSelectedItems();
for(String sV : auswahl){
System.out.println(sV);
}
});
Elemente editieren
Manchmal ist es praktisch, dass der User den gespeicherten Wert einer Zelle ändern kann:
Das lässt sich einfach umsetzen, indem wir zuerst die grundsätzliche Editierbarkeit der ListView einschalten. Anschließend müssen wir sicherstellen, dass die Cell Factory editierbare Zellen unterstützt:
listview.setEditable(true);
listview.setCellFactory(TextFieldListCell.forListView());
Bei einem Doppelklick kann der User nun der Text ändern und mit ENTER die Eingabe bestätigen. Die ObservableList checkt das sofort und aktualisiert die Sammlung automatisch.
Vollständiger Code
Hier der vollständige Code für unser Beispiel:
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class H1_ListView extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
ListView<String> listview = new ListView<>();
listview.getItems().addAll("Eins", "Zwei", "Drei", "Vier");
listview.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
listview.setEditable(true);
listview.setCellFactory(TextFieldListCell.forListView());
Button btn = new Button("Was ist ausgewählt?");
btn.setOnAction( e -> {
ObservableList<String> auswahl = listview.getSelectionModel().getSelectedItems();
for(String sV : auswahl){
System.out.println(sV);
}
});
VBox layout = new VBox();
layout.getChildren().addAll(listview, btn);
Scene scene = new Scene(layout, 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Mehr Datentypen für ListView
In unserem Beispiel oben haben wir ganz brav mit Strings gearbeitet. Selbstverständlich können wir aber alle Objekttypen in die ListView bzw. die ObservableList aufnehmen. Das ist ja gerade der Sinn von generischen Klassen 🥰
Eigene Objekttypen
Das solltest du in diesem Zusammenhang wissen:
- Innerhalb einer ListView ruft die ListCell automatisch die toString()-Methode der gespeicherten Objekte. Der Rückgabewert wird dann in der Zelle entsprechend angezeigt.
Für die Darstellung in der ListView ist also nur die toString()-Methode des Gesamt-Elements relevant.
Sehen wir uns jetzt ein entsprechendes Beispiel an, bei dem wir Objekte vom Typ Mitarbeiter in die ListView aufnehmen:
ListView<Mitarbeiter> listview = new ListView<>();
Mitarbeiter m1 = new Mitarbeiter("Luke Skywalker", 20);
Mitarbeiter m2 = new Mitarbeiter("Darth Vader", 40);
listview.getItems().addAll(m1, m2);
VBox layout = new VBox();
layout.getChildren().add(listview);
Scene scene = new Scene(layout, 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
Und so wird es in JavaFX dargestellt:
Hm... 🤔 Was wir hier angezeigt bekommen, ist die Speicherort-Adressen der beiden Objekte. Die dürften den Benutzer unseres Programms wohl kaum interessieren.
Der Grund für dieses Verhalten liegt darin, dass in der Klasse Mitarbeiter die toString()-Methode noch nicht überschrieben wurde und so wird der Standard-String zurückgeliefert.
Also überschreiben wir die toString()-Methode von Mitarbeiter kurzerhand einmmal:
public class Mitarbeiter {
String name;
int alter;
char gehaltsklasse;
public Mitarbeiter(String name, int alter){
this.name = name;
this.alter = alter;
gehaltsklasse = 'B';
}
@Override
public String toString(){
return name;
}
}
Damit sieht das Ganze doch schon user-verträglicher aus:
Einschränkung
Eine kleine Einschränkung gibt es allerdings: Es können nämlich keine ListView-Elemente durch Doppelklick editiert werden, die nicht vom Typ String sind: This method will only work on ListView instances which are of type String.