"Tree"-Variable

  • Wenn du jetzt vor hast die UDF zu verwenden, dann würde ich wieder komplett anders arbeiten.
    Das andere waren quasi nur Workarounds da ja AutoIt OOP nativ eben nicht kann.

    Sobald du den Baum aber mit OOP umsetzen willst, stehen dir da wieder andere Ansätze zur Verfügung.
    Da würde ein String und OOP einfach keinen Sinn machen. :D

    Zu der eigentlichen Frage:
    Die Funktion gibt dir ja einen String zurück, welcher in jeder Zeile ein Suffix mit der Suchtiefe enthält. Neue Knotenpunkte einzufügen ist ja relativ einfach. Dafür kannst du die Funktion _StringInsert() nutzen. Um Knotenpunkte zu löschen reicht es ja einfach die entsprechende Zeile aus dem String zu nehmen: StringReplace(). Die entsprechende Zeile musst du jedoch vorab suchen. Da bietet sich StringRegExp() an (Je nach Suchkriterien). Natürlich kannst du auch alles in einem Rutsch mit StringRegExpReplace() erledigen.

    Vielleicht wäre es an der Stelle einmal sinnvoll zu erwähnen, wie du dir genau das vorgestellt hast. Was soll dem Baum zugefügt werden, und was gelöscht?

  • Würdest du bei OOP etwa mit Arrays arbeiten?
    Wenn ich einen Knoten lösche, muss ich ja alle anderen Knoten durchgehen und dort die Nummer ändern. Das ist momentan so mein Hauptproblem

    Mein Ziel ist es:
    Ordnerstruktu, Dateien und Berechtigungen in einem Tree1 zu speichern. Bei dem Speichern würde ich gerne vorher auswählen, was rein soll.
    Aus einer CSV-Datei importiere ich eine weitere Struktur nach Tree2 (das läuft momentan noch über ein Array).
    Danach stelle beide Trees gegenüber. Diese Trees werden dann in den zukünftigen Tree3 überführt, entweder anhand von automatischen Regeln oder einer GUI.
    Tree3 wird dann auf die vorhandene Struktur angewendet und diese entsprechend angepasst (Ordner, Verknüpfungen und Berechtigungen).

    Ich könnte sicherlich auch mit _GUICtrlTreeView arbeiten, allerdings benötige ich dann immer eine GUI und darauf möchte ich verzichten. Schließlich muss ich ja Operationen auf den Tree im Hintergrund ausführen, z.B. die ganzen Ordner etc. erstellen. Oder soll ich das Fenster dann unsichtbar im Hintergrund offen lassen?

  • Nein, ich speicher dann Objekte in Objekte. Das hat den Vorteil dass man ein Direktzugriff darauf hat und sich quasi selber erneuert, wenn Zweige im Baum bearbeitet werden. Eine Löschen und Hinzufügen Funktion hat das schon. Jetzt fehlt nur noch eine Einfügen Funktion. ^^

    Ich schick dir das Beispiel via OOP heute Abend, da ich mich jetzt erstmal noch um mein RL kümmern muss. Hab drz. Kein Zugriff mehr auf die Datei.

    Gesendet von meinem HTC Desire HD A9191 mit Tapatalk 2

  • Hallo :)
    In der angehängten "Tree UDF.zip" findest du folgende Dateien:
    - AutoItObject.au3
    - Tree.au3
    - Example.au3
    - Tree Doc.txt

    Die "Tree.au3" ist die eigentliche UDF welche's eine Baumstruktur erstellen kann.
    Diese UDF basiert auf OOP, daher ist die "AutoItObject.au3" nötig.
    Die "Example.au3" Datei enthält ein einfaches Beispiel über die Funktionsweise aller Methoden und Attribute eines Objektes.
    Bei der "Tree Doc.txt" handelt es sich um eine Dokumentation zu der "Tree.au3".

    Ich hoffe diese nun fertige UDF hilft dir weiter.
    Du kannst das Objekt ja beliebig extern erweitern, dass ist sehr vorteilhaft da du es an deine Bedürfnisse anpassen kannst.
    Die eine oder andere Funktion kannst du aus der alten UDF ja einfach übernehmen und mit nutzen.
    Damit sollte es dir eigentlich gelingen!

    Falls noch Fragen da sind, dann immer her damit!
    Habe drz. Langeweile... ^^


    €dit: Dazu ein Beispiel direkt bezogen auf dein aktuelles Problem!

    Spoiler anzeigen
    [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    #include <Array.au3>
    #include "Tree.au3"

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Global $oTree = _FromPathToTree('C:\', _AttribRules, 2)
    Global $avKeys = $oTree.Windows.Keys
    Global $sPath = $oTree.Windows.Boot ; Zugriff auf untergeordnete Knotenpunkte

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(0x40000, 'Tree', $sPath)
    _ArrayDisplay($avKeys)

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Func _FromPathToTree($sPath, $hRules, $iLevel = -1)
    Local $oTree = _Tree_Object()
    Local $hFile = FileFindFirstFile($sPath & '*')
    Local $sFile = FileFindNextFile($hFile)
    Local $bDir = @extended
    Local $bRules, $sKey, $vTmp

    [/autoit] [autoit][/autoit] [autoit]

    If $iLevel Then
    While $sFile
    $bRules = $hRules($sPath & $sFile)

    [/autoit] [autoit][/autoit] [autoit]

    If $bRules Then
    $sKey = StringRegExpReplace($sFile, '[^a-zA-Z_]', '')
    If $bDir Then
    $vTmp = _FromPathToTree($sPath & $sFile & '\', $hRules, $iLevel -1)
    $oTree.append($sKey) = ((IsObj($vTmp)) ? ($vTmp) : ($sPath & $sFile))
    Else
    $oTree.append($sKey) = $sPath & $sFile
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $sFile = FileFindNextFile($hFile)
    $bDir = @extended
    WEnd
    Else
    FileClose($hFile)
    Return
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($hFile)
    Return $oTree
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _AttribRules($sPath)
    $sAttrib = FileGetAttrib($sPath)
    Return Not StringRegExp($sAttrib, '[SHT]')
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit]

    5 Mal editiert, zuletzt von Yjuq (26. November 2014 um 00:01)

  • Vielen Dank, richtig genial :)

    Noch ein paar Verständnis-Fragen:
    Gehen bei OnAutoItExitRegister mehrere Funktionen?
    So, wie ich das verstanden habe, gibt $oTree.exists aus, an welcher Stelle das Blatt auf der Ebene ist?
    Knoten können keine Werte haben und Blätter können keine Knoten werden?
    Append hängt ein Blatt am Schluss an oder ein Knoten mit Blättern?
    Insert hängt einen Knoten direkt an die Root und zwischen alle bisherigen Knoten und Blätter?

    Ich habe mal die Ordner-Funktion zum Test erweitert, allerdings funktioniert nur der erste ArrayDisplay. Was habe ich falsch gemacht:

    Spoiler anzeigen
    [autoit]


    #cs ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    AutoIt Version: 3.3.10.2
    Author: myName

    [/autoit] [autoit][/autoit] [autoit]

    Script Function:
    Template AutoIt script.

    [/autoit] [autoit][/autoit] [autoit]

    #ce ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    ; Script Start - Add your code below here
    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    #include <Array.au3>
    #include ".\include\Tree.au3"

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Global $oTree = _FromPathToTree('C:\Users\abc\', _AttribRules, 4)
    Global $avKeys[2] = [$oTree.AppData.Keys, $oTree.AppData.Boot.Keys]
    Global $sPath[2] = [$oTree.AppData.Local, $oTree.AppData.Local.Adobe] ; Zugriff auf untergeordnete Knotenpunkte

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($sPath)-1
    MsgBox(0x40000, 'Tree', $sPath[$i])
    Next
    For $i = 0 To UBound($avKeys)-1
    _ArrayDisplay($avKeys[$i])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Func _FromPathToTree($sPath, $hRules, $iLevel = -1)
    Local $oTree = _Tree_Object()
    Local $hFile = FileFindFirstFile($sPath & '*')
    Local $sFile = FileFindNextFile($hFile)
    Local $bDir = @extended
    Local $bRules, $sKey, $vTmp

    [/autoit] [autoit][/autoit] [autoit]

    If $iLevel Then
    While $sFile
    $bRules = $hRules($sPath & $sFile)

    [/autoit] [autoit][/autoit] [autoit]

    If $bRules Then
    $sKey = StringRegExpReplace($sFile, '[^a-zA-Z_]', '')
    If $bDir Then
    $vTmp = _FromPathToTree($sPath & $sFile & '\', $hRules, $iLevel - 1)
    $oTree.append($sKey) = ((IsObj($vTmp)) ? ($vTmp) : ($sPath & $sFile))
    Else
    $oTree.append($sKey) = $sPath & $sFile
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $sFile = FileFindNextFile($hFile)
    $bDir = @extended
    WEnd
    Else
    FileClose($hFile)
    Return
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($hFile)
    Return $oTree
    EndFunc ;==>_FromPathToTree

    [/autoit] [autoit][/autoit] [autoit]

    Func _AttribRules($sPath)
    $sAttrib = FileGetAttrib($sPath)
    Return StringRegExp($sAttrib, '[D]')
    EndFunc ;==>_AttribRules

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit][/autoit]

    Ich denke, die UDF sollte im Forum so verfügbar gemacht werden, dass auch noch andere sie nutzen können :)

  • Zitat

    Gehen bei OnAutoItExitRegister mehrere Funktionen?


    Ja


    Zitat

    So, wie ich das verstanden habe, gibt $oTree.exists aus, an welcher Stelle das Blatt auf der Ebene ist?


    Nein, es gibt dir an welchen Index dieser in dem Attribut keys hat. Damit kannst du eigentlich prüfen ob der Schlüssel bereits vergeben ist. Das mit der Position ist nur intern so geregelt da ich nicht die neuste AutoItObject Version genutzt habe. Merke dir einfach: Es gibt dir zurück OB das Schlüsselwort für den Knotenpunkt bereits vergeben ist.


    Zitat

    Knoten können keine Werte haben und Blätter können keine Knoten werden?


    An den knoten hängen ja die Blätter. Die Blätter sind in dem Fall die Attribute und die Knoten das eigentliche Objekt. Demnach also: Richtig erkannt


    Zitat

    Append hängt ein Blatt am Schluss an oder ein Knoten mit Blättern?


    Append hängt dem Knotenpunkt (dem Objekt) ein weiteres Blatt (Attribut) an.


    Zitat

    Insert hängt einen Knoten direkt an die Root und zwischen alle bisherigen Knoten und Blätter?


    Ja, der Knotenpunkt wird mitten im Pfad erstellt. Du wählst den Knotenpunkt aus wo ein weiterer Knotenpunkt eingefügt wird. Du hast z.B. den Pfad $oTree.a.b.c und willst zwischen b und c einen weiteren Knotenpunkt x erzeugen. Dann rufst du die Methode einfach bei dem Objekt b auf. Sprich: $oTree.a.b.insert('x')

  • Ja, in Zeile 21 versuchst du ein Knotenpunkt auszulesen. Aber die Knotenpunkte sind halt nur Objekte welche keine eigenen Werte besitzen. Kannst du jedoch umgehen indem du ein "globales" Schlüsselwort verwendest was du einfach jedem Knotenpunkt zuordnest.

    z.B. das Schlüsselwort __obj__ oder sowas. Dann kannst du auch "Knotenpunkte auslesen" (Siehe Zeile 39):

    Spoiler anzeigen
    [autoit]

    #cs ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    AutoIt Version: 3.3.10.2
    Author: myName

    [/autoit] [autoit][/autoit] [autoit]

    Script Function:
    Template AutoIt script.

    [/autoit] [autoit][/autoit] [autoit]

    #ce ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    ; Script Start - Add your code below here
    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    #include <Array.au3>
    #include ".\include\Tree.au3"

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Global $oTree = _FromPathToTree('C:\Users\abc\', _AttribRules, 4)
    Global $avKeys[2] = [$oTree.AppData.Keys, $oTree.AppData.Boot.Keys]
    Global $sPath[2] = [$oTree.AppData.Local.__obj__, $oTree.AppData.Local.Adobe.__obj__] ; Zugriff auf untergeordnete Knotenpunkte

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($sPath)-1
    MsgBox(0x40000, 'Tree', $sPath[$i])
    Next
    For $i = 0 To UBound($avKeys)-1
    _ArrayDisplay($avKeys[$i])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    Func _FromPathToTree($sPath, $hRules, $iLevel = -1)
    Local $oTree = _Tree_Object()
    Local $hFile = FileFindFirstFile($sPath & '*')
    Local $sFile = FileFindNextFile($hFile)
    Local $bDir = @extended
    Local $bRules, $sKey, $vTmp

    [/autoit] [autoit][/autoit] [autoit]

    $oTree.append('__obj__') = $sPath ; HINZUGEFÜGT!

    [/autoit] [autoit][/autoit] [autoit]

    If $iLevel Then
    While $sFile
    $bRules = $hRules($sPath & $sFile)

    [/autoit] [autoit][/autoit] [autoit]

    If $bRules Then
    $sKey = StringRegExpReplace($sFile, '[^a-zA-Z_]', '')
    If $bDir Then
    $vTmp = _FromPathToTree($sPath & $sFile & '\', $hRules, $iLevel - 1)
    $oTree.append($sKey) = ((IsObj($vTmp)) ? ($vTmp) : ($sPath & $sFile))
    Else
    $oTree.append($sKey) = $sPath & $sFile
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $sFile = FileFindNextFile($hFile)
    $bDir = @extended
    WEnd
    Else
    FileClose($hFile)
    Return
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    FileClose($hFile)
    Return $oTree
    EndFunc ;==>_FromPathToTree

    [/autoit] [autoit][/autoit] [autoit]

    Func _AttribRules($sPath)
    $sAttrib = FileGetAttrib($sPath)
    Return StringRegExp($sAttrib, '[D]')
    EndFunc ;==>_AttribRules

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit]

    Ich hoffe dass du jetzt klar kommst! Wie du eine Baumstruktur beispielsweise erstellen kannst ist nun hoffentlich klar. Ich denke mit Objekten zu arbeiten ist hier die beste Lösung da du halt einen Direktzugriff auf einzelne Knotenpunkte etc. hast. :)

  • Das klappt jetzt schon prima :)
    Du hast eine Zeile hinzugefügt, die gewisse Zeichen aus dem String schneidet:
    $sKey = StringRegExpReplace($sFile, '[^a-zA-Z_]', '')
    Wird das benötigt, weil die Objektnamen nur diese Zeichen können?
    Dann kann ich die Ordnerstruktur wohl doch nur anhand der Werte der Blätter aufbauen statt der Namen und ich muss alle Werte der Blätter durchgehen, wenn ich das richtige finden will. Wenn z.B. Punkte oder Leerzeichen bei Dateinamen fehlen, kann ich ja sonst nicht die richtige Datei finden :)
    Alternativ könnte ich noch bei dem gesuchten Ordner ein StringRegExpReplace machen und dadurch die Auswahl auf mehrere einzelne Objekte reduzieren.

  • Korrekt, wie du sicherlich weißt gibt es Beschränkungen bei Variablenbezeichnungen. Die gleichen Beschränkungen gelten auch für Attribute in einem Objekt. Ist so und kann man auch nichts dran machen. Aber eigentlich sollte eine Suche ja nicht über die Bezeichner erfolgen sondern über deren Inhalt. Wäre ja auch total unsinnig. Du kannst den Baum ja auch erweitern sodass direkt in der Wurzel sämtliche Pfade als extra Attribut hinterlegt werden (+ deren Schlüssel im Objekt). So kannst du dann trotzdem Dateien suchen und hast dennoch eine Baumstruktur durch die Objekte. Aber man sollte sich vorab natürlich immer fragen in wie fern das eigene Vorhaben Sinn macht und ob man nun unbedingt bestimmte Dinge benötigt. Wenn es dir halt nur um das Suchen von Dateien geht, würde ich einfach alle Pfade in ein String schreiben und komplett auf die Baumstruktur verzichten.

  • Was mir noch aufgefallen ist: Wenn ich einen Ordner "Test" und den anderen "Test$" genannt habe, dann gibt es nur den Ordner "Test", weil Objekte ja keine Sonderzeichen akzeptieren.
    Eigentlich wollte ich die Namen nun per Integer hochzählen, allerdings werden ja keine Zahlen als Objektnamen genommen. Kann ich irgendwie Buchstaben hochzählen?

  • Herjee... Lies dir nochmal den Post von mir durch und überleg dann mal wie du die vorhandene Funktion so umschreibst, dass du doch mit zahlen arbeiten kannst :S

    Gesendet von meinem HTC Desire HD A9191 mit Tapatalk 2

  • Yeah, du hast mich auf eine genial Idee gebracht!
    $oTree.1 geht nicht, aber $oTree._1 geht. => Ich habe nun "_" & $i als Fortlaufende Nummerierung :)

    Da ich die Objektsammlung mit For In Next durchgehen wollte und das nicht geklappt hat, habe ich einen Thread eröffnet: autoit.de/index.php/Thread/46033-For-In-Next-mit-Unterobjekten-von-Objekten/?postID=365155#post365161
    Eigentlich dachte ich, es wäre eine einfache Lösung und wollte somit diesen Thread hier nicht zumüllen

    //edit: Sorry, dass ich noch etwas nachfrage: Ich muss die einzelnen Ebenen ja rekursiv abklappern können. Meines Wissens geht das nur indem ich den Objektnamen dynamisch benenne. Es geht allerdings weder per &-Operator noch per Eval:

    [autoit]

    $oTreeChilds = Eval("$oTree." & $oTree.keys[$i])
    $oTreeChilds = $oTree. & $oTree.keys[$i]
    $oTreeChilds = $oTree. & Eval($oTree.keys[$i])

    [/autoit]


    Hast du oder jemand anderes noch einen Tipp für mich?