# List in JTree umwandeln



## m0ps (9. Jul 2009)

Tag zusammen,
neues Problem:

Ich habe eine Liste mit Objekten, die Strings enthalten. Also sowas wie Objekt1("Auto","Mercedes","c-Klasse}, Objekt2("Auto","BMW","3er"), Objekt3("Motorad","Suzuki","irgendeinModel"), usw...

Aus dieser Liste möchte ich einen JTree bauen ala:

-Fahrzeuge
...-Auto
......-Mercedes
.........-c-Klasse
......-BMW
.........-3er
...-Motorad
......-Suzuki
.........-irgendeinModel
usw

ANMERKUNG: die Objekte sind schon nach den Strings sortiert, also erst kommen alle "Autos", diese unterglieder sich in alle "mercedes", dann alle "BMWs" usw...

Leider weiß ich nicht wie ich das realisieren soll.
Meine erste Überlegung war mit dem ersten Objekt in der Liste einen Tree zu "starten" und dann immer das gerade betrachtete Objekt mit dem Vorherigen zu vergleichen, ob es mit den Knoten übereinstimmt. Ist dies nicht der Fall, wird ein neuer Knoten erstellt.

Bei der Umsetzung scheiterts dann aber  Habs mit drölf "if"-Abfragen probiert, aber dann wieder verworfen.
Habt ihr dazu vielleicht einen Vorschlag/eine Lösung?

Grüße
m0ps


----------



## m0ps (9. Jul 2009)

PS: Diesen Thread: http://www.java-forum.org/allgemeine-java-themen/81429-jtree-aus-liste-erstellen.html  habe ich schon angeschau. Aber der ist schlecht auf meinem Beispiel anwendbar, oder?

Greetz


----------



## André Uhres (10. Jul 2009)

Wir können z.B. zuerst alle Kategorien anlegen, dann alle Marken, und schliesslich alle Modelle. Dann brauchen wir uns nicht darum zu kümmern, ob der Vaterknoten jeweils schon angelegt ist oder nicht. Zum Auffinden des jeweiligen Vaterknotens können wir uns eine Methode bauen. die den Baum rekursiv durchläuft.


----------



## m0ps (10. Jul 2009)

Danke für deine Antwort.

Hm, ist die Methode nicht ziemlich aufwendig, wenn ich die Liste für das initialisieren der Knoten durchlaufen muss + dann nochmal um die Elemente zuzuweisen?

Greetz
m0ps


----------



## Ebenius (10. Jul 2009)

André Uhres hat gesagt.:


> Wir können z.B. zuerst alle Kategorien anlegen, dann alle Marken, und schliesslich alle Modelle. Dann brauchen wir uns nicht darum zu kümmern, ob der Vaterknoten jeweils schon angelegt ist oder nicht. Zum Auffinden des jeweiligen Vaterknotens können wir uns eine Methode bauen. die den Baum rekursiv durchläuft.


Wenn die Daten schon sortiert vorliegen, dann kann man's auch noch einfacher machen. Beispiel:

```
final List<String[]> flatData = new ArrayList<String[]>();
flatData.add(new String[] { "A", "1", "i" });
flatData.add(new String[] { "A", "1", "ii" });
flatData.add(new String[] { "A", "2", "i" });
flatData.add(new String[] { "B", "1", "i" });
flatData.add(new String[] { "B", "1", "ii" });
flatData.add(new String[] { "B", "1", "iii" });

final DefaultMutableTreeNode root = new DefaultMutableTreeNode();
final Stack<DefaultMutableTreeNode> stack =
      new Stack<DefaultMutableTreeNode>();
for (String[] row : flatData) {
  // adjust stack to match level
  final Iterator<DefaultMutableTreeNode> stackIt = stack.iterator();
  for (int level = 0; level < row.length && stackIt.hasNext(); level++) {
    if (!stackIt.next().getUserObject().equals(row[level])) {
      stack.setSize(level);
      break;
    }
  }

  // rebuild trail of stack
  for (int level = stack.size(); level < row.length; level++) {
    final String s = row[level];
    final DefaultMutableTreeNode child = new DefaultMutableTreeNode(s);
    (stack.isEmpty() ? root : stack.peek()).add(child);
    stack.push(child);
  }
}
```
Ebenius


----------



## André Uhres (11. Jul 2009)

m0ps hat gesagt.:


> Hm, ist die Methode nicht ziemlich aufwendig, wenn ich die Liste für das initialisieren der Knoten durchlaufen muss + dann nochmal um die Elemente zuzuweisen?


Ich weiss nicht, was du mit "aufwendig" meinst. Meine Version würde etwa so aussehen (vom Code her imho nicht besonders aufwendig):

```
private JTree tree;
private DefaultMutableTreeNode parent;

private void buildTree(final List<String[]> flatData) {
    for (int level = 0; level < 3; level++) {
        for (String[] fahrzeug : flatData) {
            DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(fahrzeug[level]);
            parent = (DefaultMutableTreeNode) tree.getModel().getRoot();
            findParent(tree.getModel().getRoot(), fahrzeug, level);
            if (parent != null) {//null = besteht schon
                ((DefaultTreeModel)tree.getModel()).insertNodeInto(newChild, parent, parent.getChildCount());
            }
        }
    }
}

private void findParent(final Object o, final String[] fahrzeug, final int level) {
    int cc = tree.getModel().getChildCount(o);
    for (int i = 0; i < cc; i++) {
        DefaultMutableTreeNode child = (DefaultMutableTreeNode) tree.getModel().getChild(o, i);
        if (child.getLevel() == level && child.toString().equals(fahrzeug[level - 1])) {
            parent = child;
        } else if (child.getLevel() == (level + 1) && child.toString().equals(fahrzeug[level])) {
            parent = null;//besteht schon
        }
        if (!tree.getModel().isLeaf(child)) {
            tree.expandPath(new TreePath(child.getPath()));
            findParent(child, fahrzeug, level);
        }
    }
}
```


----------



## Ebenius (11. Jul 2009)

Macht halt zur Laufzeit um Längen mehr Aufwand; bekommt man natürlich nur bei größeren Datenmengen mit.

Ebenius


----------



## André Uhres (11. Jul 2009)

Eben, und nur beim Laden der Daten. Es wurden auch keine extrem ungewöhnliche Gegebenheiten erwähnt. Zudem könnten wir uns fragen, ob so grosse Datenmengen in einem JTree überhaupt noch Sinn machen würden.


----------



## Ebenius (13. Jul 2009)

Müssen wir aber nicht. 

Ich wollte lediglich darauf hinweisen, dass es einen weniger aufwändigen Weg gibt, wenn die Daten schon sortiert vorliegen. Habe ich getan.

Ebenius


----------



## André Uhres (15. Jul 2009)

Auf die entsprechende Frage des Themenerstellers hin wollte ich nur zeigen, daß meine Version leistungsfähig genug und vom Code her nicht sehr aufwendig ist.


----------



## tomier (21. Jul 2012)

Ich finde diese Lösung echt beeindruckend.
Ich hätte nur eine Frage:
Wenn ich z.B. hätte als Eigenschaften pro Objekt ("A", "1", "i", "2000EURO,"5LiterVerbrauch") und will aber den Tree genauso nur nach den 3 Kriterien("A", "1", "i") aufbauen, ABER wenn mit einem Listener die anderen 2 Eigenschaften zusätzlich auch abrufen will, ist das mit dieser Lösung auch möglich?




Ebenius hat gesagt.:


> Wenn die Daten schon sortiert vorliegen, dann kann man's auch noch einfacher machen. Beispiel:
> 
> ```
> final List<String[]> flatData = new ArrayList<String[]>();
> ...


----------

