Swing JList Auswahl-GUI-Konzept

MayR42

Mitglied
Hallo zusammen!

Im Rahmen einer Studienarbeit darf ich folgendes realisieren:

Ich will in Java für einen breiten Benutzerkreis ein Dialogfenster erstellen, in dem zwei JList-Listen enthalten sind. Der Benutzer soll in der linken JList Elemente auswählen können und sie mit einem „Hinzufügen“-Button in die rechte Liste verschieben bzw. mit einem „Entfernen“-Button aus der rechten Liste wieder zurückschieben.

Bestimmt kennt jeder so eine Oberfläche.

Die linke JList kann bis zu 2000 Einträge enthalten. Die Listen müssen sortiert sein und jeder Eintrag darf nur einmal vorkommen. Der Benutzer hat die Möglichkeit über Checkboxen bestimmte Filter für die Listen zu aktivieren um die Einträge zu reduzieren.

Meine Realisierungsidee sieht wie folgt aus:

Ich lade mir die verfügbaren Daten aus einer Hashmap (ca. 5000 Datensätze) in ein TreeSet um doppelte Einträge zu vermeiden und um die Daten gleich zu sortieren. Daraufhin werden die Daten in eine DefaultList geladen und an das JList-Model übergeben.

Was haltet ihr davon?

Da der Benutzer die Liste wahrscheinlich oft filtert oder Einträge verschiebt, müssen die Listen wahrscheinlich oft aktualisiert werden. Ich habe ein wenig Bedenken, dass es zu Performance-Problemen kommen kann. Habe aber keine andere Realsierungsidee.

Viele Grüße
 
Hallo MayR42,
tatsächlich hat Swing DefaultListModel Performance-Problemen. Darüber hatte ich mal hier im Forum geschrieben. DefaultListModel bietet nur Methoden an, um einzelnes Item hinzufügen (ob addElement(E element), add(int index, E element), oder setElementAt(…), ...), nicht aber wie andere Komponent eimal komplett eine Collection hizugefügt wird. Sehen wir z.B. die Code einer Methode:
Code:
private Vector<E> delegate = new Vector<E>();
public void add(int index, E element) {
     delegate.insertElementAt(element, index);//Item wird addiert
     fireIntervalAdded(this, index, index);
}
Bei Methode fireIntervalAdded(…) wird Jlist.repaint() aufgeruft, also für Deine 2000-5000 Datensätze Deine GUI sovielmal neugezeichnet. Diese Phänomen bemerkte ich seit ca. 15 Jahren, und es wird nicht korrigiert. Ich glaube nicht, dass bei SUN (oder Oracle) keine gewusst hätte. Bei DefaultComboBoxModel oder ListView bieten sie z.B. über Konstruktor die Collection zu ersetzen, GUI wird nur einmal neugezeichnet. Man hat keine Chance, die Methoden zu überladen (-schreiben), weil Vector delegate private definiert ist.
Heuzutage emfehle ich lieber zu JavaFX zu benutzen. Wenn Du unbedingt bei Swing bleibt, rate ich eher zu JTable zu benutzen. Falls Du unbedingt bei Jlist bleibt, bleibt wohl nur die Lösung (was ich damals auch getan hatte) neue Class DefaultListModel in eigenem Projekt zu bauen, in dem ich die ganze Original-Source-Code übernimmt, erweiterte mit add(index, Collection) bzw. setItems(Collection) - Collection wird zuerst ersetzt(addiert), erst dann wird fire-Methode aufgerufen.
 
Zuletzt bearbeitet:
Alternativ AbstractListModel erweitern und die Methode getElemenAt(int index) und getSize() überschreiben. Dann die benötigten add-Methoden implementieren, die z. B. das Hinzufügen aller Elemente einer Collection ermöglichen könnte. Dabei sollte fireIntervalAdded(Object source, int index0, int index1) erst dann aufgerufen werden, wenn der Einfügevorgang abgeschlossen ist.
 
Vielen Dank für eure Lösungsvorschläge!
Ich muss Swing verwenden und kann leider kein FX einsetzen.
Dadurch das die Elemente in der JListe nur einmal vorkommen dürfen und sortiert sein müssen, bin ich noch am überlegen, ob ich meine eigene Implementierung besser wäre als der Umweg über TreeSet mit anschließender Schleife über TreeSet=>DefaultList 😕
 
Wenn der tausendfache Aufruf von DefaultListModel.add oder addItem tatsächlich ein bottleneck ist, versuchs mal mit TreeSet<T> --> T[] (Konvertierung zu einem Array, das TreeSet bietet dafür eine fertige Methode an), dann DefaultListModel.copyInto(Object[] anArray).
 
@Harry Kane: Warum ist das kopieren von TreeSet<T> --> T[]-Array --> DefaultList schneller als z.B.

Code:
while ( iterator.hasNext()) {
            fElement = (MinClone) iterator.next();
            anzeigeListe.addElement( fElement.getId());
        }
 
Weil im ersten Fall das DefaultListModel nur einmal einen event feuern sollte, der die JList dazu bringt, sich selber zu zeichnen. Im zweiten Fall mit dem code snippet sollte jeder Aufruf von addElement zu einem Neuzeichnen führen, was die Sache verlangsamt.
Darf ich deine Frage so interpretieren, dass die von mir vorgeschlagene Variante tatsächlich schneller ist?
 
Du machst dir da etwas zu viele Sorgen.
So lange du nicht mit addElement usw. arbeitest, ist die Performance kein Thema. 5000 Einträge sind für ein Set überhaupt kein Problem. Nach dem Fertigstellen des Sets setze ein neues Listmodel (lass es NICHT direkt auf dem Set basieren, sondern auf einer Kopie, z.B. auf einem Array oder einer Arraylist), anschließend selektiere das neue Element. Dann kriegst du auch nur einen Event.
Die GUI sprich immer erst dann an, wenn deine Arbeit mit den Listen/Sets/Filtern oder was auch immer beendet ist, dann hast du überhaupt kein Problem mit der Performance.
 

Zurück
Oben