Version 3 of Populate a ttk::treeview given a nested dict

Updated 2011-07-15 14:24:20 by daedra

Takes a nested dict, made here using makeNestedDict, and populates a ttk::treeview

The nested dict is of the form {node1 {node1Child1 {child1Leaf 1 {} child1Leaf2 {}}} node2 {node2Child1 ...}}, where

  • Nodes with children are keys pointing to values which are themselves keys pointing to more values, and
  • Leaves are nodes whose children are empty {}
# chops the path and extension from the absolute path of a file
proc chopPathAndExt path {
  return [file rootname [file tail $path]]
}

# returns bool: is the element a leaf?
proc isLeaf element {
  return [expr {$element == {}}]
}

# fills given ttk::treeview $tree with contents of nested dict $dic
proc populateTreeView {tree parent dic} {
  foreach {k v} $dic {
    set k [chopPathAndExt $k]
    if { [isLeaf $v] } {
      # $parent$k ensures unique id
      $tree insert $parent end -id $parent$k -text $k
    } else {
      # $k$v ensures unique id
      $tree insert $parent end -id $k$v -text $k
      populateTreeView $tree $k$v $v
    }
  }
}

proc makeTreeView { } {
  ttk::treeview .tree
  .tree configure -columns "items"
  .tree configure -height 20
  .tree column "items" -width 200 -anchor center
  set nestedDict [makeNestedDict]
  populateTreeView .tree {} $nestedDict
  pack .tree
}

makeTreeView

An example of a function which makes a nested dict follows.

# builds a flat list of files/directories one level under $path
proc ls {path} {
  return [glob -nocomplain -directory $path *]
}

# recursively builds a nested dict of all files/directories under $path
proc ls-R {path} {
  set result {}
  foreach item [ls $path] {
    if {[file isdirectory [file join $path $item]]} {
      dict set result $item [ls-R [file join $path $item]]
    } else {
      dict set result $item {}
    }
  }
  return $result
}

# makes the filesystem tree
proc makeNestedDict {path} {
  return [ls-R $path]
}

makeNestedDict {/var}