Swing Kategoriebaum aus Datenbank erstellen

xadoX

Aktives Mitglied
Habe eine Datenbank bestehend aus knapp 30.000 Kategorien.
Folgende Struktur ist vorhanden:

CategoryID, CategoryLevel, CategoryName, CategoryParentID, LeafCategory.

Mit diesen Daten versuche ich ein wenig verzweifelt einen Kategoriebaum mittles jTree aufzubauen.
Im Grunde brauch ich nur das root Element (was wir hier einfach mal "Kategorien" nennen), denn das rootElement kann man ja einfach dem Konstruktor übergeben.

Habe mir folgene Funktion geschrieben. Nachdem das Programm 10 Minuten lang keine Reaktion mehr aufnehmen wollte hab ich es abgeschossen.

Java:
/**
     * Baut den Kategoriebaum aus der Datenbank auf
     * @return das Wurzelelement des Baums
     */
    public DefaultMutableTreeNode getCategories(){
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Kategorien");
        return getCategoriesLevel(1, root);
    }

   /**
     * Erstellt die Kategorien des i'ten Levels
     * @param level Kategorielevel
     * @param root Wurzelelement
     * @return Wurzelelement
     */
    public DefaultMutableTreeNode getCategoriesLevel(int level, DefaultMutableTreeNode root){
        DefaultMutableTreeNode node;
        String sql, catName;
        int catID, catParID;
        boolean isLeaf;
        Statement st;
        ResultSet rs;
        Kategorie cat;
        sql = "SELECT CategoryID, CategoryName, CategoryParentID, LeafCategory FROM ebaycat WHERE CategoryLevel = "+level;
        try {
            st = cn.createStatement();
            rs = st.executeQuery(sql);
            while(rs.next()){
                catID = rs.getInt("CategoryID");
                catName = rs.getString("CategoryName");
                catParID = rs.getInt("CategoryParentID");
                isLeaf = rs.getBoolean("LeafCategory");
                cat = new Kategorie(catID, catName, catParID, isLeaf);
                node = new DefaultMutableTreeNode(cat);
                root.add(node);
                if(!isLeaf){
                    getCategoriesLevel(++level, node);
                }
            }
        } catch (SQLException ex) {
            gui.makeErrorMessage(ex.toString());
            return null;
        }
        return root;
    }

Als ich beim rekursiven Aufruf level++, statt ++level gesetzt hatte gabs nen Stackoverflow.

Seht ihr vielleicht meinen Denkfehler?
 
S

SlaterB

Gast
hmm, du weißt aus irgendeinem Grund schon die exakte Fehlerstelle, du siehst eine Variante mit der es geht, eine andere mit der es nicht geht,
was soll man denn noch dazu sagen?
mache dich schlau was ++x vs. x++ bedeutet, logge die Aufrufe, welchen Wert der Parameter jeweils hat,
ist doch alles kein Geheimnis?
 

slawaweis

Bekanntes Mitglied
Funktionsparameter sollte man nicht verändern, außer es gibt gute Gründe. So sollte man nicht ++ verwenden, sondern einfach "level+1" in dem rekursiven Aufruf.

Der Aufbau des Baums ist so nicht sinnvoll, soweit ich das interpretieren kann. Ohne das Schema zu kennen, würde ich sagen Du musst CategoryParentID als WHERE Parameter verwenden.

Wenn Du den Baum am Anfang vollständig aufbauen willst, so solltest Du alle Kategorien mit einer einzigen SQL Anweisung rauslesen und mit einer Map den Baum aufbauen. Falls der Baum abhängig von den Aktionen des Anwenders aufgebaut werden soll (d.h. Kategorien erst lesen, wenn der User einen Knoten geöffnet hat), sollte man einen TreeWillExpandListener auf das JTree verwenden.

Slawa
 

xadoX

Aktives Mitglied
Ich denke ich habe jetzt die richtige rekursive Funktion erstellt.
Wie slawaweis aber schon sagt, sollte ich mir überlegen, dass Ganze in einer einzigen Datenbankabfrage zu speichern. Ich hab jetzt nämlich fast 5000 SQL Abfragen die ca. 100 Minuten brauchen.

Da ich vorher noch nie mit Hashmaps gearbeitet hab wär ich über einen kurzen Anstoss sehr dankbar.
Weiß momentan echt nicht wie ich die Kategorien schnell in den JTree bekomme.
 

slawaweis

Bekanntes Mitglied
1. es wird eine leere Map vom Typ Map<Integer, DefaultMutableTreeNode> erstellt, sofern "CategoryID" ein Integer ist
2. es werden alle Kategorien aus der Datenbank mit einer Abfrage gelesen
3. das ResultSet wird sequentiell abgearbeitet. Für jedes Element also:
4a. falls in der Map bereits ein DefaultMutableTreeNode mit dem Schlüssel CategoryID vorhanden ist, wird dieses mit den Daten aus der aktuellen Zeile aktualisiert
4b. falls nicht, wird ein neues DefaultMutableTreeNode mit den Daten aus der aktuellen Zeile angelegt und in der Map gespeichert
5. Anhand von CategoryParentID wird der Elternknoten aus der Map geholt
6a. ist der Elternknoten vorhanden, wird der aktuelle Knoten dem Elternknoten als Kind zugewiesen
6b. falls nicht, wird ein neuer Elternknoten mit der CategoryParentID als Schlüssel angelegt, in der Map abgelegt und das Kind wird zugewiesen.

Jetzt ist die Frage, wie sehen die Root-Elemente aus? Gibt es nur einen Wurzelknoten in der Datenbank oder mehrere? Wurzelknoten haben keine Eltern, d.h. CategoryParentID muss NULL, 0, -1 oder was ähnliches sein. Wenn man es weis, muss man noch mal die Map durchgehen und alle DefaultMutableTreeNode mit so einer CategoryParentID rausholen und in den Wurzelknoten des JTree stecken. Oder man merkt sich diese Knoten beim Abarbeiten des ResultSet. Weiterhin ist noch die Rolle von CategoryLevel mir unklar.

Nach diesem Algorithmus sollte der Baum jetzt vollständig aufgebaut sein, falls dieser auch korrekt in der Datenbank lag. Falls z.B. CategoryParentID auf einen Elternknoten verweist, welcher nicht mehr in der Datenbank ist, wird zwar ein Teilbaum in der Map vorhanden sein, aber nicht mehr im Ergebnisbaum.

Slawa
 

xadoX

Aktives Mitglied
Danke für deine ausführliche Hilfe.

Die CategoryParentID von den root-Element ist leider die gleiche wie deren CategoryID. Da kann ich aber CategoryLevel nutzen. Wäre es dann nicht sinnvoll der Map einen weiteren Integer hinzuzufügen?
Einen für CategoryLevel? Dann kann man später abfragen welche Kategorie eine root Kategorie ist.

4a. falls in der Map bereits ein DefaultMutableTreeNode mit dem Schlüssel CategoryID vorhanden ist, wird dieses mit den Daten aus der aktuellen Zeile aktualisiert

Dieser Fall tritt nur dann auf, wenn zuvor 6b eingetreten ist, also ein Schlüssel mit CategoryParentID erzeugt wurde, aber dieser noch kein DefaultMutableTreeNode zugeordnet wurde, richtig?
 

slawaweis

Bekanntes Mitglied
Die CategoryParentID von den root-Element ist leider die gleiche wie deren CategoryID. Da kann ich aber CategoryLevel nutzen. Wäre es dann nicht sinnvoll der Map einen weiteren Integer hinzuzufügen?
Einen für CategoryLevel? Dann kann man später abfragen welche Kategorie eine root Kategorie ist.
kannst Du bitte die Rolle von CategoryParentID und CategoryLevel erklären? Mir ist ganz klar, für was die beiden jeweils zuständig sind.

Dieser Fall tritt nur dann auf, wenn zuvor 6b eingetreten ist, also ein Schlüssel mit CategoryParentID erzeugt wurde, aber dieser noch kein DefaultMutableTreeNode zugeordnet wurde, richtig?
genau. Das ist eine Art Platzhalter, bis die Informationen zu diesem Knoten im ResultSet dran sind.

Slawa
 

xadoX

Aktives Mitglied
kannst Du bitte die Rolle von CategoryParentID und CategoryLevel erklären? Mir ist ganz klar, für was die beiden jeweils zuständig sind.

Nun ja, CategoryParendID ist die ID des Vaterelements. Ohne die ist es nicht möglich einen Baum zu erstellen.
CategoryLevel sagt aus auf welcher Ebene sich die Kategorie befindet. Also die rootKategorien befinden sich auf CategoryLevel 1. Deren Kinder auf 2 usw.

EDIT: Mist, habe gerade gesehen, dass man einer Hashmap nur zwei Werte übergeben kann.
Also wird die Idee CategoryLevel mit einzubringen nicht funktionieren...
 
Zuletzt bearbeitet:

slawaweis

Bekanntes Mitglied
Nun ja, CategoryParendID ist die ID des Vaterelements. Ohne die ist es nicht möglich einen Baum zu erstellen.
CategoryLevel sagt aus auf welcher Ebene sich die Kategorie befindet. Also die rootKategorien befinden sich auf CategoryLevel 1. Deren Kinder auf 2 usw.
das ergibt keinen Sinn, das wäre eine redundante Information. Die Ebenen ergeben sich über die CategoryParendID. Was passiert, wenn z.B. ein Knoten Level 4 hat, aber der Parent Level 2? Weiterhin ist CategoryLevel nicht eindeutig, den Kinder von verschiedenen Eltern können den selben Level Wert haben. So ist es für eine Map nicht zu gebrauchen.

Die Wurzeln sind übrigens ganz einfach zu identifizieren. Wenn CategoryParentID == CategoryID ist, ist es eine Wurzel, andernfalls ein Knoten/Blatt.

Slawa
 
S

SlaterB

Gast
> Was passiert, wenn z.B. ein Knoten Level 4 hat, aber der Parent Level 2?

> Weiterhin ist CategoryLevel nicht eindeutig, den Kinder von verschiedenen Eltern können den selben Level Wert haben.

ist das nicht zweimal dasselbe Problem? ;)
 

xadoX

Aktives Mitglied
Ok, der Wert für CategoryLevel ist vielleicht nur dann sinnvoll, wenn man erst nur die root-Element aufbauen will. Dann kann man einfach abfragen wo CategoryLevel = 1 ist

Was passiert, wenn z.B. ein Knoten Level 4 hat, aber der Parent Level 2?

Dieser Fall kann nicht eintreten.
 

xadoX

Aktives Mitglied
Habs jetzt so gelöst und es scheint auch zu funktionieren. Allerdings ergaben einigen Stichproben, dass nicht alle Kategorien angezeigt werden. Hier der Code. Sieht vielleicht jemand meinen Fehler?

Java:
public DefaultMutableTreeNode getCategoriesLevel(DefaultMutableTreeNode root){
        DefaultMutableTreeNode node, dummy_node;
        Kategorie cat1;
        HashMap<Integer,DefaultMutableTreeNode> h = new HashMap<Integer,DefaultMutableTreeNode>();
        String sql, catName;
        int catID, catParID, catLevel;
        boolean isLeaf;
        Statement st;
        ResultSet rs;
        Kategorie cat;
        sql = "SELECT CategoryID, CategoryLevel, CategoryName, CategoryParentID, LeafCategory FROM ebaycat";
        try {
            st = cn.createStatement();
            rs = st.executeQuery(sql);
            while(rs.next()){
                catID = rs.getInt("CategoryID");
                catName = rs.getString("CategoryName");
                catParID = rs.getInt("CategoryParentID");
                isLeaf = rs.getBoolean("LeafCategory");
                catLevel = rs.getInt("CategoryLevel");
                cat = new Kategorie(catID, catLevel, catName, catParID, isLeaf);
                node = new DefaultMutableTreeNode(cat);
                if (h.containsKey(catID)){
                    dummy_node = (DefaultMutableTreeNode)h.get(catID);
                    cat1 = (Kategorie)dummy_node.getUserObject();
                    cat1.setCatID(catID);
                    cat1.setCatName(catName);
                    cat1.setCatParID(catParID);
                    cat1.setIsLeaf(isLeaf);
                } else{
                    h.put(catID, node);
                }
                if(h.containsKey(catParID)){
                    if (catLevel != 1){
                        dummy_node = (DefaultMutableTreeNode)h.get(catParID);
                        dummy_node.add(node);
                    }
                } else{
                    dummy_node = new DefaultMutableTreeNode(new Kategorie(0,0,null,0,false)); //dummy Node
                    dummy_node.add(node);
                    h.put(catParID, dummy_node);
                }
                if(catLevel == 1){
                    root.add(h.get(catID));
                }
            }
        } catch (SQLException ex) {
            gui.makeErrorMessage(ex.toString());
            return null;
        }
        return root;
    }
 
S

SlaterB

Gast
wenn du weißt welche konkreten Kategorien betroffen sind, dann prüfe doch was exakt an dieser Stelle passiert,
prüfe ob die entsprechene Kategorie als ein Ergebnis der Query vorhanden ist
if ("xy".equals(catName)) {
System.out.println("ist da");
}
prüfe zu welchem parentNode eingefügt wird usw.
 

xadoX

Aktives Mitglied
Hab folgendes rausbekommen. In der Datenbank liegen 29820 Kategorien.

Das hier wird 2848 mal aufgerufen
Java:
if (h.containsKey(catID)){
                    dummy_node = (DefaultMutableTreeNode)h.get(catID);
                    cat1 = (Kategorie)dummy_node.getUserObject();
                    cat1.setCatID(catID);
                    cat1.setCatName(catName);
                    cat1.setCatParID(catParID);
                    cat1.setIsLeaf(isLeaf);
                    vorhanden++;

und das hier 26972 mal

Code:
else{
                    if(h.put(catID, node)== null) {
                        nichtvorhanden++;
                    }

Also 29820 mal.

Wenn ich mir am Ende des Codes die Kategorienanzahl der root ausgeben lasse komm ich nur auf 4385.
Das hab ich so gemacht.

Java:
int sum = 0;
        for (int i = 0; i<root.getChildCount();i++){
            sum++;
            if(root.getChildAt(i).getChildCount()!=0){
                for (int j = 0; j<root.getChildAt(i).getChildCount();j++){
                    sum++;
                    if(root.getChildAt(i).getChildAt(j).getChildCount()!=0){
                        for (int k = 0; k<root.getChildAt(i).getChildAt(j).getChildCount();k++){
                            sum++;
                            if(root.getChildAt(i).getChildAt(j).getChildAt(k).getChildCount()!=0){
                                for (int l = 0; l<root.getChildAt(i).getChildAt(j).getChildAt(k).getChildCount();l++){
                                    sum++;
                                     if(root.getChildAt(i).getChildAt(j).getChildAt(k).getChildAt(l).getChildCount()!=0){
                                         for (int m = 0; m<root.getChildAt(i).getChildAt(j).getChildAt(k).getChildAt(l).getChildCount();m++){
                                             sum++;
                                             if(root.getChildAt(i).getChildAt(j).getChildAt(k).getChildAt(l).getChildAt(m).getChildCount()!=0){
                                                 for (int n = 0; n<root.getChildAt(i).getChildAt(j).getChildAt(k).getChildAt(l).getChildAt(m).getChildCount();n++){
                                                     sum++;
                                                     if(root.getChildAt(i).getChildAt(j).getChildAt(k).getChildAt(l).getChildAt(m).getChildAt(n).getChildCount()!=0)
                                                         System.out.println("noch mehr");
                                                 }
                                             }
                                         }
                                     }
                                }
                            }
                        }
                    }

                }
            }
        }
 
S

SlaterB

Gast
hübscher Schleifen-Salat,
du weißt dass du lokale Variablen, etwa
Node k = root.getChildAt(i).getChildAt(j).getChildAt(k);
anlegen kannst?

die natürlichste Ursache wäre, wenn einfach nicht alle Kategorien miteinander verknüpft sind, nicht bis zu root hinausführen,
such dir wie gesagt einfach eine konkrete fehlende Id raus und schaue dazu detailliert noch,
oder durchlaufe alternativ die Map

Java:
for (Node n : map) {
   suche wiederholt Parent zum Parent zum Parent usw. zum Node,
   if Parent == root, dann x+1 // x sollte am Ende 4385 sein
   else Ausgabe 'Problemkategorie == .., höchster Parent != root == ..'
}
 

xadoX

Aktives Mitglied
for (Node n : map) {

Diese Art von Schleife kenn ich leider nicht. Kannst du sie mir mit meinen Variablen posten?

die natürlichste Ursache wäre, wenn einfach nicht alle Kategorien miteinander verknüpft sind, nicht bis zu root hinausführen,

Dann versteh ich nicht, warum mir mein jTree von der Wurzel aus folgenden Pfad anzeigt:

Sport -> Fußball

Fußball hingen müsste noch sechs weitere Unterkategorien haben.
 
Zuletzt bearbeitet:
S

SlaterB

Gast
for (DefaultMutableTreeNode n : h.values()) {
}

edit:
und ich verstehe nicht, inwiefern dein Beispiel einer einzelnen vorhandenen Verknüpfung meiner Aussage,
dass nur 4000 Elemente von root aus verknüpft sind, der Rest nicht, widerspricht
 

xadoX

Aktives Mitglied
Mh ich versteh es grad auch nicht...

Versuche grad deine Schleife zu implementieren, aber verzweifle ein wenig.
Wärst du so nett und mir die Schleife doch nochmal etwas genauer zu erklären?
 
S

SlaterB

Gast
wärst du so nett, deinen Code (zu dieser Schleife bisher), deine Verzweiflung und sonstigen relevanten Dinge zu erklären?
 

xadoX

Aktives Mitglied
Klar :)

Java:
for (DefaultMutableTreeNode n : h.values()) {
            DefaultMutableTreeNode parent = (DefaultMutableTreeNode)n.getParent();
            while (parent != root){
                parent = (DefaultMutableTreeNode)parent.getParent();
                if (parent == null){
                    continue;
                }
                if (parent == root){
                    x++;
                }
            }
        }
        System.out.println("x: "+x);
 
S

SlaterB

Gast
und besteht eine Frage? ist nicht exakt so wie ich dachte, aber für x könnte schon das richtige rauskommen?
wohl eher nicht wenn du dich beschwerst
 

xadoX

Aktives Mitglied
Ich krieg ne Nullpointerexception an der Stelle

Java:
parent = (DefaultMutableTreeNode)parent.getParent();
 
S

SlaterB

Gast
und kein Interesse bzw. Nachdenken dazu, dieses Problem zu lösen?
wenn parent null ist, dann muss n oder ein Node auf dem Weg nach oben ein Node ohne Parent sein,
schau dir diesen Node an, gib die Kategorie aus,
dann gehe zurück zum Aufbau-Code, wieder mit dem von mir schon vorgeschlagenen Namensvergleich exakt diese Kategorie genauer untersuchen, was wird dort als Parent gesetzt oder eben nicht gesetzt?

dem Code nach müsste dort jeder Node irgendwo höher eingefügt werden, wird dabei überhaupt der parent korrekt gesetzt?
wenn nicht, dann musst du das anscheinend erst manuell selber machen
 
T

Tomate_Salat

Gast
dann musst du eben noch eine null-prüfung einbauen:
Java:
while (parent != null && parent != root)

damit kannst du dir eigentl. die eine if-abfrage sparen.
 

xadoX

Aktives Mitglied
Habs jetzt so implementiert.
X ergibt 3399.
Also 3399 Kategorien kommen bis zur root.
X ergibt 23554.
Also 23554 Kategorien die irgendwo keinen Vater mehr haben.

Java:
int x = 0;
        int y = 0;
        for (DefaultMutableTreeNode n : h.values()) {
            DefaultMutableTreeNode parent = (DefaultMutableTreeNode)n.getParent();
            if (parent != null){
                while (parent != root){
                    parent = (DefaultMutableTreeNode)parent.getParent();
                    if (parent == null) {
                        System.out.println(((Kategorie)n.getUserObject()).getCatName()+" CatID: "+((Kategorie)n.getUserObject()).getCatID());
                        y++;
                        break;
                    }
                    if (parent == root){
                        x++;
                    }
                }
            }
        }
        System.out.println("x: "+x);
        System.out.println("y: "+y);

Jetzt gibts allerdings wieder etwas sehr merkwürdiges.

Im JTree komm ich nur bis Pfad

Antiquitäten & Kunst -> Glas & Kristall

Glas & Kristall müsste noch folgende Unterkategorien haben:

Dekorglas -> Briefbeschwerer

Bei der Ausgabe wird "Briefbeschwerer" gelistet (also hat irgendwann auf dem Weg nach oben keinen Vater)
Dekorglas wird hingegen unlogischerweise nicht gelistet. Obwohl es der Vater vom Briefbeschwerer ist und ebenfalls im JTree nicht angezeigt wird....
 
Zuletzt bearbeitet:
S

SlaterB

Gast
parent != null kannst du nicht ignorieren, sondern das ist ein Problem in deinem Baum!
ein Entry der keinen Parent hat wird offensichtlich nicht angezeigt, interessiert dich das nicht näher?

na auf diesem Wege Schritt für Schritt zu debuggen ist übers Forum eh nicht sehr effektiv
 

xadoX

Aktives Mitglied
Du hast Recht, hab noch ein else if beigefügt.

Java:
} else if (parent == null){
                System.out.println(((Kategorie)n.getUserObject()).getCatName()+" CatID: "+((Kategorie)n.getUserObject()).getCatID());
                y++;
            }

Jetzt zeigt er x = 3399 und y = 26385 an.
3399 +26385 = 29784 + 36 root-Kategorien = 29820 (so sollte es auch sein)

Nur damit ihr das richtig versteht.
Es gibt ein root-Element "Kategorien". Darunter kommen dann die ersten 36 Hauptkategorien, die ich hier auch root-Kategorien nenne

EDIT: h.size() ergibt 29820
 
Zuletzt bearbeitet:

xadoX

Aktives Mitglied
Ich habs jetzt so gemacht wie du wolltest.

BSP.

Sport->Fußball->Bälle müsste es geben

Fußball hat die CatID 13331 und Bälle die ID 93156

Habe nun folgenden Code in die while-Schleife von Resultset eingebaut

Java:
if(h.containsKey(13331)&& h.containsKey(93156)){
                    cat3 =(DefaultMutableTreeNode)h.get(93156);
                    cat3par = (DefaultMutableTreeNode)h.get(13331);
                     if(!cat3par.isNodeChild(cat3)){
                        System.out.println("Fehler bei "+((Kategorie)node.getUserObject()).getCatName());
                        err++;
                    }
}

Am Ende des Programms ist err aber 0.
Die Verbindung zwischen cat3par und cat3 ist also die ganze Zeit vorhanden. Wird jedoch nicht dargestellt.
 
S

SlaterB

Gast
ist denn Fußball in der GUI zu sehen und Ball nicht?
wenn nein -> dann ist doch komplett egal was zwischen denen beiden ist, untersuchen was mit Fussball los ist, was ist dessen Parent usw.

wenn ja -> dein Code zeigt nicht wirklich viel, dass keine Ausgabe kommt kann tausend Gründe haben,
allein schon dass dein Code nicht ausgeführt wird, vielleicht sind aber auch die Nodes nicht in der Map, nicht in der Query,
nicht in der DB usw.,

versuche es lieber mit (einmalig am Ende ausgeführt)
Java:
System.out.println("Fussball da? "+h.containsKey(13331));
System.out.println("Bälle da? "+h.containsKey(93156));
if(h.containsKey(13331)&& h.containsKey(93156)){
    cat3 =(DefaultMutableTreeNode)h.get(93156);
    cat3par = (DefaultMutableTreeNode)h.get(13331);
   System.out.println("Beziehung korrekt? "+cat3par.isNodeChild(cat3));
}
usw., das liefert erstmals Informationen, nicht unbedingt gleich Lösungen,
Vorhandensein in Map muss nicht direkt mit Anzeige in GUI zusammenhängen,
aber zumindest irgendwelche Informationen

> Wird jedoch nicht dargestellt.

das ist durchaus möglich auch wenn die Map komplett stimmt, dann kann man in andere Richtung suchen,
dein Schleifensalat von 13:40 mit nur 4000 Elementen von root aus gesehen spricht aber für Map-Probleme, also ruhig da noch untersuchen
 
Zuletzt bearbeitet von einem Moderator:

xadoX

Aktives Mitglied
Fußball ist der Gui zu sehen und Ball nicht.
Die Datenbankeinträge sind zu 100% korrekt.

Den Code von dir hab ich vor dem "return root" ganz am Ende ausgeführt und alles ergibt true.

EDIT:

Hab den Schleifensalat jetzt geändert und mir ne rekursive Funktione geschrieben

Java:
public int getCategoryCount(DefaultMutableTreeNode root, int sum){
        for (int i = 0; i<root.getChildCount();i++){
            sum++;
            if(root.getChildAt(i).getChildCount()!=0){
                sum = getCategoryCount((DefaultMutableTreeNode)root.getChildAt(i), sum);
            }
        }
        return sum;
    }

Kommt auch 4385 Kategorien raus...
 
Zuletzt bearbeitet:
S

SlaterB

Gast
unter der Annahme, dass die Daten richtig sind, wollte ich hinsichtlich JTree-Update auf Methoden wie
DefaultTreeModel
public void valueForPathChanged(TreePath path, Object newValue)

Messaged when the user has altered the value for the item identified by path to newValue. If newValue signifies a truly new value the model should post a treeNodesChanged event.
hinweisen, aber bei kompletter Änderung passt das nicht wirklich,
und du lädst deine Daten doch sicherlich eher am Anfang, nicht mittten drin mit schon zum Teil aufgeklappten JTree?

ich denke ich kann dann nichts hilfreiches mehr beitragen, was immer ich an weiteren Ideen habe könnte ich nur sinnvoll direkt am Code ausprobieren,
ich benötigte dann also ein komplettes Testprogramm und außerdem noch eine Text-Datei mit Dummy-Daten,
muss nicht aus deiner DB sein, du kannst auch per Zufallsgenerator neue erzeugen,
müssen auch nicht 20.000 sein, am Anfang eh besser erst mit 20 oder 200 testen, bis eben ein Fehler auftritt,
das kann ich auch komplett übernehmen (mit allerdings der Möglichkeit, dass es dann keine Probleme gibt),

aber wenigstens den Quellcode soweit mit GUI mit JTree usw. bitte posten, das möchte ich nicht selber auch alles programmieren
(natürlich auch gerne nichts von alldem wenn es auf andere Weise klappt/ weiter zu forschen geht)
 

xadoX

Aktives Mitglied
Es klappt tatsächlich so wie slawaweis gepostet hat!!!

Versteh allerdings noch nicht so ganz warum? :D

Ist doch eigentlich das gleiche oder?^^

Der einzige Unterscheid ist die Variable.

slawaweis Code:

Java:
cat = new Kategorie(catID, catLevel, catName, catParID, isLeaf);
node = new DefaultMutableTreeNode(cat);
if (h.containsKey(catID)){
                    node = h.get(catID);
                    node.setUserObject(cat);
                } else{
                    h.put(catID, node);
                }

Mein Code:

Java:
cat = new Kategorie(catID, catLevel, catName, catParID, isLeaf);
node = new DefaultMutableTreeNode(cat);
if (h.containsKey(catID)){
                    dummy_node = h.get(catID);                  
                    dummy_node.setUserObject(cat);                  
                } else{
                    h.put(catID, node);
                }
 
Zuletzt bearbeitet:
S

SlaterB

Gast
gibt es denn überhaupt doppelte CategoryIDs? (edit: ach ja, vom Einfügen des Parent, vielleicht bald noch ein edit zum Rest)
im alten Code wurden dann neue Nodes erstellt und zum Parent hinzugefügt, nicht aber in die Map,
diese enthielten also zum Teil doppelte Unter-Nodes mit derselbern Id,
inwiefern das zu Problemen führt kann ich persönlich bei all meinen Blahblah wiederum nicht eindeutig sagen,
besonders kritisch wird es gewiss, wenn es unterschiedliche CategoryNamen zur selben CategoryID gibt


nun wird jedenfalls der neue doppelte Node mit dem ursprünglichen überschrieben und dieser erste dann (weiter unten) erneut in den Parent eingefügt, obwohl schon drin,
auch nicht allzu vorteilhaft wenn ich das richtig sehe, aber funktioniert den Quellcode nach,

doppelte CategoryIDs sind grundsätzlich bedenklich, besonders falls die restlichen Attribute nicht gleich sind,
aber gut wenn es soweit zumindest von slawaweis gesehen wurde ;)

edit: mit dem parent macht es dann Sinn,
Ball kommt zuerst dran, legt Dummy-Node x zu Fussball nur mit Id an,
wenn dann Fussball kommt wird im alten Code x mit den Daten aktualisiert, aber ein neu erstellter Node y weiter in Parent eingefügt,
damit ging x und Unternode Ball verloren

das Nachschauen nur nach Ids in der Map reichte also nicht, da es mehrere Nodes zu Ids gab,
na da habe ich dann hier wirklich nicht viel beigetragen
 
Zuletzt bearbeitet von einem Moderator:

xadoX

Aktives Mitglied
Und für die Erklärung gibts von mir auch noch ein DANKE :)

Jetzt werd ich mich morgen damit beschäftigen die Liste zu sortieren, da werde ich aber bei Problemen ggf. einen neuen Thread aufmachen.

Nochmals Danke!
 

slawaweis

Bekanntes Mitglied
ich habe den Quelltext einwenig vereinfacht. Anstatt containsKey() und dann get() aufzurufen, kann man gleich get() aufrufen und das Ergebnis auf null prüfen. Weiterhin habe ich dummy_node in parent_node umbenannt. Der Quelltext ist aber ungetestet.

Java:
        //...
        DefaultMutableTreeNode node, parent_node;
        //...
            while(rs.next()){
                catID = rs.getInt("CategoryID");
                catName = rs.getString("CategoryName");
                catParID = rs.getInt("CategoryParentID");
                isLeaf = rs.getBoolean("LeafCategory");
                catLevel = rs.getInt("CategoryLevel");
                cat = new Kategorie(catID, catLevel, catName, catParID, isLeaf);

                node = h.get(catID);

                if (node == null){
                    node = new DefaultMutableTreeNode();
                    h.put(catID, node);
                }

                node.setUserObject(cat);

                if(catLevel == 1){
                    root.add(node);
                    continue;
                }

                parent_node = h.get(catParID);

                if(parent_node == null){
                    parent_node = new DefaultMutableTreeNode();
                    h.put(catParID, parent_node);
                }

                parent_node.add(node);
            }
        //...



Jetzt werd ich mich morgen damit beschäftigen die Liste zu sortieren, da werde ich aber bei Problemen ggf. einen neuen Thread aufmachen.
falls es um die Sortierung der Knotenkinder geht, so sollte man diese einfach richtig einfügen. Anstatt parent_node.add(node), erstellt man eine Unterfunktion insertNodeByName(DefaultMutableTreeNode parent, DefaultMutableTreeNode node). In dieser geht man alle bisherigen Kinder des Parents durch und wo der Name passt, wird mit DefaultMutableTreeNode.insert() eingefügt.

Slawa
 

xadoX

Aktives Mitglied
Der geändert Code funktioniert auch ohne Probleme.
Sortieren klappt jetzt auch.
Hier noch der vollständige Code

Java:
try {
            st = cn.createStatement();
            rs = st.executeQuery(sql);
            while(rs.next()){
                catID = rs.getInt("CategoryID");
                catName = rs.getString("CategoryName");
                catParID = rs.getInt("CategoryParentID");
                isLeaf = rs.getBoolean("LeafCategory");
                catLevel = rs.getInt("CategoryLevel");
                cat = new Kategorie(catID, catLevel, catName, catParID, isLeaf);

                node = h.get(catID);
                //Falls noch nicht vorhanden, dann erstellt einen neuen Knoten
                //und fuege ihn der Map hinzu
                if (node == null){
                    node = new DefaultMutableTreeNode();
                    h.put(catID, node);
                }
                //Setz dem Knoten das Kategorieobjekt
                node.setUserObject(cat);
                //Falls das KategorieLevel = 1 ist, so wird der Knoten der
                //Wurzel hinzugefuegt. Schleife wird unterbrochen, da bei
                //catLevel = 1 die catID der catParID entspricht
                if(catLevel == 1){
                    root = insertNodeByName(root, node);
                    continue;
                }
                //Falls catLevel > 1 hol den Vaterknoten aus der Map
                parent_node = h.get(catParID);
                //Ist der Vater null, dann erstell einen neuen und fueg ihn
                //der Map hinzu
                if(parent_node == null){
                    parent_node = new DefaultMutableTreeNode();
                    h.put(catParID, parent_node);
                }
                //Uebergeb dem Vater den aktuellen Knoten als Kind
                //Sortiere das Kind dabei in alphabetischer Reihenfolge ein
                parent_node = insertNodeByName(parent_node, node);
            } 
        } catch (SQLException ex) {
            gui.makeErrorMessage(ex.toString());
            return null;

Und noch die Sortier-Funktion:

Java:
/**
     * Fuegt node in alphabetischer Reihenfolge beim Vater ein
     * @param parent DefaultMutableTreeNode Vater
     * @param node DefaultMutableTreeNode einzufuegender Knoten
     * @return DefaultMutableTreeNode Vater
     */
    public DefaultMutableTreeNode insertNodeByName(DefaultMutableTreeNode parent, DefaultMutableTreeNode node){
        int childcount, i;
        DefaultMutableTreeNode child;
        String catHelp, insertingCatName;
        insertingCatName = ((Kategorie)node.getUserObject()).getCatName();
        childcount = parent.getChildCount();
        for (i=0; i<childcount; i++){
            child = ((DefaultMutableTreeNode)parent.getChildAt(i));
            catHelp = ((Kategorie)child.getUserObject()).getCatName();
            if(insertingCatName.compareTo(catHelp)<0){
                parent.insert(node, i);
                return parent;
            }
        }
        parent.insert(node, childcount);
        return parent;
    }
 
Zuletzt bearbeitet:

slawaweis

Bekanntes Mitglied
sieht gut aus. Wenn es ohne Probleme läuft, dann ist alles richtig. Jetzt könnte man auch die dynamische Baumerstellung üben, wo die Kinder erst beim Aufklappen des Parents geladen werden :D

Slawa
 

xadoX

Aktives Mitglied
Da er den Baum eh innerhalb von ca. 4 Sekunden komplett aufbaut lass ich das lieber :D
Vielleichst kannst du mir bei meinem anderen Thread helfen :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Tabelle zu Datenbank hinzufügen / Apache Derby AWT, Swing, JavaFX & SWT 7
L JavaFx Textformatierung mittels Datenbank und Funktion anpassen AWT, Swing, JavaFX & SWT 5
N Java MySQL Datenbank durchsuchen? AWT, Swing, JavaFX & SWT 7
ralfb1105 JavaFX TreeView dynamisch aus Datenbank Tabelle erstellen AWT, Swing, JavaFX & SWT 22
J Searchfunktion auf einer MS Access Datenbank AWT, Swing, JavaFX & SWT 7
M TableView + Datenbank Aktualisierung AWT, Swing, JavaFX & SWT 4
Bluedaishi JavaFX Button Image aus Datenbank AWT, Swing, JavaFX & SWT 13
S Insert Umlaute in Datenbank AWT, Swing, JavaFX & SWT 5
J Suchmaschine einer Datenbank AWT, Swing, JavaFX & SWT 5
P JavaFX, TableView und Datenbank AWT, Swing, JavaFX & SWT 4
F JavaFX Von Datenbank in ListView AWT, Swing, JavaFX & SWT 4
kilopack15 Simple Datenbank mit AWT AWT, Swing, JavaFX & SWT 9
K Textvorschläge aus der Datenbank AWT, Swing, JavaFX & SWT 25
A checkbox mit allen tabllen aus datenbank befüllen AWT, Swing, JavaFX & SWT 8
C (JavaFX 8) SQLite Datenbank in einem TableView darstellen AWT, Swing, JavaFX & SWT 2
M Combo Box auswahl in eine Datenbank speichern AWT, Swing, JavaFX & SWT 1
V Java FX POJO aus Datenbank in FX TableView / Best Practice AWT, Swing, JavaFX & SWT 0
thet1983 Swing JTable mit MySQL Datenbank AWT, Swing, JavaFX & SWT 14
N JTable, AbstractTableModel aus Datenbank initialisieren AWT, Swing, JavaFX & SWT 8
D Applet GWT speichert Daten nicht in Datenbank AWT, Swing, JavaFX & SWT 2
E JList /DefaultListModel mit Datenbank verbinden AWT, Swing, JavaFX & SWT 10
M Datenbank in Jtable mit einem JButton anzeigen lassen AWT, Swing, JavaFX & SWT 4
S Frameübergreifend in Datenbank eingeloggt bleiben AWT, Swing, JavaFX & SWT 9
S Swing JComboBox mit Datenbank füllen AWT, Swing, JavaFX & SWT 16
I Jlist dynamisch aus Datenbank füllen AWT, Swing, JavaFX & SWT 14
N Formular für Suchanfragen in einer Datenbank AWT, Swing, JavaFX & SWT 3
J Swing Datenbank in ein Swingfenster importieren? AWT, Swing, JavaFX & SWT 13
K TableModel mit Daten aus Datenbank füllen AWT, Swing, JavaFX & SWT 7
C Combobox im JFrame aus Datenbank befüllen AWT, Swing, JavaFX & SWT 6
C Bild in einer Datenbank speichern? AWT, Swing, JavaFX & SWT 7
S Swing Daten aus Datenbank in JTable AWT, Swing, JavaFX & SWT 2
C Anführungszeichen in JTextArea für Datenbank ersetzen AWT, Swing, JavaFX & SWT 3
B Datensätze einer Datenbank in JTable ausgeben AWT, Swing, JavaFX & SWT 14
O JDialog anzeigen beim öffnen einer Datenbank AWT, Swing, JavaFX & SWT 4
A JList mit 2 Werten aus der Datenbank füttern AWT, Swing, JavaFX & SWT 5
G JTable aus Datenbank füllen AWT, Swing, JavaFX & SWT 4
T Warnkorb + Tabelle + Datenbank AWT, Swing, JavaFX & SWT 3
P JTree aus Datenbank für Kategorien-Realisierung AWT, Swing, JavaFX & SWT 2
P JTable (->Datenbank) editieren/updaten AWT, Swing, JavaFX & SWT 3
R Jtree aus Datenbank akutalisieren AWT, Swing, JavaFX & SWT 9
M Datenbericht aus Datenbank darstellen.(einfaches Konzept) AWT, Swing, JavaFX & SWT 2
A JTable mit MySQL Datenbank füllen AWT, Swing, JavaFX & SWT 12
C [JTable] Update der Datenbank AWT, Swing, JavaFX & SWT 6
U Bild in Datenbank speichern AWT, Swing, JavaFX & SWT 26
T JTable und Datenbank AWT, Swing, JavaFX & SWT 20
W JTextfield aktualisieren / Wert aus Datenbank neu abfragen AWT, Swing, JavaFX & SWT 2
R JTable mit Daten aus der Datenbank füllen AWT, Swing, JavaFX & SWT 3
M Daten aus Datenbank ins JTable einfügen AWT, Swing, JavaFX & SWT 4
G Bild direkt aus Datenbank anzeigen lassen AWT, Swing, JavaFX & SWT 14
M JComboBox aus Datenbank mit 2 Werten füllen AWT, Swing, JavaFX & SWT 5
M eigene GUI Bibliothek erstellen. AWT, Swing, JavaFX & SWT 10
M Mandelbrot mit BigDecimal erstellen und in der UI zeichnen, funktionierte nicht. AWT, Swing, JavaFX & SWT 1
I Hilfe bei dem Erstellen einer SQL Abfrage aus gewählten JComboBoxen AWT, Swing, JavaFX & SWT 5
C Swing ImageIcon erstellen, skalieren und verwenden AWT, Swing, JavaFX & SWT 3
T src ordner erstellen AWT, Swing, JavaFX & SWT 6
M Javafx versuch Bibliothek zu erstellen AWT, Swing, JavaFX & SWT 0
melaniemueller Confirmation Dialog erstellen AWT, Swing, JavaFX & SWT 18
izoards Outlook Mail erstellen - Signatur wird nicht angezeigt. AWT, Swing, JavaFX & SWT 3
E Putzplan erstellen AWT, Swing, JavaFX & SWT 15
news2swen automatisches erstellen eines Languagefiles AWT, Swing, JavaFX & SWT 1
W Clear Canvas und anschließendes neues Erstellen von Objekten auf Canvas aus ArrayList AWT, Swing, JavaFX & SWT 4
P Swing Programm hängt sich bei Buttondruck auf? (GUI für "Chatbot" erstellen) AWT, Swing, JavaFX & SWT 15
D runnable Jar mit Javafx erstellen(Eclipse) AWT, Swing, JavaFX & SWT 10
N Kontextmenü (Popup-Fenster) erstellen AWT, Swing, JavaFX & SWT 3
L JavaFX PropertyView mit dynamischer EditCell erstellen? AWT, Swing, JavaFX & SWT 8
C Falschfarbenbild (lineare Grauwertspreizung)aus Grauwert-Bild erstellen AWT, Swing, JavaFX & SWT 15
H Beim JFrame erstellen ein anderes schließen AWT, Swing, JavaFX & SWT 0
Z Random Butten erstellen ohne Container AWT, Swing, JavaFX & SWT 15
F Verzeichnis über GUI erstellen AWT, Swing, JavaFX & SWT 2
J Exception beim JFrame erstellen AWT, Swing, JavaFX & SWT 6
S Labels in Panel erstellen AWT, Swing, JavaFX & SWT 1
B JavaFX RadioButtons erstellen AWT, Swing, JavaFX & SWT 7
N Ausführbare Datei aus JavaFX Projekt erstellen AWT, Swing, JavaFX & SWT 22
A Objekt von einem Window erstellen? AWT, Swing, JavaFX & SWT 8
K Buttons dynamisch erstellen (NetBeans) AWT, Swing, JavaFX & SWT 10
ralfb1105 JavaFX Dynamisch TableView Spalten erstellen AWT, Swing, JavaFX & SWT 4
O Basics - Anwendung erstellen mit mehreren Szenen AWT, Swing, JavaFX & SWT 1
dereki2000 LookAndFeel Individuelles LAF erstellen AWT, Swing, JavaFX & SWT 9
C SWT Breadcrumb Zeile mit entsprechenden Hyperlinks erstellen AWT, Swing, JavaFX & SWT 0
D Swing Anwendung ohne JPanel erstellen AWT, Swing, JavaFX & SWT 1
L Chat erstellen AWT, Swing, JavaFX & SWT 13
N "Automatisches" erstellen von jButtons AWT, Swing, JavaFX & SWT 1
K Aus 2 Arrays xy - Graph erstellen AWT, Swing, JavaFX & SWT 9
K Swing outerPanel und innerPanel erstellen AWT, Swing, JavaFX & SWT 4
N Eclipse - GUI - MacBook - Buttonsichtbarkeit beim Anlegen/Erstellen AWT, Swing, JavaFX & SWT 14
Timo_neu_in_java Buttons Erstellen AWT, Swing, JavaFX & SWT 6
P JList erstellen AWT, Swing, JavaFX & SWT 4
H Musik wird nach dem erstellen der .jar Datei nicht mehr abgespielt AWT, Swing, JavaFX & SWT 1
J Statistik erstellen AWT, Swing, JavaFX & SWT 3
H GUI erstellen um JUnit Tests auszuführen AWT, Swing, JavaFX & SWT 29
H JavaFX via .fxml einen abgeleiteten Button erstellen... AWT, Swing, JavaFX & SWT 4
D Swing JComboBox (DefaultComboBoxModel) überschreibt Eintrag beim erstellen AWT, Swing, JavaFX & SWT 0
Prafy Sich ändernde Farbverläufe erstellen AWT, Swing, JavaFX & SWT 4
Thallius Swing Mehrere tausend "Panels" erstellen AWT, Swing, JavaFX & SWT 3
O Swing JList beim Klicken in der GUI erstellen AWT, Swing, JavaFX & SWT 6
M JavaFX GUI-Elemente erstellen, nachdem die GUI geladen hat AWT, Swing, JavaFX & SWT 4
U dynamisches JTree erstellen AWT, Swing, JavaFX & SWT 2
A Mit dem Scene Builder eine Collage erstellen (Bilder beziehen aus Flickr) AWT, Swing, JavaFX & SWT 1
D JavaFX build.fxbuild error beim Erstellen einer exe AWT, Swing, JavaFX & SWT 2
T JavaFX Flexible Layouts dynamisch erstellen / Design-Inspirationen AWT, Swing, JavaFX & SWT 8

Ähnliche Java Themen

Neue Themen


Oben