n. Knoten der obersten Ebene eines TreeView ermitteln



  • Hi zusammen,

    ich wühl mich seit 30 Minuten durch die Hilfe des CG2007/2010 ohne dass ich wirklich weiter komme. Ich möchte den n. Knoten der obersten Ebene eines TreeView bestimmen. Die Klasse TreeView hat ein Attribut Items, das aber alle Knoten des TreeView enthält, damit sieht ein Tree dann so aus:

    +-Node 0     [Index 0]
    | +-Node 0_1 [Index 1]
    | +-Node 0_2 [Index 2]
    +-Node 1     [Index 3]
      +-Node 1_1 [Index 4]
      +-Node 1_2 [Index 5]
    

    Ich hätte ja vermutet, dass ich an Node 1 über den Index 1 komme, da die anderen Knoten ja Kinder der Knoten der obersten Ebene sind. Lange Rede, kurzer Sinn: Wie komme ich über den Index an den vorhergehenden/folgende Sibling eines Knotens (getPrevSibling()/getNextSibling() gehen nicht, weil der Baum zwischendurch neu aufgebaut wird).



  • DocShoe schrieb:

    (getPrevSibling()/getNextSibling() gehen nicht, weil der Baum zwischendurch neu aufgebaut wird)

    Was genau meinst du damit?



  • Ich glaube, dieser Pseudo Code verdeutlicht das Problem:

    void TForm1::MoveUp( TObject* Sender )
    {
       // existiert eine Auswahl?
       if( Tree->Selected )
       {
          int Index = Tree->Selected->Index;
    
          // darf der ausgewählte Knoten nach oben verschoben werden?
          if( Index > 0 && Index < Data.size() -1 && Data.size() > 1 )
          {
             // ja, im Datenmodell das aktuelle Element mit seinem Vorgänger vertauschen
             swap( Data[Index], Data[Index -1] );
    
             // Tree neu aufbauen
             populate_tree();
    
             // Index war der zuletzt ausgewählte Knoten im Baum, da der Baum aber
             // neu aufgebaut wurde gibt es keine Auswahl mehr. Um den vormals
             // ausgewählten Knoten erneut auszuwählen muss der Knoten mit dem
             // Index (Index -1) ausgewählt werden.
          }
       }
    }
    

    Ich könnte natürlich die Eigenschaften der beiden beteiligten Knoten vertauschen, ohne den Baum neu aufzubauen... aber das müsste ich ja ausprogrammieren 😉



  • ich weiß nicht, obs das bei der VCL gibt, aber in .NET gibts eine Eigenschaft, die heißt parent und die ist 0 wenn es ein root-Knoten ist. Damit und einer Schleife könntest du dir dann eine Funktion bauen, die dir den nten Knoten zurückgibt bzw. seine ID.

    greetz KN4CK3R



  • Ich versuche mal, dein Problem anhand deiner Indextabelle nachzuvollziehen:

    Ausgangssituation:

    +-Node 0     [Index 0]
    | +-Node 0_1 [Index 1]
    | +-Node 0_2 [Index 2]
    +-Node 1     [Index 3]
      +-Node 1_1 [Index 4]
      +-Node 1_2 [Index 5]
    

    Endsituation:

    +-Node 1     [Index 0]
      +-Node 1_1 [Index 1]
      +-Node 1_2 [Index 2]
    +-Node 0     [Index 3]
    | +-Node 0_1 [Index 4]
    | +-Node 0_2 [Index 5]
    

    Gesucht: der neue Index von Node 1.

    Lösung: nimm den Index vom Vorgänger von Node 1 in der Ausgangssituation, d.h., rufe getPrevSibling()->Index vor der Transformation auf.

    Wenn du einen Node nach unten verschiebst, müßtest du die rekursive Anzahl der Subnodes des nachfolgend benachbarten Nodes herausfinden und auf den alten Index deines Nodes addieren. Das sollte auch keine Schwierigkeit sein; entweder ist

    int newIndex = Index + getNextSibling ()->getNextSibling ()->Index - getNextSibling ()->Index;
    

    , oder (falls nur ein Nachfolger existiert)

    int newIndex = Index + Items->Count - getNextSibling ()->Index;
    

    .

    Vielleicht habe ich da etwas völlig falsch verstanden, aber das scheint mir zu sein, was du suchst, oder?

    DocShoe schrieb:

    ...
             // ja, im Datenmodell das aktuelle Element mit seinem Vorgänger vertauschen
             swap( Data[Index], Data[Index -1] );
    

    Nur als Hinweis: wenn du das Modell ohnehin separat speicherst, solltest du vielleicht eine virtuelle Tree-Komponente verwenden. Das beugt Fehlern durch das doppelte Vorhandensein des Modells vor, vereinfacht die Handhabung der meisten Szenarien und ist auch meist viel schneller. (Das Comctl32-Treeview, das TTreeView wrappt, knickt meiner Erfahrung nach schon bei ein paar tausend Einträgen ein.) Für Delphi und C++Builder ist die Standardlösung das Virtual Treeview von Mike Lischke.



  • Ich hab´s inzwischen anders gelöst, aber trotzdem vielen Dank für deine Hilfe. Meine neue Lösung sieht so aus, dass ich einen aktuellen Knoten mit den Eigenschaften eines Datums versehen kann. Da ich die beiden Daten und Knoten habe, die vertauscht werden sollen, baue ich die jeweiligen Knoten neu auf. Damit bleiben auch die Zeiger gültig und ich kann getPrevSibling() benutzen, um den neu auszuwählenden Knoten bestimmen, da lediglich die Kindknoten verändert werden.
    Manchmal lohnt es sich doch wohl, ein wenig nachzudenken bevor man auf der Tastatur rumhackt :p



  • Danke auch für den virtuellen Baum, ich werde mir das bei Gelegenheit mal angucken, sieht auf jeden Fall vielversprechend aus. Ich wünschte, ich hätte vor drei Wochen davon gewusst 😉 Im aktuellen Projekt ist die Performance nicht allzuwichtig, wenn der Baum mehr als 20 Einträge hat war der Benutzer schon ziemlich fleissig.


Anmelden zum Antworten