Literatur

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.