ComboBoxModel
Das Interface ComboBoxModel wird benötigt, wenn das standardmäßige DefaultComboBoxModel die Daten nicht in der gewünschten Weise anzeigt. Dies ist z.B. bei komplexen Objekten der Fall, da das ComboBoxModel nicht "weiß", welche Informationen in der JComboBox angezeigt werden sollen.
In diesem Kapitel werden wir Ihnen in einem Beispiel demonstrieren, wie komplexe Objekte mittels einer eigenen Model-Klasse in einer JComboBox angezeigt werden.
Wir erstellen uns dafür zunächst eine einfache Klasse, deren Objekte später in die Klappliste eingetragen werden sollen. In unserem Beispiel soll es sich dabei um Highscore-Einträge handeln. Die Klasse Highscore besteht aus nur zwei Attributen, dem Namen und dem Rang. Über die Methode getHighscoreEintrag wird aus den beiden Attributen ein Eintrag in Form von Rang: Name erstellt und zurückgegeben.
public class Highscore { private String name; private int rang; public Highscore(String name, int rang){ this.name = name; this.rang = rang; } public String getHighscoreEintrag(){ return this.rang + ": " + this.name; } public String getName(){ return this.name; } public int getRang(){ return this.rang; } }
Wir ändern nun unser Beispiel aus dem Oberkapitel JComboBox so ab, dass an Stelle der Strings nun die Highscore-Objekte übergeben werden.
import java.util.Vector; import javax.swing.*; public class ComboBoxModelBeispiel { public static void main(String[] args) { JFrame meinJFrame = new JFrame(); meinJFrame.setTitle("JComboBox Beispiel"); meinJFrame.setSize(300, 100); JPanel panel = new JPanel(); JLabel label = new JLabel("Highscore"); panel.add(label); //neuer Vector wird erstellt Vector vec = new Vector(); //Highscore-Objekte werden dem Vektor hinzugefügt vec.add(new Highscore("Ben", 3)); vec.add(new Highscore("Jochen", 1)); vec.add(new Highscore ("Robert", 2)); //JComboBox mit Highscore-Daten wird erzeugt JComboBox highscoreCombo = new JComboBox(vec); panel.add(highscoreCombo); meinJFrame.add(panel); meinJFrame.setVisible(true); } }
Wenn Sie den Code ausführen, sehen Sie, dass die Einträge in der JComboBox in der Form Paketname.Klassenname@Objekt-ID ausgegeben werden.
Dies macht natürlich in der Praxis wenig Sinn und soll auch nur der Demonstration dienen, warum es also etwas mehr Aufwand erfordert, wenn man komplexe Objekte hinzufügen möchte.
Jeder JComboBox liegt ein ComboBoxModel zugrunde. Dort wird z.B. definiert, welche Daten in der Klappliste angezeigt werden und welcher Eintrag selektiert ist. Standardmäßig ist die Klasse DefaultComboBoxModel dafür zuständig. Für komplexe Objekte muss jedoch eine eigene ComboBoxModel-Klasse erstellt werden. Diese muss das Interface ComboBoxModel implementieren.
Das Interface ComboBoxModel sieht die folgenden Methoden vor:
Methodenname | Kurzbeschreibung |
Object getSelectedItem() | Liefert das Objekt zurück (z.B. einen String), welcher als ausgewählter Eintrag in der JComboBox angezeigt werden soll. |
setSelectedItem(Object anItem) | Die Funktion wird aufgerufen, wenn ein Eintrag in der JComboBox selektiert wird. |
Das Interface ComboBoxModel bietet jedoch keine Möglichkeiten zum Einfügen und Entfernen von Elementen. Die Daten müssten daher direkt in der ComboBoxModel-Klasse verankert werden und können nicht von einer anderen Klasse dort eingetragen und entfernt werden.
Mehr Möglichkeiten stellt das von ComboBoxModel abgeleitete Interface MutableComboBoxModel zur Verfügung. Dieses bietet neben den oben genannten Methoden von ComboBoxModel noch einige weitere Methoden:
Methodenname | Kurzbeschreibung |
void addElement(Object obj) | Ein weiteres Element wird am Ende hinzugefügt. |
void insertElementAt(Object obj, int index) | Ein Element wird an dem angegebenen Index eingefügt. |
void removeElement(Object obj) | Das Element, was dem Übergabeparameter entspricht, wird gelöscht. |
void removeElementAt(int index) | Das Element mit dem angegebenen Index wird aus dem Model entfernt. |
Wir basteln uns nun unsere eigene Modell-Klasse, indem wir das MutableComboBoxModel und die entsprechenden Methoden implementieren.
import java.util.Vector; import javax.swing.MutableComboBoxModel; import javax.swing.event.ListDataListener; public class HighscoreMutableModel implements MutableComboBoxModel { // Das Attribut eintraege stellt unsere Listelemente dar Vector eintraege = new Vector(); // Index für selektierten Eintrag int index=-1; /* Hier geben wir zurück, was als selektierter Eintrag in der JComboBox angezeigt werden soll */ public Object getSelectedItem() { if(index >= 0) { return ((Highscore)eintraege.elementAt(index)).getHighscoreEintrag(); } else { return ""; } } // Diese Funktion wird beim Selektieren eines Eintrages aufgerufen // Dort ermitteln wir den Index für das ausgewählte Element // anItem ist der in der JComoboBox ausgewählte Eintrag public void setSelectedItem(Object anItem) { for(int i = 0; i< eintraege.size(); i++) { if(((Highscore)eintraege.elementAt(i)). getHighscoreEintrag().equals(anItem)) { index = i; break; } } } // Hier liefern wir die Anzahl der Elemente in unserer Liste zurück public int getSize() { return eintraege.size(); } // Hier wird ein Element an einer bestimmten Stelle zurückgegeben public Object getElementAt(int index) { return ((Highscore)eintraege.elementAt(index)).getHighscoreEintrag(); } // Hier fügen wir unserer Liste ein Highscore-Objekt hinzu // Wir ordnen es so ein, dass es in die Rangfolge passt public void addElement(Object obj) { if(!eintraege.contains(obj)) { int i=0; while(i<eintraege.size()&&((Highscore)eintraege.get(i)).getRang() <=((Highscore)obj).getRang()){ i++; } eintraege.add(i, obj); if(index==-1)index=0; } } // Hier entfernen wir ein Objekt aus der Liste public void removeElement(Object obj) { if(eintraege.contains(obj)) { eintraege.remove(obj); } } // Hier fügen wir ein Element an einer bestimmten Position ein public void insertElementAt(Object obj, int index) { eintraege.add(index, obj); } // Hier entfernen wir ein Element aus der Liste mit dem übergebenem Index public void removeElementAt(int index) { if(eintraege.size()> index) { eintraege.removeElementAt(index); } } // Die beiden folgenden Methoden berücksichtigen wir hier nicht public void addListDataListener(ListDataListener l) { } public void removeListDataListener(ListDataListener l) { } }
Unsere Modelklasse hat zwei Attribute: Im Vector eintraege werden unsere Highscore-Objekte erfasst, die für die JComboBox von unserer Model-Klasse aufbereitet werden. Außerdem erfassen wir den selektierten Index im Attribut index, welches wir mit -1 initialisieren, um zu verhindern, dass es eine Fehlermeldung gibt, wenn noch keine Daten in die JComboBox eingetragen wurden.
Die Methode getSelectedItem gibt den Text zurück, der angezeigt werden soll, wenn ein Element selektiert wurde. In unserem Beispiel wird der Text durch die Methode getHighscoreEintrag bereitgestellt. Diese gibt ein Objekt in Form eines aus Namen und Rang des Highscore-Eintrages zusammengesetzten Strings zurück. In getSelectedItem wird nun also die Methode getHighscoreEintrag des aktuell selektierten Highscore-Objektes aufgerufen. Doch woher wissen wir, welches Objekt selektiert wurde?
Dies geschieht in der Methode setSelectedItem, die zuvor automatisch, wenn der Benutzer einen Eintrag aus der JComboBox auswählt, aufgerufen wird. Um herauszufinden, welchen Index das ausgewählte Element hat, durchlaufen wir den Vektor in einer Schleife und rufen die Methode getHighscoreEintrag() eines jeden Objektes auf und vergleichen den zurückgegebenen String mit dem selektierten String. Bei Gleichheit wird der zugehörige Index im Attribut index gespeichert.
Die Methode getElementAt() dient dazu, alle Einträge zu ermitteln, die in der Klappliste zur Auswahl stehen. Auch hier wird die Methode getHighscoreEintrag aufgerufen, da diese Einträge in unserem Beispiel genauso aufgebaut sind wie der gerade ausgewählte Eintrag im Textfeld.
Außerdem implementieren wir die Methode addElement. Diese wird aufgerufen, wenn der JComboBox ein neues Element hinzugefügt wird. Standardmäßig werden diese beim DefaultComboBoxModel an der letzten Stelle eingefügt. Da wir aber eine Rangliste haben, sollen die Highscore-Einträge nach ihrem Rang geordnet werden. Dies lösen wir, indem wir in einer Schleife den Index ermitteln, an dem wir das Element einfügen müssen und dieses an der Stelle dem Vector mit der add-Funktion hinzufügen .
In der Methode removeElement löschen wir das Element an dem übergebenem Index mit der remove-Funktion des Vectors.
Wenn wir unser ComboBoxModel nun mit der JComboBox verknüpfen wollen, müssen wir ein Objekt unserer Modelklasse dem Konstruktor der JComboBox übergeben und die Highscore-Objekte hinzufügen. Die Klasse ComboBoxModelBeispiel von oben ändern wir dann wie folgt ab:
import java.util.Vector; import javax.swing.*; public class ComboBoxModelBeispiel { public static void main(String[] args) { JFrame meinJFrame = new JFrame(); meinJFrame.setTitle("JComboBox Beispiel"); meinJFrame.setSize(300, 100); JPanel panel = new JPanel(); JLabel label = new JLabel("Highscore"); panel.add(label); //neuer Vector wird erstellt Vector vec = new Vector(); //JComboBox mit Highscore-Daten wird erzeugt JComboBox highscoreCombo = new JComboBox(new HighscoreMutableModel()); //Highscore-Objekte werden in die JComboBox eingetragen highscoreCombo.addItem(new Highscore("Ben", 3)); highscoreCombo.addItem(new Highscore("Jochen", 1)); highscoreCombo.addItem(new Highscore("Robert", 2)); panel.add(highscoreCombo); meinJFrame.add(panel); meinJFrame.setVisible(true); } }
Wenn Sie jetzt den modifizierten Code ausführen, sollten Sie folgendes Bild sehen:
Sie sehen, die Einträge werden nun nicht in der Reihenfolge, in der sie hinzugefügt wurden, sondern nach Rang geordnet, dargestellt.