CTreeCtrl - Unterknoten hinzufügen



  • Ok, ich nehm alles zurück und behaupte das Gegenteil 🤡

    Funktioniert. Wusste nur nicht, dass Standardmäßig keine Icons dabei sind.



  • plizer schrieb:

    Sollte doch eigentlich das ergeben:

    Root
    |
    +--Child1
    | |
    | +--ChildChild
    |
    +--Child2

    Nein aber das hier. 😉

    +--Root
       |
       +--Child1
       |         |
       |        +--ChildChild
       |
       +--Child2
    

    plizer schrieb:

    Ok, ich nehm alles zurück und behaupte das Gegenteil 🤡

    Funktioniert. Wusste nur nicht, dass Standardmäßig keine Icons dabei sind.

    Meinst du Icons für jewilgen Knoten oder die Plus-/Minuszeichen? Die müssen natrülich per Flag gesetzt werden.



  • Ich hatte einfach nicht gemerkt, dass ein Baum aufgebaut wurde. Als nächsten muss ich jetzt mal schauen, wie das mit den Bildern geht. Danke für Deine Hilfe!



  • plizer schrieb:

    Ich hatte einfach nicht gemerkt, dass ein Baum aufgebaut wurde. Als nächsten muss ich jetzt mal schauen, wie das mit den Bildern geht. Danke für Deine Hilfe!

    Das ist auch kein Problem. Du weist dem TreeView eine ImageList mit SetImageList zu. Füllst diese mit Bildern.

    Beim hinzufügen von TreeView Items muss du dann das Flag TVIF_IMAGE in der Itemstruktur setzen (mask Member) und weist dem iImage Member den Index des Bildes in der ImageList zu.



  • Gibt es eine Möglichkeit zu erfragen, ob ein string schon als Unterknoten verhanden ist? Ich muss nämlich aus einer liste von strings einen Baum erstellen.
    Aus:

    A12
    A15
    A16
    A21
    A23
    A30
    B12
    B13
    B23
    C34
    

    soll werden:

    A
    +-- 1
        +-- 2
        +-- 5
        +-- 6
    +-- 2
        +-- 1
        +-- 3
    +-- 3
        +-- 0
    B
    +-- 1
        +-- 2
        +-- 3
    +-- 2
        +-- 3
    C
    +-- 3
        +-- 4
    

    Dazu muss ich nun wissen, ob ein Unterknoten ein string enthält, nur weiss ich nicht wie ich an die strings kommen soll in den nodes!

    Kannst Du mir da nen Tipp geben?



  • plizer schrieb:

    Kannst Du mir da nen Tipp geben?

    Eine Methode in CTreeCtrl dafür gibt es nicht. Du müsstest beim hinzufügen von Knoten vorher die vorhanden durchlaufen und prüfen ob "der Neue" schon existiert. Falls nicht fügst du ihn hinzu.



  • HaJo. schrieb:

    plizer schrieb:

    Kannst Du mir da nen Tipp geben?

    Eine Methode in CTreeCtrl dafür gibt es nicht. Du müsstest beim hinzufügen von Knoten vorher die vorhanden durchlaufen und prüfen ob "der Neue" schon existiert. Falls nicht fügst du ihn hinzu.

    Genau so wollte ich das machen! Allerdings weiss ich nicht, wie ich an den string eines vorhandenen Knoten kommen kann! Ich bekomme ja immer nur an HTREEITEM dran.



  • plizer schrieb:

    Genau so wollte ich das machen! Allerdings weiss ich nicht, wie ich an den string eines vorhandenen Knoten kommen kann! Ich bekomme ja immer nur an HTREEITEM dran.

    Mit GetNextSiblingItem / GetPrevSiblingItem kannst du die Items durchwandern. und mit GetItemText erhälst du einen CString mit dem zugehörigen Text welchen du mit Compare vergleichen könntest.



  • HaJo. schrieb:

    plizer schrieb:

    Genau so wollte ich das machen! Allerdings weiss ich nicht, wie ich an den string eines vorhandenen Knoten kommen kann! Ich bekomme ja immer nur an HTREEITEM dran.

    Mit GetNextSiblingItem / GetPrevSiblingItem kannst du die Items durchwandern. und mit GetItemText erhälst du einen CString mit dem zugehörigen Text welchen du mit Compare vergleichen könntest.

    Danke für Deine Unterstützung! 🙂 Mit den Daten sollte ich es dann hinbekommen!



  • Ich kanns nicht glauben, dass ich nach mindestens 2 Manntage es immer noch nicht hinbekommen habe, in einem CTreeCtrl zu schauen, ob ein Unterknoten mit einem bestimmten string vorhanden ist und falls nicht, diesen einzufügen.

    Ich habe mir alle interessanten MSDN Beispiele zum CTreeCtrl angeschaut und alles versucht. Aber die Beispiele entbehren sich für mich jeder Logik, so dass ich da einfach nichts hinbekomme.
    Beispiel:

    HTREEITEM hmyItem;
    if (pmyTreeCtrl->ItemHasChildren(hmyItem))
    {
    ...
    

    hmyItem ist doch undefiniert. Wie kann ich dann anschließend einer Methode ein undefiniertes Objekt (bzw. eine Kopie) in der Parameterliste übergeben? Oder wird hmyItem ein neuer Wert zugeordnet? (Weil anschließend damit weitergearbeitet wird) Wenn das so ist, werde ich das wohl nie wirklich verinnerlichen, weil ich das für mich sehr unlogisch ist.

    😞



  • plizer schrieb:

    hmyItem ist doch undefiniert. Wie kann ich dann anschließend einer Methode ein undefiniertes Objekt (bzw. eine Kopie) in der Parameterliste übergeben? Oder wird hmyItem ein neuer Wert zugeordnet? (Weil anschließend damit weitergearbeitet wird) Wenn das so ist, werde ich das wohl nie wirklich verinnerlichen, weil ich das für mich sehr unlogisch ist.:(

    Der Parameter hItem müsste ein Handle auf das TreeView Item sein, bei dem du die Kinderprüfung durchführen möchtest.



  • HaJo. schrieb:

    plizer schrieb:

    hmyItem ist doch undefiniert. Wie kann ich dann anschließend einer Methode ein undefiniertes Objekt (bzw. eine Kopie) in der Parameterliste übergeben? Oder wird hmyItem ein neuer Wert zugeordnet? (Weil anschließend damit weitergearbeitet wird) Wenn das so ist, werde ich das wohl nie wirklich verinnerlichen, weil ich das für mich sehr unlogisch ist.:(

    Der Parameter hItem müsste ein Handle auf das TreeView Item sein, bei dem du die Kinderprüfung durchführen möchtest.

    Danke! Hast Du dazu vielleicht einen Link wo ich Infos dazu bekomme? Ich habe zwar schon einige gute C++ Bücher hier, aber zu handles steht da nirgend etwas.

    PS: Sieben Bücher und insgesamt über 5000 Seiten und keinmal das Wort handle. Wieder einmal etwas, was ich nicht verstehe.



  • plizer schrieb:

    Danke! Hast Du dazu vielleicht einen Link wo ich Infos dazu bekomme? Ich habe zwar schon einige gute C++ Bücher hier, aber zu handles steht da nirgend etwas.

    Zu Handles oder wie du weiter vorgehen müsstest?

    PS: Sieben Bücher und insgesamt über 5000 Seiten und keinmal das Wort handle. Wieder einmal etwas, was ich nicht verstehe.[/quote]
    http://de.wikipedia.org/wiki/Handle



  • Am besten natürlich wie ich auch weiterkomme. Aber ich mags ja selbst nicht, wenn sich Leute was verkauen lassen. Also bin ich auch nicht böse wenn mir keiner hilft ;). Obwohl, lange genug sitz ich ja schon dran.

    Aber was meinst Du genau mit:

    Der Parameter hItem müsste ein Handle auf das TreeView Item sein, bei dem du die Kinderprüfung durchführen möchtest.

    Ich will also schauen, ob im CTreeCtrl ein Eintrag vorhanden ist.

    Ich lege die Items folgendermaßen an:

    HTREEITEM hRoot = m_ctlTreeCtrl.InsertItem("Wurzel", TVI_ROOT);
    HTREEITEM h1 = m_ctlTreeCtrl.InsertItem("Unterknoten", hRoot);
    HTREEITEM h2 = m_ctlTreeCtrl.InsertItem("UUnterknoten".c_str(), h1);
    HTREEITEM h3 = m_ctlTreeCtrl.InsertItem("UUUnterknoten".c_str(), h2);
    HTREEITEM h4 = m_ctlTreeCtrl.InsertItem("UUUUnterknoten".c_str(), h3);
    

    Wie kann ich nun z.B. rausfinden ob unter der "Wurzel" der Eintrag "Unterknoten" verhanden ist. Oder halt ob bei "UUUnterknoten" "UUUUnterknoten" enthalten ist.

    Da ich erst später nachfrage, kenne ich in dem Moment nicht hRoot oder h1 usw., sondern muss die Information aus dem CTreeCtrl bekommen, nur wie?



  • plizer schrieb:

    Da ich erst später nachfrage, kenne ich in dem Moment nicht hRoot oder h1 usw., sondern muss die Information aus dem CTreeCtrl bekommen, nur wie?

    Kurze Verständnisfrage. Legst du alle Elemente erst an - auch doppelte - und prüfst "irgendwann" später oder möchtest du beim Anlegen immer gleich prüfen ob ein Knoten mit dem String X schon existiert?



  • Ich bekomme die einzelnen Strings aus einer Datenbank, die vereinfacht so aussehen:

    A12
    A15
    A16
    A21
    A23
    A30
    B12
    B13
    B23
    C34
    

    Daraus soll dann der unten dargestellte Baum werden. Ich habe den String schon aufgeteilt, so dass ich 5 Variablen habe, die bis zu 5 Ebenen tief gehen. Natürlich soll er das A am Anfang z.B. nur einmal anlegen, wenn es da ist, kann er direkt den Unterpunkt einfügen, aber natürlich nur falls dieser auch noch nicht da ist usw.
    Algorithmisch gesehen macht mir das keine Probleme, aber ich kann mit dem CTreeCtrl überhaupt nicht umgehen!

    A
    +-- 1
        +-- 2
        +-- 5
        +-- 6
    +-- 2
        +-- 1
        +-- 3
    +-- 3
        +-- 0
    B
    +-- 1
        +-- 2
        +-- 3
    +-- 2
        +-- 3
    C
    +-- 3
        +-- 4
    


  • Hmm nun gut. Deine Datenbank scheint sortiert zu sein. Erst alle Werte mit A dann B ...

    // hParentItem gibt das Elternelement an mit desses Kindelementen der Stringvergleich duchgeführt werden soll
    bool CMyDialog::NodeExists(const HTREEITEM &hParentItem, const CString &NodeValue)
    {
        if (this->m_TreeView.ItemHasChildren(hParentItem))
        {
            // Erstes Kindelement
            HTREEITEM hItem = this->m_TreeView.GetNextItem(hParentItem, TVGN_CHILD);
    
            while(hItem != NULL)
            {
                // Text des Knotens holen
                CString Text = this->m_TreeView.GetItemText(hItem);
    
                // Strings vergleichen
                if (NodeValue.Compare(Text) == 0)
                    return true;
    
                // Nächsten Knoten holen
                this->m_TreeView.GetNextItem(hItem, TVGN_NEXT);
            }
        }
    
        return false; // Keine Kinder
    }
    
    void CMyDialog::OnBnClickedButton1()
    {
        TVINSERTSTRUCT TvStruct;
        TVITEMEX       &TvItemEx      = TvStruct.itemex;
        HTREEITEM      hRootItem      = 0; // Wurzel Knoten Ebene 0
        HTREEITEM      hCharacterItem = 0; // Buchstaben Knoten (A, B, ...) Ebene 1
        CString        CharNode,
                       NumNode;
    
        TvStruct.hParent      = NULL;
        TvStruct.hInsertAfter = TVI_ROOT;
    
        TvItemEx.mask    = TVIF_TEXT;
        TvItemEx.pszText = "Ich bin die Wurzel";
    
        // (1) Als erstes den Wurzelknoten
        if ((hRootItem = this->m_TreeView.InsertItem(&TvStruct)) == NULL)
        {
            // Fehler
        }
    
        TvStruct.hParent      = hRootItem;
        TvStruct.hInsertAfter = TVI_LAST;
    
        // (2) Die Buchstabenknoten hinzufügen vorher prüfen ob Knoten schon existiert
        if (!NodeExists(hRootItem, CharNode))
        {
            TvItemEx.pszText = CharNode.GetBuffer(); // Hier die Buchstaben angeben
    
            if ((hCharacterItem = this->m_TreeView.InsertItem(&TvStruct)) == NULL)
            {
                // Fehler
            }
    
            // (3) Hier di Zahlenknoten hinzufügen und auch vorher prüfen
            if (!NodeExists(hCharacterItem, NumNode))
            {
                TvStruct.hParent = hCharacterItem;
                TvItemEx.pszText = NumNode.GetBuffer(); // Hier die Zahlen angeben
                if (this->m_TreeView.InsertItem(&TvStruct) == NULL)
                {
                    // Fehler
                }
            }
        }
    }
    

    So in etwa sollte es gehen. Die Schritte 2/3 sollten natürlich in eine Schleife. Der Code ist ohne Gewähr und ich habe ihn nicht getestet.



  • @HaJo.: Vielen, vielen Dank! 🙂 Da hab ich ja schon ein schlechtes Gewissen, dass Du das so mal eben für mich gemacht hast!

    Ich werde versuchen es sofort zu implementieren.

    Nochmals vielen Dank! 🙂

    Schöne Grüße,
    plizer



  • HaJo. schrieb:

    plizer schrieb:

    Ich hatte einfach nicht gemerkt, dass ein Baum aufgebaut wurde. Als nächsten muss ich jetzt mal schauen, wie das mit den Bildern geht. Danke für Deine Hilfe!

    Das ist auch kein Problem. Du weist dem TreeView eine ImageList mit SetImageList zu. Füllst diese mit Bildern.

    Beim hinzufügen von TreeView Items muss du dann das Flag TVIF_IMAGE in der Itemstruktur setzen (mask Member) und weist dem iImage Member den Index des Bildes in der ImageList zu.

    Ich bin nun dabei die Plus- und Minuszeichen in dem Baum darzustellen. Wie wird dies in MFC gemacht mit dem Flag?

    Was ich auch noch nicht verstehe, weil ich wohl immer noch nur in Objekten denke (HTREEITEM ist ja kein Objekt und kann es einfach nicht bei mir im Hirn zuordnen):
    Wie komme ich denn an das erste Element im Baum? Ich hab die MSDN für CTreeCtrl vorliegen und finde Methoden wie SelectItem(), GetParentItem(), aber diese brauchen ja alle schon HTREEITEM, aber da will ich ja drankommen! Also wo ist mein Denkfehler?
    Warum wird es denn nicht z.B. so gelöst, wenn ich den Text des ersten Unterknoten des ersten Element haben will (Methoden erfunden)?
    String text = tree.getItem(0).getItem(0).getText();
    Das wäre doch soviel einfacher, oder denk ich das nur?
    Ich brauch bei Java praktisch keine Hilfe mehr, weil die Klassen- und Methodennamen und der immer gleiche Aufbau alles an Informationen geben, was ich brauche. Aber wahrscheinlich gehts euch C++-lern genauso...



  • War vielleicht jetzt ein blödes Beispiel, weils so in Java auch nicht aussehen würde, aber vielleicht weiss jemand, wie ich das meine!


Anmelden zum Antworten