TreeView-(Un)Checked-Example

    • Offizieller Beitrag

    Bei einem TreeView mit Checkboxen möchte man ja manchmal, dass die Haken auch für die Child-Items mitgesetzt werden.
    Ich habe mal drei rekursive Funktionen geschrieben, die eine solche Funktionalität erreichen:

    - Alle Child-Items des angehakten Items werden ebenfalls angehakt
    - Alle Haken bei übergeordneten Parent-Items werden entfernt, wenn der Haken bei einem Item entfernt wird
    - Überprüfung ob alle Sibling-Items ebenfalls angehakt sind und, wenn zutreffend, das übergeordnete Parent-Item anhaken

    Schaut euch einfach das Beispiel an:

    Spoiler anzeigen
    [autoit]


    #include<GUIConstantsEx.au3>
    #include<GuiTreeView.au3>
    #include<TreeViewConstants.au3>
    #include<WindowsConstants.au3>

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

    Global $hGui = GUICreate('TreeView-(Un)Checked-Example', 400, 600)
    Global $hTreeView = GUICtrlCreateTreeView(5, 5, 390, 590, BitOR($GUI_SS_DEFAULT_TREEVIEW, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE)
    Global $hRoot = GUICtrlCreateTreeViewItem('Root', $hTreeView)
    _GUICtrlTreeView_SetBold($hTreeView, $hRoot)
    _GUICtrlTreeView_BeginUpdate($hTreeView)
    For $x = 1 To 3
    $hItem1 = _GUICtrlTreeView_AddChild($hTreeView, GUICtrlGetHandle($hRoot), StringFormat('[%02d] Child 1st Gen.', $x))
    For $y = 1 To 3
    $hItem2 = _GUICtrlTreeView_AddChild($hTreeView, $hItem1, StringFormat('[%02d] Child 2nd Gen.', $y))
    For $z = 1 To 2
    $hItem3 = _GUICtrlTreeView_AddChild($hTreeView, $hItem2, StringFormat('[%02d] Child 3rd Gen.', $z))
    Next
    Next
    Next
    _GUICtrlTreeView_EndUpdate($hTreeView)
    _GUICtrlTreeView_Expand($hTreeView)
    GUISetState()

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

    While True
    Switch GUIGetMsg()
    Case $GUI_EVENT_PRIMARYDOWN ; (*)
    $aInfo = GUIGetCursorInfo($hGui) ; (*)
    If $aInfo[4] = $hTreeView Then ; (*)
    $aAdjust = ControlGetPos($hGui, '', $hTreeView) ; (*)
    If BitAND(_GUICtrlTreeView_HitTest($hTreeView, $aInfo[0]-$aAdjust[0]-2, $aInfo[1]-$aAdjust[1]-2), 64) Then ; (*)
    $hSelect = _GUICtrlTreeView_GetSelection($hTreeView)
    $checked = _GUICtrlTreeView_GetChecked($hTreeView, $hSelect)
    $hItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hSelect)
    If $hItem Then _SetChildItemsChecked($hTreeView, $hItem, $checked)
    If $checked Then
    _VerifySiblingItems($hTreeView, $hSelect)
    Else
    _SetParentItemsUnchecked($hTreeView, $hSelect)
    EndIf
    EndIf
    EndIf
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd
    ; (*) = diese Konstruktion ist notwendig, weil man sonst nicht zwischen einem Mausklick
    ; auf den Item-Text und der Checkbox unterscheiden kann

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

    ; Überprüft (rekursiv) ob alle Sibling-Items angehakt sind und setzt, wenn zutreffend, den Haken beim Parent-Item
    Func _VerifySiblingItems($hTreeView, $hItem)
    Local $hTmp, $hSave = $hItem, $iCount = _GUICtrlTreeView_GetSiblingCount($hTreeView, $hItem)
    While True
    $hTmp = _GUICtrlTreeView_GetNextSibling($hTreeView, $hItem)
    If Not $hTmp Then ExitLoop
    $hItem = $hTmp
    WEnd
    Do
    If _GUICtrlTreeView_GetChecked($hTreeView, $hItem) Then $iCount -= 1
    $hItem = _GUICtrlTreeView_GetPrevSibling($hTreeView, $hItem)
    Until Not $hItem
    If Not $iCount Then
    Local $hParent = _GUICtrlTreeView_GetParentHandle($hTreeView, $hSave)
    If $hParent Then
    _GUICtrlTreeView_SetChecked($hTreeView, $hParent)
    _VerifySiblingItems($hTreeView, $hParent)
    EndIf
    EndIf
    EndFunc

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

    ; Setzt (rekursiv) den Haken bei allen Child-Items, wenn der Haken bei einem Item gesetzt wurde
    Func _SetChildItemsChecked($hTreeView, $hItem, $checked)
    Do
    Local $hNewItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hItem)
    If $hNewItem Then _SetChildItemsChecked($hTreeView, $hNewItem, $checked)
    _GUICtrlTreeView_SetChecked($hTreeView, $hItem, $checked)
    $hItem = _GUICtrlTreeView_GetNextChild($hTreeView, $hItem)
    Until Not $hItem
    EndFunc

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

    ; Entfernt (rekursiv) den Haken bei allen Parents, wenn der Haken von einem Item entfernt wurde
    Func _SetParentItemsUnchecked($hTreeView, $hItem)
    Local $hParent = _GUICtrlTreeView_GetParentHandle($hTreeView, $hItem)
    If $hParent Then _SetParentItemsUnchecked($hTreeView, $hParent)
    _GUICtrlTreeView_SetChecked($hTreeView, $hItem, False)
    EndFunc

    [/autoit]
    • Offizieller Beitrag

    Danke, für das Lob! :)
    Die rekursiven Funktionen sind vor allem dann sinnvoll, wenn die Anzahl der Items und/oder die "Tiefe" des TreeViews vorher nicht bekannt sind.
    Außerdem war es eine gute Übungsaufgabe für rekursive Funktionen.

    Allerdings bin ich mit der Mausklick-Abfrage noch nicht so recht zufrieden. Muss mal schauen, ob es da noch eine andere Möglichkeit gibt...

  • Hallo Oscar,

    habe dein TreeView-Beispiel gefunden, funktioniert super :thumbup: , für meinen Zweck benötige ich etwas ähnliches, nur müssten da 3 Möglichkeiten vorhanden sein


    • nicht angekreuzt (ist nicht in dieser Gruppe und in keiner Untergruppe)
    • leicht angekreuzt mit hellerer Farbe (ist in irgendeiner Untergruppe)
    • voll angekreuzt (ist in allen Untergruppen)


    Hast du eine Idee, wie ich ansetzen muss um das zu realisieren. Mit CHECKED kann es ja nicht klappen, gibt es eine andere Möglichkeit um das visuell darzustellen.

    Spoiler anzeigen
    [autoit]

    #Region ### START Koda GUI section ### Form=
    $Form1 = GUICreate("Form1", 633, 447, 193, 125)
    $TreeView1 = GUICtrlCreateTreeView(94, 29, 175, 251)
    $TreeView1_0 = GUICtrlCreateTreeViewItem("Verein", $TreeView1)
    $TreeView1_1 = GUICtrlCreateTreeViewItem("Vorstandsmitglieder", $TreeView1_0)
    $TreeView1_2 = GUICtrlCreateTreeViewItem("Fussballabteilung", $TreeView1_0)
    $TreeView1_3 = GUICtrlCreateTreeViewItem("Aktive Spieler", $TreeView1_2)
    $TreeView1_4 = GUICtrlCreateTreeViewItem("1. Mannschaft", $TreeView1_3)
    $TreeView1_5 = GUICtrlCreateTreeViewItem("2. Mannschaft", $TreeView1_3)
    $TreeView1_6 = GUICtrlCreateTreeViewItem("Handballabteilung", $TreeView1_0)
    $TreeView1_7 = GUICtrlCreateTreeViewItem("", $TreeView1_0)
    GUISetState(@SW_SHOW)
    #EndRegion ### END Koda GUI section ###
    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

    [/autoit]

    EDIT

    Das obige Script ist nur dazu da, damit man erkennt warum ich gerne 3 Möglichkeiten hätte, würde mich freuen wenn du hierzu eine Idee hättest.

    mfg AutoBert

    Einmal editiert, zuletzt von AutoBert (15. Februar 2009 um 23:25)

    • Offizieller Beitrag

    Bei "normalen" Checkboxen gibt es den "3STATE"-Modus. Dieser ist aber für ein Treeview von AutoIt nicht vorgesehen.
    Vielleicht kennt einer der Anwesenden einen Trick diesen Modus auch für ein Treeview benutzen zu können?


    Edit: Man könnte den Bold-Style für einen 3State-Modus benutzen:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstantsEx.au3>
    #include <GuiTreeView.au3>
    #include <TreeViewConstants.au3>
    #include <WindowsConstants.au3>

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

    Global $hGui = GUICreate('TreeView-(Un)Checked-Example', 400, 600)
    Global $hTreeView = GUICtrlCreateTreeView(5, 5, 390, 590, BitOR($GUI_SS_DEFAULT_TREEVIEW, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE)
    Global $hRoot = GUICtrlCreateTreeViewItem('Root', $hTreeView)
    _GUICtrlTreeView_BeginUpdate($hTreeView)
    For $x = 1 To 3
    $hItem1 = _GUICtrlTreeView_AddChild($hTreeView, GUICtrlGetHandle($hRoot), StringFormat('[%02d] Child 1st Gen.', $x))
    For $y = 1 To 3
    $hItem2 = _GUICtrlTreeView_AddChild($hTreeView, $hItem1, StringFormat('[%02d] Child 2nd Gen.', $y))
    For $z = 1 To 2
    $hItem3 = _GUICtrlTreeView_AddChild($hTreeView, $hItem2, StringFormat('[%02d] Child 3rd Gen.', $z))
    Next
    Next
    Next
    _GUICtrlTreeView_EndUpdate($hTreeView)
    _GUICtrlTreeView_Expand($hTreeView)

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

    GUISetState()
    While True
    Switch GUIGetMsg()
    Case $GUI_EVENT_PRIMARYDOWN ; (*)
    $aInfo = GUIGetCursorInfo($hGui) ; (*)
    If $aInfo[4] = $hTreeView Then ; (*)
    $aAdjust = ControlGetPos($hGui, '', $hTreeView) ; (*)
    If BitAND(_GUICtrlTreeView_HitTest($hTreeView, $aInfo[0]-$aAdjust[0]-2, $aInfo[1]-$aAdjust[1]-2), 64) Then ; (*)
    $hSelect = _GUICtrlTreeView_GetSelection($hTreeView)
    $checked = _GUICtrlTreeView_GetChecked($hTreeView, $hSelect)
    If $checked Then
    _VerifySiblingItems($hTreeView, $hSelect)
    Else
    _SetParentItemsUnchecked($hTreeView, $hSelect)
    EndIf
    $hItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hSelect)
    If $hItem Then
    _SetChildItemsChecked($hTreeView, $hItem, $checked)
    _GUICtrlTreeView_SetBold($hTreeView, $hSelect, False)
    EndIf
    EndIf
    EndIf
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd
    ; (*) = diese Konstruktion ist notwendig, weil man sonst nicht zwischen einem Mausklick
    ; auf den Item-Text und der Checkbox unterscheiden kann

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

    ; Überprüft (rekursiv) ob alle Sibling-Items angehakt sind und setzt, wenn zutreffend, den Haken beim Parent-Item
    Func _VerifySiblingItems($hTreeView, $hItem)
    Local $hTmp, $hSave = $hItem, $iCount = _GUICtrlTreeView_GetSiblingCount($hTreeView, $hItem)
    While True
    $hTmp = _GUICtrlTreeView_GetNextSibling($hTreeView, $hItem)
    If Not $hTmp Then ExitLoop
    $hItem = $hTmp
    WEnd
    Do
    If _GUICtrlTreeView_GetChecked($hTreeView, $hItem) Then $iCount -= 1
    $hItem = _GUICtrlTreeView_GetPrevSibling($hTreeView, $hItem)
    Until Not $hItem
    If Not $iCount Then
    Local $hParent = _GUICtrlTreeView_GetParentHandle($hTreeView, $hSave)
    If $hParent Then
    _GUICtrlTreeView_SetChecked($hTreeView, $hParent)
    _GUICtrlTreeView_SetBold($hTreeView, $hParent, False)
    _VerifySiblingItems($hTreeView, $hParent)
    EndIf
    Else
    Local $hParent = _GUICtrlTreeView_GetParentHandle($hTreeView, $hSave)
    If $hParent Then
    _GUICtrlTreeView_SetBold($hTreeView, $hParent, True)
    _VerifySiblingItems($hTreeView, $hParent)
    EndIf
    EndIf
    EndFunc

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

    ; Setzt (rekursiv) den Haken bei allen Child-Items, wenn der Haken bei einem Item gesetzt wurde
    Func _SetChildItemsChecked($hTreeView, $hItem, $checked)
    _GUICtrlTreeView_SetBold($hTreeView, $hItem, False)
    Do
    Local $hNewItem = _GUICtrlTreeView_GetFirstChild($hTreeView, $hItem)
    If $hNewItem Then _SetChildItemsChecked($hTreeView, $hNewItem, $checked)
    _GUICtrlTreeView_SetChecked($hTreeView, $hItem, $checked)
    _GUICtrlTreeView_SetBold($hTreeView, $hItem, False)
    $hItem = _GUICtrlTreeView_GetNextChild($hTreeView, $hItem)
    Until Not $hItem
    EndFunc

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

    ; Entfernt (rekursiv) den Haken bei allen Parents, wenn der Haken von einem Item entfernt wurde
    Func _SetParentItemsUnchecked($hTreeView, $hItem)
    Local $hTmp, $hSave = $hItem, $iCount = 0
    While True
    $hTmp = _GUICtrlTreeView_GetNextSibling($hTreeView, $hItem)
    If Not $hTmp Then ExitLoop
    $hItem = $hTmp
    WEnd
    Do
    If _GUICtrlTreeView_GetChecked($hTreeView, $hItem) Or _GUICtrlTreeView_GetBold($hTreeView, $hItem) Then $iCount += 1
    $hItem = _GUICtrlTreeView_GetPrevSibling($hTreeView, $hItem)
    Until Not $hItem
    $hItem = $hSave
    Local $hParent = _GUICtrlTreeView_GetParentHandle($hTreeView, $hItem)
    If $iCount Then
    _GUICtrlTreeView_SetBold($hTreeView, $hParent, True)
    Else
    _GUICtrlTreeView_SetBold($hTreeView, $hParent, False)
    EndIf
    If $hParent Then _SetParentItemsUnchecked($hTreeView, $hParent)
    _GUICtrlTreeView_SetChecked($hTreeView, $hItem, False)
    EndFunc

    [/autoit]

    Wenn nicht alle Siblings angehakt sind, dann wird der Parent in Fettschrift dargestellt. Falls Dir das ausreicht!?

  • Hallo Oscar,

    erstmal danke für deinen Lösung, würde mir reichen, ob dem DAU auch?

    Nach dem ich auch dein Directory-Treeview-Beispiel gefunden habe,ist mir eine eine anderer Ansatz eingefallen. Man nehme _GUICtrlTreeView_SetIcon, wenn man den auch noch auslesen kann (ImageIndex?) kann ich dies auch abspeichern und beim nächsten Aufruf wieder abbilden.

    PS. Die Hilfe in diesem Forum ist ja schneller, als ich das von früheren Zeiten von kommerzieller Software gewohnt bin

    mit freundlichem Gruß aus demTaubertal

    AutoBert

    • Offizieller Beitrag

    Sollte mit _GUICtrlTreeView_GetImageIndex gehen, wenn Du eine ImageList für die Icons benutzt.

    Was mir beim erstellen des Scripts "_GUICtrlTreeView_CreateDirectory.au3" aufgefallen war:
    - Wenn man Icons benutzt, dann bekommt jeder Eintrag ein Icon
    - Wenn man beim erstellen eines Eintrags kein Icon angibt, dann wird das vom Parent "vererbt"
    - und das erstellen des Treeviews wird langsamer (je nach Größe kann sich das durchaus bemerkbar machen)

    P.S.: Ja, wir sind recht schnell, hier im Forum. ;)

  • Hallo Oscar ,

    versuche gerade dein Beispiel auf 3-DState zu erweitern, beim Durchtesten deines Skriptes ist mir aufgefallen, daß man es an 2 Stellen optimieren könnte:

    Spoiler anzeigen
    [autoit]


    ; Überprüft (rekursiv) ob alle Sibling-Items angehakt sind und setzt,
    ;wenn zutreffend, den Haken beim Parent-Item
    ;wenn nicht wird abgebrochen und mit _SetParentItemsUnchecked (rekursiv) alle Parent-Haken entfernt
    Func _VerifySiblingItems($hTreeView, $hItem)
    Local $hTmp, $hSave = $hItem, $iCount = _GUICtrlTreeView_GetSiblingCount($hTreeView, $hItem)
    Do
    If _GUICtrlTreeView_GetChecked($hTreeView, $hItem) Then
    $hItem = _GUICtrlTreeView_GetNextSibling($hTreeView, $hItem)
    $iCount -= 1
    Else
    $iCount = $iCount *-1
    EndIf
    Until Not ($hItem and $iCount>0)
    if $iCount >0 Then
    $hItem = $hSave
    Do
    If _GUICtrlTreeView_GetChecked($hTreeView, $hItem) Then
    $iCount -= 1
    $hItem = _GUICtrlTreeView_GetPrevSibling($hTreeView, $hItem)
    Else
    $iCount = $iCount *-1
    EndIf
    Until Not ($hItem and $iCount>0)
    EndIf
    ;1. Änderung bishierher kein merklicher Vorteil
    If Not $iCount Then
    Local $hParent = _GUICtrlTreeView_GetParentHandle($hTreeView, $hSave)
    If $hParent Then
    _GUICtrlTreeView_SetChecked($hTreeView, $hParent)
    $checked = _GUICtrlTreeView_GetChecked($hTreeView, $hParent)
    If $checked Then ;2. Änderung dies bringt in großen Bäumen mit vielen unchecked(en) Zweigen ca. Faktor 20
    _VerifySiblingItems($hTreeView, $hParent)
    Else
    _SetParentItemsUnchecked($hTreeView, _GUICtrlTreeView_GetLastChild($hTreeView,_GUICtrlTreeView_GetParentHandle($hTreeView,$hParent)))
    EndIf
    EndIf
    EndIf
    EndFunc

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

    Jetzt hoffe ich nur noch, daß es bei mir mit dem Umsetzen auch klappt

    mfg (Auto)Bert

  • Hallo Zusammen zu dem Thema habe ich auch eine Frage und zwar möchte ich wenn ich mein Treeview Element auswähle das alle unter dieser Rubrik stehenden Elemente auch ausgewählt werden. Gibt es bei dem Treeview auch so einen efehlt wie Guictrlsetstate ? Und wenn eine Frage wie stelle ich das an ?

    Spoiler anzeigen
    [autoit]


    $Form1 = GUICreate("Allgemein", 615, 438, 192, 124);erstellt die GUI
    $Okay = GUICtrlCreateButton("Okay", 328, 360, 129, 41);erstellt einen okay button
    $Abbrechen = GUICtrlCreateButton("Abbrechen", 456, 360, 129, 41)
    $Label1 = GUICtrlCreateLabel("Was wollen Sie Installieren?", 216, 24, 136, 17);Überschrift
    $TreeView1 = GUICtrlCreateTreeView(88, 96, 305, 193, BitOR($TVS_CHECKBOXES, $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_SHOWSELALWAYS))
    $TreeView1_0 = GUICtrlCreateTreeViewItem("Allgemein", $TreeView1)
    $TreeView1_3 = GUICtrlCreateTreeViewItem("7 Zip", $TreeView1_0)
    $GUI1 = GUISetState(@SW_SHOW)

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE;stellt den X button da
    Exit

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

    Case $Okay ; für denn fall, dass Okay geklickt wird
    If BitAnd(GUICtrlRead($TreeView1_3),$GUI_CHECKED) = $GUI_CHECKED Then
    $filepath = 'C:\Install\'
    $filename = '7z920.exe /S'
    $Pid = Run("cmd.exe", $filepath)
    WinWaitActive("Administrator: Eingabeaufforderung", "", 10)
    Send($filename)
    Send("{ENTER}")
    Sleep(500)
    Send('exit')
    Send("{ENTER}")
    EndIf

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

    Case $Abbrechen;für den fall ,dass abbrechen gedrückt wird,wird das programm beendet
    Exit

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

    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit]
  • Hallo skull693,

    herzlich willkommen im Forum und viel Spass mit AutoIt.

    Hier kannst du dir die deutsche Hilfe herunterladen.
    Hier gibt es ein AutoIt-Tutorial: http://wiki.autoit.de/wiki/index.php/Tutorial Sehr hilfreich ist auch das Buch von peethebee .

    und jetzt zu deiner Frage: genau das macht dieses Beispiel ja. Da es keine direkten Funktionen (Befehle) dafür gibt hat Oscar diese für dieses Beispiel entwickelt. Zum besseren Verständnis arbeitest du das Skript durch und schaust dir zu jedem dir bisher nicht bekannten Befehl die Hilfe und die Beispiele dazu an,

    mfg autoBert