Save/Load TreeView Part 2 - 2020/10/22

Post your working scripts, libraries and tools
User avatar
TheArkive
Posts: 390
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Save/Load TreeView Part 2 - 2020/10/22

22 Oct 2020, 16:39

AHK v2 version is here.

Main highlights:
  • Save TreeView nodes, structure, and properties to array.
  • Load TreeView nodes, structure, and properties from array.
  • TreeView items can contain any valid text (no semicolon used as separator in this method).
  • Preserves Expand, Bold, Check properties of each node.
  • Preserves selected item.
  • Preserves icon index (NOTE: you must pre-load your own image list still)
  • Optionally, use a serializer (ie. JSON, XML) to save array to disk, and load form disk.
  • As an array, you can attach this data to a larger settings array, and save.
  • The code is MUCH smaller than my previous script here.
Important Notes:
  • The output array is linear.
  • The data in this array allows for perfectly replicating the TreeView
  • The output isn't meant to be "human readable" (so no adding comments)

So, here is part 2 to take things a few steps further. Please note it is recommended to use an object serializer (such as this JSON library) if you need to save/load the TreeView array data to/from a file.

Thanks to @just me for his post which inspired me to find a way to cut to the chase better than my last attempt.

Code: Select all

; AHK v1
; ==========================================================
;
; Inspired by user "just me"s post here: https://www.autohotkey.com/boards/viewtopic.php?p=121483#p121483
;
; JSON serializer: https://www.autohotkey.com/boards/viewtopic.php?f=83&t=74799&p=323348#p323348
;
; Example for usage with JSON serializer:
;
; To load tree data from disk:
;       
;       Gui, TreeView, MyTreeName               ; ensure TreeView is active
;       FileRead, myVar, json-tree-data.txt     ; load JSON text to var
;       myObj := jxon_load(myVar)               ; convert var to array/object
;       LoadTree(myObj)                         ; now your tree is recreated
;
; To save tree data to disk:
;
;       Gui, TreeView, MyTreeName               ; ensure TreeView is active
;       myArray := SaveTree()                   ; dump tree to array
;       myVar := jxon_dump(myArray)             ; convert array to JSON text
;       FileAppend, %myVar%, json-tree-data.txt ; save data to file
;
;
; Using arrays in this way, you can save TreeView data to another settings array, or
; keep the TreeView data separate, according to your needs.
;
; Note, when saving icon index, it is actually 0 based.  So items that don't have an
; icon will still return index 0 (which translates to index 1 for AHK).
;
; ==========================================================
; EXAMPLE
; ==========================================================

; Global testArray, treeHwnd, imgListID

; Gui, MyGui:New
; Gui, MyGui:Add, Button, x+0 yp gTreeToArray, To Array
; Gui, MyGui:Add, Button, x+0 yp gClear, Clear
; Gui, MyGui:Add, Button, x+0 yp gArrayToTree, To Tree
; Gui, MyGui:Add, Button, x+10 yp gRePop, Repopulate

; Gui, MyGui:Add, Checkbox, x+10 yp+4 vMyCheck, Include Icons
; GuiControl,, MyCheck, 1

; Gui, MyGui:Add, TreeView, xs y+16 w600 r17 Checked HwndtreeHwnd vMyTreeName ; define vControlName and Hwnd
; Gui, MyGui:Show


; populate(false)

; populate(icon:=false) {
    ; If !icon {
        ; IL_Destroy(imgListID)
        ; GuiControl, -ImageList, MyTreeName
        ; GuiControl, -Icon, MyTreeName
    ; } Else {
        
        ; makeImgList()
    ; }
    
    ; icon := icon ? " Icon1" : ""
    ; i1 := TV_Add("Item 01",,"Expand" icon) ; icon index is 0 based on retrieval
        ; icon := icon ? " Icon2" : ""
        ; i4 := TV_Add("Item 04",i1,"Expand" icon)
            ; icon := icon ? " Icon3" : ""
            ; i13 := TV_Add("Item 13",i4,"" icon)
            ; icon := icon ? " Icon4" : ""
            ; i16 := TV_Add("Item 15",i4,"" icon)
    ; icon := icon ? " Icon1" : ""
    ; TV_Add("Item 05",i1,"" icon)
    ; icon := icon ? " Icon2" : ""
    ; TV_Add("Item 06",i1,""  icon)
    ; icon := icon ? " Icon3" : ""

    ; i2 := TV_Add("Item 02",,"Bold Expand" icon)
    ; icon := icon ? " Icon4" : ""
        ; i7 := TV_Add("Item 07",i2,"Bold Check Expand" icon)
        ; icon := icon ? " Icon1" : ""
            ; TV_Add("Item 14",i7,"Check" icon)
            ; icon := icon ? " Icon2" : ""
    ; TV_Add("Item 08",i2,"Bold" icon)
    ; icon := icon ? " Icon3" : ""
    ; TV_Add("Item 09",i2,"Bold" icon)
    ; icon := icon ? " Icon4" : ""

    ; i3 := TV_Add("Item 03",,"Check Expand" icon)
    ; icon := icon ? " Icon1" : ""
        ; i10 := TV_Add("Item 10",i3,"Check Expand" icon)
        ; icon := icon ? " Icon2" : ""
            ; TV_Add("Item 16",i10, icon)
            ; icon := icon ? " Icon1" : ""
    ; TV_Add("Item 11",i3,"Check" icon)
    ; icon := icon ? " Icon3" : ""
    ; TV_Add("Item 12",i3,"Check" icon)
    ; icon := icon ? " Icon4" : ""
; }

; makeImgList() {
    ; imgListID := IL_Create(4)
    ; IL_Add(imgListID,"shell32.dll",128)
    ; IL_Add(imgListID,"shell32.dll",132)
    ; IL_Add(imgListID,"shell32.dll",133)
    ; IL_Add(imgListID,"shell32.dll",131)
    ; TV_SetImageList(imgListID)
; }

; RePop() {
    ; TV_Delete()
    ; GuiControlGet, MyCheck
    ; populate(MyCheck)
; }

; TreeToArray() {
    ; testArray := SaveTree(true) ; true = save icons
    ; msgbox Tree data saved to array.
; }

; ArrayToTree() {
    ; LoadTree(testArray)
; }

; Clear() {
    ; TV_Delete()
; }

; GuiClose() { ; GUI close event
    ; ExitApp ; do this otherwise the script keeps running after the GUI closes
; }

; ==========================================================================
; Library functions
; ==========================================================================

SaveTree(icons:=false) {
    baseObj := Array(), ID := TV_GetNext()
    
    While ID {
        e := TV_Get(ID,"E"), c := TV_Get(ID,"C"), b := TV_Get(ID,"B")
        s := (TV_GetSelection()=ID) ? 1 : 0
        TV_GetText(t,ID)
        
        icon := TreeGetIconIndex(treeHwnd,ID)
        
        If icons
            baseObj.Push(Object("text",t, "expanded",e, "checked",c, "bold",b, "id",ID, "selected",s, "icon",icon+1, "parent",TV_GetParent(ID)))
        Else
            baseObj.Push(Object("text",t, "expanded",e, "checked",c, "bold",b, "id",ID, "selected",s, "parent",TV_GetParent(ID)))
        
        ID := TV_GetNext(ID,"Full")
    }
    
    return baseObj
}

LoadTree(a) { ; a = input array
    id_trans := Object() ; for translating parent IDs
    sel_id := 0
    
    For i, item in a {
        CurID := item["id"], pID := item["parent"]
        icon := (item.HasKey("icon") ? item["icon"] : 0)
        
        attr := (item["expanded"] ? "Expand" : "")
        attr .= (item["checked"] ? " Check" : "")
        attr .= (item["bold"] ? " Bold" : "")
        attr .= (item.HasKey("icon") ? " Icon" icon : "")
        
        new_id := !pID ? TV_Add(item["text"],,attr) : new_id := TV_Add(item["text"],id_trans[pID],attr)
        sel_id := (item["selected"] ? new_id : sel_id)
        
        id_trans[CurID] := new_id ; record new parent ID, linked to old ID
    }
    id_trans := "", a := "" ; free arrays
    
    If sel_id
        TV_Modify(sel_id,"Select")
}

TreeGetIconIndex(hCtl,hItem=0) {    ; support function
	If (!hItem) {                   ; thanks to user "just me" for his LV_EX_ lib for ideas to make this code
		SendMessage, 0x110A, 0x9, 0,, ahk_id %hCtl% ; 0x110A TVM_GETNEXTITEM ; 0x9 current selection
        hItem := (ErrorLevel And ErrorLevel <> "FAIL") ? ErrorLevel : ""
        If hItem = ""
            return ""
	}
	
	vPIs64 := (A_PtrSize=8) ; determine system arch
	vPtrType := vPIs64?"Int64":"Int" ; set data type
	vSize1 := vPIs64?56:40 ; set pointer size
	
	VarSetCapacity(TVITEM, vSize1, 0) ; make variable/structure
	NumPut(0x2, &TVITEM, 0, "UInt") ;mask ;TVIF_IMAGE := 0x2 ; define that we want the img index
	
	vMsg := StrLen(Chr(0xFFFF))?0x113E:0x110C ;TVM_GETITEMW := 0x113E ;TVM_GETITEMA := 0x110C ; define msg according to unicode availability
	
	NumPut(0, &TVITEM, vPIs64?36:24, "Int") ;iImage
	NumPut(hItem, &TVITEM, vPIs64?8:4, vPtrType) ;hItem ; put item handle into structure
	
    SendMessage, %vMsg%, 0, &TVITEM,, ahk_id %hCtL% ;TVM_GETITEMW := 0x113E ;TVM_GETITEMA := 0x110C ; get TV item info struct
	vImageIndex := NumGet(&TVITEM, vPIs64?36:24, "Int") ;iImage ; extract img index from structure
	
	return vImageIndex
}
Last edited by TheArkive on 23 Oct 2020, 07:39, edited 2 times in total.
User avatar
elModo7
Posts: 189
Joined: 01 Sep 2017, 02:38
GitHub: elModo7
Location: Spain
Contact:

Re: Save/Load TreeView Part 2 - 2020/10/22

22 Oct 2020, 17:19

Dang I have used the previous version for extended TV and it has worked wonderfully, thank you for updating this!
:beer:
User avatar
TheArkive
Posts: 390
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Save/Load TreeView Part 2 - 2020/10/22

23 Oct 2020, 05:51

@elModo7

Glad ya like it :D ... I've started going through some of the libs i've created (some of them are silly - some more useful) ... and it was high time to find a way to remove the limitations of the last version of this script.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: bautai, CappuccinoCake, lmstearn and 21 guests