Literatur

ListModel

Die Einträge einer JList werden von einem Listenmodell verwaltet. Aus den Daten, die der JList im Konstruktor oder über die Methode setListData übergeben werden, wird ein unveränderliches Datenmodell erstellt.

Über die Methode getModel() kann auf das Listenmodell zugegriffen werden. Das Interface ListModel bietet zwar Methoden, um die Einträge auszulesen, jedoch keine Möglichkeit die Daten zu verändern. Häufig werden Listen jedoch zur Laufzeit dynamisch verändert, so dass es eines komplexeren Listenmodells bedarf.

Für einfachere dynamische Listen bietet sich die Klasse DefaultListModel an. Diese ist sehr stark der Klasse java.util.Vector nachempfunden. Wenn man mit Vectoren vertraut ist, sollte es also auch leicht fallen, mit einem Listenmodell umzugehen.

Um zu zeigen, wie man mit dem DefaultListModel Einträge hinzufügen und löschen kann, haben wir das Beispiel aus dem Kapitel JList etwas abgeändert:

 
import javax.swing.*;
 
public class JListBeispiel {
 
    public static void main(String[] args) {
        JFrame meinJFrame = new JFrame();
        meinJFrame.setTitle("JListBeispiel");
        meinJFrame.setSize(300, 300);
        JPanel panel = new JPanel();
 
        JLabel frage = new JLabel("Für welche Themen interessierst du dich?");
        panel.add(frage);
 
        // Array für unsere JList
        String interessen[] = {"Politik", "Autos", "Mode", 
            "Film- und Fernsehen", "Computer", "Tiere", "Sport"};
 
        //DefaultListModell wird erzeugt
        DefaultListModel listenModell = new DefaultListModel();
 
        //JList mit Einträgen wird erstellt
        JList themenAuswahl = new JList(listenModell);
        for(int i=0; i<interessen.length; i++){
        	listenModell.addElement(interessen[i]);
        }
 
        //JList wird Panel hinzugefügt
        panel.add(themenAuswahl);
 
        //Eintrag "Programmieren" wird an Index 4 eingefügt
        listenModell.add(4, "Programmieren");
 
        //erster Eintrag "Politik" wird entfernt
        listenModell.removeElementAt(0);
 
        //String "Mode" wird entfernt        
        listenModell.removeElement("Mode");
 
        meinJFrame.add(panel);
        meinJFrame.setVisible(true);
 
    }
}

 

Mit addElement(Object obj) werden Einträge an das Ende der Liste hinzugefügt. Über die Methode add(int index, Object element) können neue Elemente an einer beliebigen Position in die Liste eingefügt werden. Mit removeElementAt(int index) kann ein Eintrag an einer bestimmten Position wieder entfernt werden. Möglich ist auch, mit removeElement(Object obj) ein bestimmtes Objekt zu löschen.

Aber auch das DefaultListModel reicht ohne Veränderung nicht immer aus. Wie wir bereits im Kapitel ComboBoxModel veranschaulicht haben, würde z.B. das Einfügen komplexer Objekte ohne eigene Modellklasse zu keinen sinnvollen Einträgen in der Liste führen. Um dies zu realisieren, müssen wir eine eigene Listenmodell-Klasse erstellen.

Als Beispiel wollen wir, analog zum Kapitel ComboBoxModel, die Liste mit den Objekten der Klasse Highscore füllen. Die Klasse Highscore sah wie folgt aus:

 
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;
    }
 
}

Eigene Listenmodellklassen werden oft von der abstrakten Klasse AbstractListModel abgeleitet. Diese bietet einige vorimplementierte Methoden für den Umgang mit ListDataListenern. ListDataListener werden benötigt, wenn man z.B., wie es oft in Anwendungen der Fall ist, ein Textfeld hat, in dem der Benutzer einen Wert eintragen soll, der anschließend (z.B. nach einem Klick auf einen entsprechenden Button) in der Liste erscheinen soll Die Klasse AbstractListModel implementiert das Interface ListModel. Die Methoden getSize und getElementAt müssen in der von AbstractListModel abgeleiteten eigenen Listenmodellklasse noch implementiert werden.

In unserem Beispiel machen wir es uns etwas einfacher und leiten von der Klasse DefaultListModel ab, die schon viele Methoden so implementiert hat, wie wir sie für unser Beispiel benötigen. Wir überschreiben daher nur die Methoden, die wir in der Standardfunktionalität verändern müssen, damit die Highscore-Einträge korrekt und in richtiger Reihenfolge angezeigt werden.

 
import javax.swing.DefaultListModel;
 
 
public class HighscoreListModel extends DefaultListModel {
 
    public Object getElementAt(int index) {
        Highscore highscore = (Highscore) super.getElementAt(index);
        return highscore.getHighscoreEintrag();
    }
    
 
    public void addElement(Object obj) {
        if(!this.contains(obj))
        {
            int i=0;
            
            while(i<this.size()&&((Highscore)this.get(i)).getRang()
                <=((Highscore)obj).getRang()){
                    i++;
           }
             
            this.add(i, obj);
        }
    }
       
}

Für unsere Zwecke reicht es, die Methoden getElementAt und addElement zu überschreiben. Die Methode getElementAt wird intern aufgerufen, um die Listeneinträge zu erstellen. Um das ausgewählte Objekt zu ermitteln, rufen wir der Einfachheit halber die Methode getElementAt der Oberklasse DefaultListModel auf. Diese liefert aber eine Referenz auf das gesamte Highscore-Objekt zurück, was sich, wie wir bereits gelernt haben, als Listeneintrag nicht eignet. Daher rufen wir die Methode getHighscoreEintrag auf und geben den String zurück, den diese Methode liefert. Dies ist der eigentliche Listeneintrag.

Damit die Einträge in sortierter Reihenfolge eingefügt werden, ermitteln wir in addElement die Rangfolge des Highscore-Objektes und fügen es an der ermittelten Position ein.

Unsere Startklasse JListBeispiel, die die JList mit den Highscore-Einträgen anzeigt, sieht wie folgt aus:

 
import javax.swing.*;

public class JListBeispiel {
 
    public static void main(String[] args) {
        JFrame meinJFrame = new JFrame();
        meinJFrame.setTitle("ListModelBeispiel");
        meinJFrame.setSize(200, 150);
        JPanel panel = new JPanel();
 
        JLabel label = new JLabel("Highscore");
        panel.add(label);
 
        /* Neues Objekt unserer Model-Klasse 
            HighscoreListModel wird erzeugt */
        HighscoreListModel highscoreModel = new HighscoreListModel();
 
        //Wir fügen unserem ListModel Highscore-Objekte hinzu
        highscoreModel.addElement(new Highscore("Ben", 3));
        highscoreModel.addElement(new Highscore("Jochen", 1));
        highscoreModel.addElement(new Highscore("Robert",2));
 
        //Wir übergeben dem Konstruktor der JList unser ListModel
        JList highscoreList = new JList(highscoreModel);
 
        panel.add(highscoreList);
        meinJFrame.add(panel);
        meinJFrame.setVisible(true);
 
    }
}

Wir erzeugen zunächst eine Instanz der Modellklasse. Diese übergeben wir dem Konstruktor beim Erstellen der JList. Die Highscore-Objekte fügen wir mit addElement dem Listenmodell hinzu. Sie sehen, dass die Einträge in der ermittelten Sortierung eingefügt werden.