CTreeCtrl - Unterknoten hinzufügen



  • 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!



  • plizer schrieb:

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

    Der Schalter heißt TVS_HASLINES. Falls du das Steuerelement im Resource Editor hinzufügst, kannst du es auch manuelle über die Eigenschaften setzen.

    plizer schrieb:

    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):

    Ein HTREEITEM ist ein Handle - also so etwas wie ein eindeutiger Indetifizierer - für ein Objekt. Mit Objekt ist unter Windows nicht immer ein Objekt wie eine Klasse gemeint. Ein HWND ist auch ein Handle für ein bst. Fenster.

    plizer schrieb:

    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?

    Das erste Element ist *immer* das Wurzelelement. Wie bei einem Baum in der "echten" Welt auch. Also holst du dir erst einmal das Handle dafür mit GetRootItem. Ab hier müsstest du durch deinen Baum navigieren.

    plizer schrieb:

    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?

    Das hat windowsevolutionsspezifische Gründe und eben dann auch MFC Entiwicklungsgründe. Die MFC sind bei weitem nicht perfekt erleichtern dem Entwickler aber ungemein die Arbeit unter Windows. Sicherlich hätte man vieles einfacher/besser machen können. Aber die Entwickler werden sich schon etwas dabei gedacht haben. Genaueres kann ich dir dazu leider nicht sagen.

    plizer schrieb:

    Aber wahrscheinlich gehts euch C++-lern genauso...

    Ja. Die MFC sind ein guter Weg das Windows API in Objekten/Klassen zu kapseln. Dieser Weg hätte von mir aus aber auch konsequenter und an einigen Stellen etwas einfacher für den Endentwickler desinged werden können. Aber wie gesagt, die MFC Schöpfer werden sich bestimmt jede Menge Gedanken gemacht haben.



  • Die MFC-Schöpfer werden sich nichts dabei gedacht haben. Sie werden damals einfach keine andere Möglichkeit gehabt haben. Die Win-API (C, kein C++) ist jetzt sicherlich mehr als 20 Jahre alt, die MFC hat die Welt erblickt als es noch keinen C++-Standard gab (da hat der MS-Compiler wahrscheinlich gerade mal das Schlüsselwort class gekannt ;)). Die WinAPI und MFC sind einfach alt. Und man kann nicht erwarten, das sie mit modernen GUI-Framworks mithält. Aber dafür ist sie für Windows ein mächtiges FW, gerade wegen ihres Alters.

    Wem der originale MFC-Tree zu umständlich ist, kann ja mal unter Codeproject schauen, ob er nicht einen moderneren und intuitiveren MFC-Tree findet.

    @plizer! Es gibt für C++ GUI-Frameworks die eindeutig intuitiver sind. Diese basieren aber nicht auf alte APIs, sondern zeichnen wie Java Swing ihren Baum dann selber. Ergo können sie auch C++ in seinen schönen Möglichkeiten ausschöpfen. Und dann ist so ein Baum auch wirklich objektorientiert, wie der JTree und sein dazugehörigen TreeModel. Da wäre z.B. der Tree von gtkmm oder Item View von Qt.



  • Thx euch beiden! Wusste nicht, dass die MFC schon soo alt ist!

    Mich hat gerade mal die Performance von Java und C++ bei einer ganz einfachen Rechnung interessiert und folgenden Quelltext geschrieben:

    C++:

    #include "stdafx.h"
    #include <time.h>
    
    int main(int argc, char* argv[])
    {
        int ergebnis = 0;
    	long start = time(NULL);
        for(int i=0; i<100000; i++) {
    		for(int j=0; j<100000; j++) {
    			ergebnis = i*j;
    		}
    	}
        cout << "Gesamtzeit: " << time(NULL)-start; 
    	return 0;
    }
    

    und das gleiche in Java:

    public class Main {
        public Main() {
        }
    
        public static void main(String[] args) {
            // TODO code application logic here
    
            long start = System.currentTimeMillis();
            int ergebnis = 0;
            for(int i=0; i<100000; i++) {
                for(int j=0; j<100000; j++) {
                    ergebnis = i*j;
                }
    	}
            long gesamt = System.currentTimeMillis() - start;
            System.out.println("Gesamtzeit: " + gesamt);
        }
    }
    

    Nun hat es in C++ ca. 30 Sekunden gedauert und in Java ca. 20 Sekunden! Wie kann das sein? Ich hätte eigentlich erwartet, dass Java langsamer sein würde.



  • Naja, hängt vieles vom C++-Compiler und den Einstellungen ab. Man müsste schon deine Compiler-Flags wissen. Weiterhin hast du sicherlich eine aktuelle JRE mit aktuellem Hotspot benutzt. Mußt du natürlich für C++ genauso machen: aktuellen Compiler und Flags so anpassen, das sie auf deine CPU optimiert sind. Aber ich denke mal, du hast einfach ganz naiv eine EXE mit Debug-Infos erstellt. 😉



  • Mein Ergebnis:
    Mit MinGW-Compiler (GCC3.4, also einer von der alten Schule 😉 ), Compiler-Flag -O2: 5 Sekunden
    Mit JRE 1.5: 34 Sekunden



  • Thx fürs Testen... Ich habe hier ne nette Seite gefunden: http://shootout.alioth.debian.org/, dort werden für die unterschiedlichsten Programmiersprachen bestimmte Programmteile/Algorithmen getestet.

    Aber inzwischen bin ich noch verzweifelter als noch vor einem Monat. Für den Teil den ich programmieren muss, wurde damals als derjenige, der noch da war 1 Manntag dafür angegeben und der Typ hätte das wohl auch in der Zeit geschafft. Ich sitze nun schon fast 1 Monat dadran und werde bestimmt noch einen weiteren Monat brauchen, wenn ich es überhaupt irgendwann fertig wird.

    Immer wieder Linker-Fehler weil von den hunderten von selbst geschriebenen DLL's wieder irgendeine fehlte. Dazu diese Vermischung von ATL,WTL und MFC in den Projekten, wodurch die wirresten Fehlermeldungen entstehen. Dazu dieses total veraltete System. Ich bin schon richtig schlecht gelaunt und werd schon aggressiv wenn ich 9 Stunden am Tag nur nach Fehlerlösungen suche ohne auch nur eine Zeile zu programmieren :(.

    Ich werde mich wohl jetzt einfach wieder bewerben als Entwickler für C# oder Java. Nur frage ich mich, wie sich das im Lebenslauf macht, wenn man gleich wieder bei ner Firma abhaut, wo man gerade angefangen ist...



  • 😞 Also das hört sich nicht gerade toll an. Kann mir das gut vorstellen, das diese Umstellung einen resignieren lassen kann. Wobei man hinterfragen sollte, warum du so viele Linkfehler bekommst? Hat dein Vorgänger kein korrektes Build-System "hinterlassen"? Er muß ja auch irgendwie gearbeitet haben, ohne Errors. Warum ist er überhaupt von der Firma abgehauen? Vielleicht ist ihm das ganze selber über den Kopf gewachsen? Hunderte DLLs hört sich auch nicht gerade übersichtlich an... um nicht zu sagen, es hört sich komplex an. DLLs schön und gut, aber man kann es auch übertreiben. Keine Modularität ist schlecht, aber auch auf brechen und biegen das andere Extrem. Oder sind das alles ActiveX-Komponenten?

    Vielleicht kann man sich ja auch zur Aufgabe machen, das ganze endlich mal aufzuräumen? 😉 Z.B. kann man den Sinn von sovielen DLLs hinterfragen (nicht gleich als sinnlos hinstellen, aber hinterfragen!). Und evtl. vieles in weniger DLLs zusammenfassen oder in statischen Libraries ummodeln?

    Keiner kennt hier das Projekt, also kann man nicht wirklich helfen.

    Aber einen Tree mit map usw. haste doch schon geschafft, oder? Also zumindest "neues" scheint ja kein Problem zu sein? Oder hat es am Ende doch nicht funktioniert? Wenn es funktioniert hat, ist halt der alte Code eine Einarbeitungssache.

    Am Ende mußt du wissen, ob du dich mit dem Altprojekt weiter beschäftigen willst ? Bewerben kann man sich immer nebenbei. Und was das Intermezzo in der aktuellen Firma angeht: nach spätestens 7 oder 10 Jahren interessiert das bestimmt niemanden mehr. Bis dahin haste neue Referenzen gesammelt. Kann mir nur vorstellen, das die Bewerbung die du jetzt rausschickst, dich nach dem Grund fragen wird.



  • @Artchi: Danke für die aufmunternden Worte! 👍

    Ich kämpfe mich einfach weiter durch. Es geht ja ein bisle voran und keiner verlangt hier Wunder von mir. Und den Baum habe ich ja hinbekommen und der Aufbau geht rasent schnell (96.000 Elemente in wenigen Sekunden).

    Leider wurde in der Vergangenheit immer unter Zeitdruck gearbeitet (wo ist das auch nicht so) und daher gibt es bis für eine activeX Komponente keine Dokumentation. Dass der Hauptprogrammierer gegangen ist, lag vor allem an einem endlosen Projekt, welches ja bis jetzt anhält. Er konnte es wohl einfach nicht mehr sehen und hat trotzdem einer ordentlichen Gehaltserhöhung abgelehnt daran weiter zu arbeiten. Wollte wohl mal was neues sehen, denn Geld ist ja nicht alles.

    Ich neige ein wenig zum Aufgeben, wenn sovieles auf einmal kommt. Dabei kommt man immer am besten weiter, wenn man es immer weiter versucht. Ich werds jetzt mal ohne jammern versuchen :-). Anschließend wird ja alles neu überlegt und vielleicht wirds ja .NET mit c# (ist ja sehr ähnlich zu Java), damit hab ich meine Masterarbeit geschrieben (aber in der Bioinformatik).

    Mich würde ja interessieren, wie Du so auf dem Arbeitsmarkt gehandelt wirst. Du scheinst ja über ein enormes Grundwissen zu verfügen und so einiges auf den Kasten zu haben. Da kann man sicher einiges verdienen, oder? 😉

    Heute werde ich mich mit dem CADORecordset beschäftigen und hoffe damit Daten zu einer activeX Komponente schicken zu können, die diese Daten graphisch auswertet. Und dann bin ich schon zu 70% durch mit dem Teil, was ich hier für das Projekt machen muss (also eigentlich nicht besonders viel und für einen erfahrenen Programmierer).

    Ups, ganz schön Offtopic mittlerweile ^^.

    Schöne Grüße,
    plizer



  • Öhm, also ich bin 30, habe jedoch schon mit 22 Jahren meinen ersten Arbeitsvertrag als C++-Programmierer gehabt. 😃 Mußte ein bestehendes Projekt auf ein neues System portieren. Danach bin ich in einer anderen Firma als Java-Coder gelandet. Mache ich heute immer noch... leider. 😞 C++ vermisse ich beruflich und ist deshalb noch mein Hobby! 😋 Weil C++ am Ende, trotz seines Alters und Macken, einfach die coolere Sprache ist.


Anmelden zum Antworten