Wie man eine TabPane dynamisch mit Tabs befüllt, möchte ich in diesem Tutorial erläutern.
Ziel
Das Ziel soll es sein, dass durch einen Klick auf einen Menüpunkt in einer MenuBar ein neuer Tab in der TabPane erzeugt wird.
Erste Schritte
Als erstes benötigt man ein Model wo die Liste mit den Tabs abgelegt wird. Und von dort wird dann die Liste referenziert.
import java.util.ArrayList; import java.util.List; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.control.Tab; public class Model { private List<Tab> list = new ArrayList<Tab>(); private ObservableList<Tab> tabs = FXCollections.observableList(list); public ObservableList<Tab> getTabs() { return tabs; } public void setTabs(ObservableList<Tab> tabs) { this.tabs = tabs; } }
Nachdem man das Model erzeugt hat, muss nun die Listen aus der TabPane und dem Model zusammengefügt werden. (Mergen) Dazu habe ich im Internet eine brauchbare Lösung gefunden.
private ObservableList<Tab> merge(ObservableList<Tab> into, ObservableList<Tab>... lists) { final ObservableList<Tab> list = into; for (ObservableList<Tab> l : lists) { list.addAll(l); l.addListener((javafx.collections.ListChangeListener.Change<? extends Tab> c) -> { while (c.next()) { if (c.wasAdded()) { list.addAll(c.getAddedSubList()); } if (c.wasRemoved()) { list.removeAll(c.getRemoved()); } } }); } return list; }
Quelle: http://stackoverflow.com/questions/26636199/merge-multiple-observablelist-into-one-list
Die oben genannte Methode muss nun nach der Initialisierung des Controllers und des setzen des Modells aufgerufen werden.
private void preInit() { ObservableList<Tab> tabs = tabPane.getTabs(); merge(tabs, model.getTabs()); }
Für eine bessere Lesbarkeit habe ich mir erst die ObservableList mit den Tabs aus der TabPane geladen und als lokale Variable abgelegt.
Die Methode merge wird hier mit der ObservableList aus der TabPane sowie mit der ObservableList aus dem Model aufgerufen.
Nun kann in der ActionMethode zum MenuItem ein neuer Tab erzeugt werden.
<MenuItem text="%new" onAction="#handleNewAction"/>
@FXML protected void handleNewAction(final ActionEvent event) { model.getTabs().add(new Tab("Hallo Welt!")); }
Ergebnis
Das Ergebnis ist, dass die beiden Listen “miteinander verbunden” wurden, es also eine Art Binding zwischen diesen Listen gibt. Es ist also nicht mehr nötigt wie beim MVC Pattern bekannt programmatisch in diesen Updatevorgang einzugreifen, sondern eher wie JSF wo die Componenten mit einer Bean verknüpft werden.
Nächste Schritte
Nächste Schritte wären hier, ein Tab zu erzeugen welches aus einer FXML geladen wird.