Wie kann man in einer JList sortieren?

Status
Dieses Thema wurde gelöst! Zur Lösung gehen…

Nico2201

Mitglied
Hallo,

ich bin dabei 3 verschiedene Sortierungsmethoden in mein Projekt in implementieren. Und zwar soll bei der ersten Methode nach den Namen (String), bei der zweiten nach dem Preis (double) und bei der dritten Methode nach dem Datum (unbekannter Wert - vermutlich Date oder sowas?) sortiert werden. Das ganze soll auf einer JList funktionieren. Im Internet habe ich etwas von einem Comparator gelesen, aber um ehrlich zu sein wurde ich da nicht schlauer draus.

Kann mir bitte jemand bei den Sortierungsmethoden helfen? Die dazugehörigen Codes mit Erklärung wäre perfekt. :cool:
 
Hi,

bist du dir sicher, dass du auf JList arbeiten willst? Wenn du auf einer normalen List arbeitest ist das ganze viel einfacher. Du kannst dann auch deine List als Model in die JList setzen.

Java:
import javax.swing.*;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

public class Test {
    static class Entity {
        private final String name;
        private final double price;
        private final LocalDate localDate;
        private final Date date;

        public Entity(String name, double price, LocalDate localDate, Date date) {
            this.name = name;
            this.price = price;
            this.localDate = localDate;
            this.date = date;
        }

        public String getName() {
            return name;
        }

        public double getPrice() {
            return price;
        }

        public LocalDate getLocalDate() {
            return localDate;
        }

        public Date getDate() {
            return date;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    public static void main(String[] args) {
        LocalDate now = LocalDate.now();
        LocalDate _2014 = LocalDate.of(2014, 1, 2);
        LocalDate _2013 = LocalDate.of(2013, 1, 2);

        Entity test1 = new Entity("Sepp Brösl", 100.4, now, Date.from(now.atStartOfDay().toInstant(ZoneOffset.UTC)));
        Entity test2 = new Entity("Donald Duck", 44.59, _2014, Date.from(_2014.atStartOfDay().toInstant(ZoneOffset.UTC)));
        Entity test3 = new Entity("Micky Maus", 155.33, _2013, Date.from(_2013.atStartOfDay().toInstant(ZoneOffset.UTC)));

        List<Entity> liste = new ArrayList<>();
        liste.add(test1);
        liste.add(test2);
        liste.add(test3);

        // JList erstellen aus vorhandener Liste
        JList<Entity> uiList = new JList<>(new AbstractListModel<Entity>() {
            public int getSize() { return liste.size(); }
            public Entity getElementAt(int i) { return liste.get(i); }
        });

        System.out.println(liste); // unsortiert

        liste.sort(Comparator.comparing(Entity::getName));
        System.out.println("nach name: " + liste); // nach name

        liste.sort(Comparator.comparingDouble(Entity::getPrice));
        System.out.println("nach preis: " + liste); // nach preis

        liste.sort(Comparator.comparing(Entity::getDate));
        System.out.println("nach date: " + liste); // nach date

        liste.sort(Comparator.comparing(Entity::getLocalDate));
        System.out.println("nach localdate: " + liste); // nach localdate
    }
}

Grüsse,
BK
 
Hi,

bist du dir sicher, dass du auf JList arbeiten willst? Wenn du auf einer normalen List arbeitest ist das ganze viel einfacher. Du kannst dann auch deine List als Model in die JList setzen.

Java:
import javax.swing.*;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

public class Test {
    static class Entity {
        private final String name;
        private final double price;
        private final LocalDate localDate;
        private final Date date;

        public Entity(String name, double price, LocalDate localDate, Date date) {
            this.name = name;
            this.price = price;
            this.localDate = localDate;
            this.date = date;
        }

        public String getName() {
            return name;
        }

        public double getPrice() {
            return price;
        }

        public LocalDate getLocalDate() {
            return localDate;
        }

        public Date getDate() {
            return date;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    public static void main(String[] args) {
        LocalDate now = LocalDate.now();
        LocalDate _2014 = LocalDate.of(2014, 1, 2);
        LocalDate _2013 = LocalDate.of(2013, 1, 2);

        Entity test1 = new Entity("Sepp Brösl", 100.4, now, Date.from(now.atStartOfDay().toInstant(ZoneOffset.UTC)));
        Entity test2 = new Entity("Donald Duck", 44.59, _2014, Date.from(_2014.atStartOfDay().toInstant(ZoneOffset.UTC)));
        Entity test3 = new Entity("Micky Maus", 155.33, _2013, Date.from(_2013.atStartOfDay().toInstant(ZoneOffset.UTC)));

        List<Entity> liste = new ArrayList<>();
        liste.add(test1);
        liste.add(test2);
        liste.add(test3);

        // JList erstellen aus vorhandener Liste
        JList<Entity> uiList = new JList<>(new AbstractListModel<Entity>() {
            public int getSize() { return liste.size(); }
            public Entity getElementAt(int i) { return liste.get(i); }
        });

        System.out.println(liste); // unsortiert

        liste.sort(Comparator.comparing(Entity::getName));
        System.out.println("nach name: " + liste); // nach name

        liste.sort(Comparator.comparingDouble(Entity::getPrice));
        System.out.println("nach preis: " + liste); // nach preis

        liste.sort(Comparator.comparing(Entity::getDate));
        System.out.println("nach date: " + liste); // nach date

        liste.sort(Comparator.comparing(Entity::getLocalDate));
        System.out.println("nach localdate: " + liste); // nach localdate
    }
}

Grüsse,
BK

Erstmal vielen Dank für deine Hilfe!

Ich habe eine normale JList mit einem DefaultListModel. Sobald ich der JList ein AbstractListModel zuordne, bekomme ich in den anderen Methoden, die nichts mit dem Sortieren zu tun haben, jede Menge Fehlermeldungen. So wie ich das in deinem Code verstanden habe, braucht man ein AbstractListModel, um eine List erstellen und somit später mit dem Comparator sortieren zu können. Geht das ganze auch in einem DefaultListModel? Wenn ja, wie?? Oder gibt es eine Alternative zu der List und dem AbstractListModel? Wenn ja, welche wäre das?
 
Hi,

soweit ich das in der Implementierung von DefaultListModel sehe wird da mit einem Vector gearbeitet. Ziemlich alte Klasse, hätte nicht gedacht die nochmal zu sehen. Aber zurück zum Thema: Nein, ich habe keine Möglichkeit gefunden, direkt an den Vector zu kommen. Also abgesehen von Reflection, was ich aber nicht empfehlen würde.

Du könntest aber über das Model ein removeAll machen und danach die Einträge sortiert nochmal einfügen.
Du machst also deine Datenhaltung in einer normalen List, die du sortieren kannst. Sobald du deine List änderst musst du halt das Model der JList neu aufbauen.

Grüsse,
BK
 
Hi,

soweit ich das in der Implementierung von DefaultListModel sehe wird da mit einem Vector gearbeitet. Ziemlich alte Klasse, hätte nicht gedacht die nochmal zu sehen. Aber zurück zum Thema: Nein, ich habe keine Möglichkeit gefunden, direkt an den Vector zu kommen. Also abgesehen von Reflection, was ich aber nicht empfehlen würde.

Du könntest aber über das Model ein removeAll machen und danach die Einträge sortiert nochmal einfügen.
Du machst also deine Datenhaltung in einer normalen List, die du sortieren kannst. Sobald du deine List änderst musst du halt das Model der JList neu aufbauen.

Grüsse,
BK

Ich habe es jetzt folgendermaßen gemacht:

Java:
public void SortiereNachName(ActionEvent e) {
        
        String[] s = new String[model.getSize()];
        
        for(int i = 0; i < s.length; i++) {
            
            s[i] = model.getElementAt(i).toString();
        }
        
        Arrays.sort(s);
        liste.setListData(s);
    }

Leider ist mir mit dieser Variante keine Möglichkeit eingefallen, wie man Zahlen, sprich "Preis" und "Datum" in der JList sortieren kann. Gibt es da etwas, was mir eventuell weiterhelfen könnte?
 
DefaultListModel ist eben nur default, also für den ganz einfachsten Fall. Ich weiß, dass AbstractListModel etwas befremdend wirken kann, aber lass dich davon nicht abschrecken. Mach dir halt einen ganz eigenen! Du kannst diesen dann genauso verwenden wie DefaultListModel.

Hier ein Beispielgerüst:
Java:
package javaforum.example;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import javax.swing.AbstractListModel;

@SuppressWarnings("serial")
public class SortableListModel<T> extends AbstractListModel<T> {

    private List<T> list;

    public SortableListModel() {
        list = new ArrayList<>();
    }

    public void sort(Comparator<T> comparator) {
        list.sort(comparator);
        fireContentsChanged(this, 0, list.size() - 1);
    }

    public void addElement(T element) {
        list.add(element);
        fireIntervalAdded(this, list.size() - 1, list.size() - 1);
    }

    @Override
    public T getElementAt(int index) {
        return list.get(index);
    }

    @Override
    public int getSize() {
        return list.size();
    }
}

Und zum Test:
Java:
package javaforum.example;

public class Entity {

    private int id;
    private String name;

    public Entity(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return id + " - " + name;
    }
}

Java:
package javaforum.example;

import java.awt.GridLayout;
import java.util.Comparator;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class TestFrame extends JFrame {
    
    public TestFrame() {    
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 2));
        
        SortableListModel<Entity> model = new SortableListModel<>();
        model.addElement(new Entity(1, "Foo"));
        model.addElement(new Entity(2, "Bar"));
        add(new JList<Entity>(model));
        
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(2, 1));
        
        JButton buttonId = new JButton("ID Sort");
        buttonId.addActionListener(e -> {
            model.sort(Comparator.comparingInt(Entity::getId));
        });
        panel.add(buttonId);
        
        JButton buttonName = new JButton("Name Sort");
        buttonName.addActionListener(e -> {
            model.sort(Comparator.comparing(Entity::getName));
        });
        panel.add(buttonName);
        
        add(panel);
        
        pack();
    }

    public static void main(String[] args) {
        new TestFrame().setVisible(true);
    }
}
 
Zuletzt bearbeitet:
DefaultListModel ist eben nur default, also für den ganz einfachsten Fall. Ich weiß, dass AbstractListModel etwas befremdend wirken kann, aber lass dich davon nicht abschrecken. Mach dir halt einen ganz eigenen! Du kannst diesen dann genauso verwenden wie DefaultListModel.

Hier ein Beispielgerüst:
Java:
package javaforum.example;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import javax.swing.AbstractListModel;

@SuppressWarnings("serial")
public class SortableListModel<T> extends AbstractListModel<T> {

    private List<T> list;

    public SortableListModel() {
        list = new ArrayList<>();
    }

    public void sort(Comparator<T> comparator) {
        list.sort(comparator);
        fireContentsChanged(this, 0, list.size() - 1);
    }

    public void addElement(T element) {
        list.add(element);
        fireIntervalAdded(this, list.size() - 1, list.size() - 1);
    }

    @Override
    public T getElementAt(int index) {
        return list.get(index);
    }

    @Override
    public int getSize() {
        return list.size();
    }
}

Und zum Test:
Java:
package javaforum.example;

public class Entity {

    private int id;
    private String name;

    public Entity(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return id + " - " + name;
    }
}

Java:
package javaforum.example;

import java.awt.GridLayout;
import java.util.Comparator;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class TestFrame extends JFrame {
   
    public TestFrame() {   
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 2));
       
        SortableListModel<Entity> model = new SortableListModel<>();
        model.addElement(new Entity(1, "Foo"));
        model.addElement(new Entity(2, "Bar"));
        add(new JList<Entity>(model));
       
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(2, 1));
       
        JButton buttonId = new JButton("ID Sort");
        buttonId.addActionListener(e -> {
            model.sort(Comparator.comparingInt(Entity::getId));
        });
        panel.add(buttonId);
       
        JButton buttonName = new JButton("Name Sort");
        buttonName.addActionListener(e -> {
            model.sort(Comparator.comparing(Entity::getName));
        });
        panel.add(buttonName);
       
        add(panel);
       
        pack();
    }

    public static void main(String[] args) {
        new TestFrame().setVisible(true);
    }
}

Vielen Dank für deine Hilfe!

Hat alles bestens geklappt, nur habe ich ein Problem durch das AbstractListModel bekommen. Und zwar weißt meine Methode "DateiOeffnen" einen Fehler auf:

Ich nutze den BufferedReader, um eine .txt Datei zu öffnen, aber das geht nicht mehr. Leider habe ich gerade keine Möglichkeit dir meinen Programmcode zu zeigen, aber hättest du eine Idee für eine Methode, mit der ich die JList mit dem AbstractListModel aus einer .txt Datei öffnen kann? Folgende Werte sollen geöffnet werden:

- name (String)
- preis (double)
- datum (double oder date??)
- summe aus preis in einem JTextField (double)
 
Vermutlich fehlt ein Parsing?

Ansonsten kann es sein, dass du eine Methode vom DefaultListModel verwendest, die mein SortableListModel Beispiel (noch) nicht hat. Könnte man dann natürlich hinzufügen.
 
Zuletzt bearbeitet:
Hier der Code für die "DateiOeffnen" Methode:

Java:
public void DateiOeffnen(ActionEvent e) {
        
        JFileChooser fcOeffnen = new JFileChooser();
        
        if(fcOeffnen.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
            
            File datei = fcOeffnen.getSelectedFile();
            
            try {
                
                br = new BufferedReader(new FileReader(datei));
                int value = Integer.parseInt(br.readLine());
                
                for(int i = 0; i < value; i++) {
                    
                    String text = br.readLine();
                    
                    while((text = br.readLine()) != null) {
                        
                        double dPreis = Double.parseDouble(text);
                        double dDatum = Double.parseDouble(text);
                        model.addElement(new Entity(text, dPreis, dDatum));
                    }
                }
                
                liste.setModel(model);
                String s = br.readLine();
                ausgabePreis.setText(s);
            }
            
            catch(IOException e1) {
                
                JOptionPane.showMessageDialog(null, "Die Liste konnte nicht geöffnet werden. Bitte versuchen Sie es erneut!", "Öffnen fehlgeschlagen", JOptionPane.WARNING_MESSAGE);
            }
            
            finally {
                
                try {
                    
                    br.close();
                    
                }
                
                catch(IOException e2) {

                    JOptionPane.showMessageDialog(null, "Die Liste konnte nicht geöffnet werden. Bitte versuchen Sie es erneut!", "Öffnen fehlgeschlagen", JOptionPane.WARNING_MESSAGE);
                }
            }
        }
    }

Ich hoffe, du kannst mir helfen.
 
Status
Dieses Thema wurde gelöst! Zur Lösung gehen…
Zurück