LessonsExtensions: Built inLesson 80

The Tree View

Show an array as a tree people can open and close with the Tree View widget: its arrayData, sorting, which branches are open, the row that is chosen and the message a click sends, and a folder's files as a tree.

  • Extensions
  • Lesson 80 of 83
  • About 12 minutes
  • 6 examples

A tree of the books

An array of arrays (Arrays) is a tree: each key leads either to a value, a leaf, or to another array, a branch. The Tree View widget shows one as a list whose branches open and close with a click on their triangle, as a file browser shows folders. Build a card with one:

Build it with the Tools palette and the Property Inspector
  1. Make a new stack, or go to an empty card. In Edit mode, drag a Tree View from the widgets of the Tools palette to the left of the card, make it tall, and name it Shelf.
  2. Drag a classic Field to the right of it and name it Details.

A Tree View shows its arrayData. Put this in the stack's script (Object > Stack Script), so that the tree is filled each time the card opens, and fillShelf can be called from anywhere in the stack:

ScriptThe script of this stack
on openCard
   fillShelf
end openCard

command fillShelf
   local tShelf
   put "Frank Herbert, 1965" into tShelf["Fiction"]["Dune"]
   put "Jane Austen, 1815" into tShelf["Fiction"]["Emma"]
   put "Carl Sagan, 1980" into tShelf["Science"]["Cosmos"]
   put "Richard Dawkins, 1976" into tShelf["Science"]["The Selfish Gene"]
   put "Walt Whitman, 1855" into tShelf["Poetry"]["Leaves of Grass"]
   set the arrayData of widget "Shelf" to tShelf
   set the sortType of widget "Shelf" to "text"
   set the readOnly of widget "Shelf" to true
end fillShelf

Keys are sorted as numbers unless sortType is text, so set it for words. A Tree View lets people add and delete elements unless it is readOnly, which suits an array a program owns. Try it from the Message Box, and open two branches with foldState, an array of the branches with a folded of false for each one open:

Message BoxType each line in the Message Box and press Return, with the script above in place
fillShelf
put the arrayData of widget "Shelf" into tShelf
put tShelf["Science"]["Cosmos"]
put false into tOpen["Fiction"]["folded"]
put false into tOpen["Science"]["folded"]
set the foldState of widget "Shelf" to tOpen
Message Box (what each put shows)
Carl Sagan, 1980
Your card as the OXT-Beyond engine draws it
Your card: the tree view at the left with Fiction open, showing Dune and Emma with their authors, Poetry closed, and Science open with Cosmos and The Selfish Gene; the empty field at the right.

The row that is chosen

A click on a row lights it and sends hiliteChanged. The lit row's hilitedElement is its path: the keys from the top of the array down to it, separated by commas, so Science,Cosmos is tShelf["Science"]["Cosmos"]. It ends with a comma, Science,Cosmos,, which item and the number of items pass over. Put this in the Tree View's script:

ScriptThe script of widget "Shelf"
on hiliteChanged
   local tPath, tShelf
   put the hilitedElement of me into tPath
   put the arrayData of me into tShelf
   if the number of items of tPath is 2 then
      put item 2 of tPath & return & tShelf[item 1 of tPath][item 2 of tPath] into field "Details"
   else
      put the number of elements of tShelf[item 1 of tPath] && "books" into field "Details"
   end if
end hiliteChanged

A path of one key is a branch, so the field says how many books it holds; a path of two is a book. Setting hilitedElement from a script lights a row too:

Message BoxType each line in the Message Box and press Return, with the scripts above in place
fillShelf
set the hilitedElement of widget "Shelf" to "Science,Cosmos"
wait 0 milliseconds with messages
put the hilitedElement of widget "Shelf"
put field "Details"
Message Box (what each put shows)
Science,Cosmos,
Cosmos
Carl Sagan, 1980
Your card as the OXT-Beyond engine draws it
Your card: the tree view with Science open and Cosmos lit, and the field at the right saying Cosmos and Carl Sagan, 1980.

A double-click on a leaf sends actionDoubleClick with the path, a good place to open the thing the row stands for. If your keys have commas in them, set the pathDelimiter to another character, such as /, and paths use that instead.

A folder as a tree

A folder is a tree too: folders inside folders, with files at the ends. A function that calls itself for each folder inside (Recursion) turns one into an array, each file with its size in bytes, ready for a Tree View:

ExampleRun it in the playground
function treeOf pFolder
   local tTree, tName
   repeat for each line tName in files(pFolder)
      put the number of bytes of URL ("binfile:" & pFolder & "/" & tName) into tTree[tName]
   end repeat
   repeat for each line tName in folders(pFolder)
      if tName is not ".." then put treeOf(pFolder & "/" & tName) into tTree[tName]
   end repeat
   return tTree
end treeOf

put specialFolderPath("temporary") & "/oxt-lesson-tree" into tRoot
create folder tRoot
create folder tRoot & "/docs"
put "Read me first." into URL ("binfile:" & tRoot & "/docs/readme.txt")
put "How to use it, step by step." into URL ("binfile:" & tRoot & "/docs/guide.txt")
put "Buy tea." into URL ("binfile:" & tRoot & "/notes.txt")

put treeOf(tRoot) into tTree
create widget "Files" as "com.livecode.widget.treeview"
set the rect of it to 20, 20, 300, 340
set the sortType of it to "text"
set the readOnly of it to true
set the arrayData of it to tTree
put false into tOpen["docs"]["folded"]
set the foldState of it to tOpen
put tTree["docs"]["guide.txt"]
put tTree["notes.txt"]

delete file tRoot & "/docs/readme.txt"
delete file tRoot & "/docs/guide.txt"
delete file tRoot & "/notes.txt"
delete folder tRoot & "/docs"
delete folder tRoot
Output
28
8
Stage what the code made, as the OXT-Beyond engine draws it
A tree view filling the left of the card: a folder named docs, open, holding guide.txt and readme.txt with their sizes, and below it notes.txt with its size.

The files are deleted at the end, and the tree still shows them: it shows its own copy of the array, not the folder. Set its arrayData again to bring it up to date.

Try it yourself

Write a function leafCount that takes an array and returns how many leaves it has, however deep its branches go, so a program could say how many books are on the shelf or files are in a folder.

Show a solution
ExampleRun it in the playground
function leafCount pTree
   local tCount, tKey
   put 0 into tCount
   repeat for each key tKey in pTree
      if pTree[tKey] is an array then
         add leafCount(pTree[tKey]) to tCount
      else
         add 1 to tCount
      end if
   end repeat
   return tCount
end leafCount

put "Frank Herbert" into tShelf["Fiction"]["Dune"]
put "Jane Austen" into tShelf["Fiction"]["Emma"]
put "Carl Sagan" into tShelf["Science"]["Cosmos"]
put "Ada" into tShelf["Notes"]
put leafCount(tShelf)
Output
4

Words in this lesson

Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.