JavaFX Im TreeView, TreeItems sortieren

Ingerten

Bekanntes Mitglied
Hallo zusammen,

Ich habe da ein kleines Problem und komme da nicht weiter, ich möchte meine Items im Treeview wie folgt sortieren.

bis jetzt ist es so:

Ordner 1
Ordner 11
Ordner 2

ich hätte es aber gerne so:

Ordner 1
Ordner 2
Ordner 11

Ich adde die Nodes in eine "ObservableList<TreeItem<PathItem>>" und die muss man doch irgendwie sortieren können oder geht das garnicht mit der "ObservableList"?

Vielen Dank schonmal.
 
Hi,
Du kannst eine Liste mit Collections.sort bzw. FXCollections.sort (für ObservableList) sortieren.
hier mal ein Beispiel für eine Observable list:
Java:
private static void sortMyList() {
   ObservableList<String> myList = FXCollections.observableList(new LinkedList<>());
   myList.addAll("Ordner 2", "Ordner 11", "Ordner 7", "Ordner 6", "Ordner 1" );
   System.out.println("vor sortieren");
   myList.forEach(item -> {
     System.out.println(item);
   });
   FXCollections.sort(myList, new Comparator<String>() {
     @Override
     public int compare(String string0, String string1) {
       int number0 = Integer.parseInt(string0.replace("Ordner ", ""));
       int number1 = Integer.parseInt(string1.replace("Ordner ", ""));
       if(number0 > number1)
         return 1;
       if(number0 < number1)
         return -1;
       else
         return 0;
     }
   });
   System.out.println("nach sortieren");
   myList.forEach(item -> {
     System.out.println(item);
   });
}
Code:
vor sortieren
Ordner 2
Ordner 11
Ordner 7
Ordner 6
Ordner 1
nach sortieren
Ordner 1
Ordner 2
Ordner 6
Ordner 7
Ordner 11
Hier noch ein paar Anmerkungen:
Das "Problem" beim Sortieren von Namen, bei denen auch noch ein Index berücksichtigt werden soll, ist, dass eine Zahl in einem String als Charakter angesehen wird, damit wird bei der Sortierung Ordner 1, Ordner 11 und dann erst Ordner 2 sortiert.
Da du aber den nach dem Index im Namen sortieren möchtest, muss die Sortierung der Liste auch mit dem Index gemacht werden.
Dazu wird im Code das Comparator-Interface benutzt. Mit diesem wird der String: "Ordner ", der für alle Items gleich ist, entfernt. Damit bleibt nur noch eine Nummer als String. Diese wird dann als int geparsed und dann wird der Vergleich mit den 2 Nummer gemacht.
Das ganze funktioniert jedoch nur solange, wie die Verzeichnisse mit "Ordner " anfangen und dann eine Zahl folgt. Wenn nach der Zahl wieder andere Charakter folgenen, fliegt das ganze hoch... NumberFormatException.
Besser wäre vielleicht, wenn du mit Regex den Index ermittelst.
 
Zuletzt bearbeitet:
Vielen Dank erstmal, ich mal schauen, ob ich da was hinbekomme.

Leider ist es genau so, wie du es als letztes beschrieben hast, es könnte eben vorkommen, das die Zahl überall stehen könnte oder es gibt keine Zahl.
Im Prinzip soll die sortierung genau wie im Windows-Explorer aussehen.
 
Juhu, ich habs hinbekommen.

Google hat doch noch was gefunden, hier die Lösung und für mein Projekt etwas abgeändert.
Und vielen Dank nochmal, für deine hilfe.

Java:
            Collections.sort(children, new Comparator<TreeItem<PathItem>>() {
                private final Comparator<String> NATURAL_SORT = new WindowsExplorerComparator();

                @Override
                public int compare(TreeItem<PathItem> o1, TreeItem<PathItem> o2) {;
                    return NATURAL_SORT.compare(o1.getValue().toString(), o2.getValue().toString());
                }
            });

Java:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WindowsExplorerComparator implements Comparator<String> {

    private static final Pattern splitPattern = Pattern.compile("\\d+|\\.|\\s");

    @Override
    public int compare(String str1, String str2) {
        Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
        Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
        while (true) {
            //Til here all is equal.
            if (!i1.hasNext() && !i2.hasNext()) {
                return 0;
            }
            //first has no more parts -> comes first
            if (!i1.hasNext() && i2.hasNext()) {
                return -1;
            }
            //first has more parts than i2 -> comes after
            if (i1.hasNext() && !i2.hasNext()) {
                return 1;
            }

            String data1 = i1.next();
            String data2 = i2.next();
            int result;
            try {
                //If both datas are numbers, then compare numbers
                result = Long.compare(Long.valueOf(data1), Long.valueOf(data2));
                //If numbers are equal than longer comes first
                if (result == 0) {
                    result = -Integer.compare(data1.length(), data2.length());
                }
            } catch (NumberFormatException ex) {
                //compare text case insensitive
                result = data1.compareToIgnoreCase(data2);
            }

            if (result != 0) {
                return result;
            }
        }
    }

    private List<String> splitStringPreserveDelimiter(String str) {
        Matcher matcher = splitPattern.matcher(str);
        List<String> list = new ArrayList<String>();
        int pos = 0;
        while (matcher.find()) {
            list.add(str.substring(pos, matcher.start()));
            list.add(matcher.group());
            pos = matcher.end();
        }
        list.add(str.substring(pos));
        return list;
    }
}
 

Zurück
Oben