The attached program is the core of a treeview, used for filemanager as an example.
It uses scrollview to attach the tree nodes.
The nodes are defined as a type, each includes a panel, on it a button and a label. It is easy to add more views as each view is accessible, so the control of colors, text etc. is available for each node separately.
I added a Tag to the node properties so additional data (on top of the text) can be stored, to help with the functionality of the tree.
The code is commented, I'll be glad to add clarifications if it is not clear enough.
Thanks to Erel and all the other contributors, it seems that B4A is unlimited !
Edit: found a bug in sub remove_children, corrected.
edit: arranged the code better.
It uses scrollview to attach the tree nodes.
The nodes are defined as a type, each includes a panel, on it a button and a label. It is easy to add more views as each view is accessible, so the control of colors, text etc. is available for each node separately.
I added a Tag to the node properties so additional data (on top of the text) can be stored, to help with the functionality of the tree.
The code is commented, I'll be glad to add clarifications if it is not clear enough.
Thanks to Erel and all the other contributors, it seems that B4A is unlimited !
B4X:
'Activity module
Sub Process_Globals
End Sub
Sub Globals
Type node(pnl As Panel,lbl As Label,btn As Button, tag As String,level As Int, parent As node, child As List)
Type treeview(sv As ScrollView, rootnode As node)
Dim tv As treeview
Dim nd(0) As node
Dim sv As ScrollView
Dim lineheight,linewidth, delta As Int
Dim plus,minus As Bitmap
Dim datalist As List
End Sub
Sub Activity_Create(FirstTime As Boolean)
activity.LoadLayout("treeview.bal")
lineheight = 36dip
linewidth = 250dip
plus.Initialize(File.DirAssets,"plus.png")
minus.Initialize(File.DirAssets,"minus.png")
tv.Initialize
tv.sv.Initialize(activity.Height)
activity.AddView(tv.sv,0,0,activity.Width,activity.Height)
tv.sv.Panel.Height = 5000
tv.rootnode.Initialize
tv.rootnode.pnl.Initialize("")
tv.rootnode.btn.Initialize("")
tv.rootnode.lbl.Initialize("")
tv.rootnode.child.Initialize
tv.rootnode.btn.Visible = False
tv.rootnode.lbl.Text = "SdCard:"
tv.rootnode.lbl.TextSize = 20
tv.rootnode.tag = File.DirRootExternal ' example for directory treeview
tv.rootnode.level = 0
tv.sv.Panel.AddView(tv.rootnode.pnl,0,0,linewidth,lineheight)
tv.sv.Panel.AddView(tv.rootnode.lbl,0,3dip,linewidth-lineheight,lineheight-10)
tv.sv.Panel.AddView(tv.rootnode.btn,3dip,3dip,lineheight-6dip,lineheight-6dip)
If get_data(tv.rootnode.tag) Then ' assign the first level of nodes
Dim nd(datalist.Size) As node
For i = 0 To datalist.Size-1
nodeinit(i,datalist.Get(i), tv.rootnode)
Next
Else
Msgbox("Files not accessible","")
End If
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub get_data(dir As String) ' this sub is now for files management, can be adapted to other kinds of data to be shown as tree
datalist.Initialize
datalist = File.ListFiles(dir)
If datalist.IsInitialized = False OR datalist.size < 1 Then Return False Else Return True
End Sub
Sub nodeinit(k,text,parent As node)
nd(k).Initialize
nd(k).pnl.Initialize("")
nd(k).lbl.Initialize("lbl")
nd(k).btn.Initialize("btn")
nd(k).child.Initialize
If File.IsDirectory(parent.tag,text) Then ' specific for files, for the case that items can or cannot be opened ( directory - file)
nd(k).btn.Text = "."
nd(k).btn.SetBackgroundImage(plus)
Else
nd(k).btn.Visible = False
nd(k).btn.Text = "F"
End If
nd(k).btn.TextSize = 14
nd(k).btn.tag = nd(k)
nd(k).lbl.Text = text
nd(k).lbl.TextSize = 20
nd(k).lbl.Tag = nd(k)
nd(k).level = parent.level + 1
nd(k).parent = parent
nd(k).tag = nd(k).parent.tag & "/" & text ' specific for file manager.
' Tag can be used for any data that you want to store in a node, in addition to the text. Here I use the path & filename.
nd(k).pnl.AddView(nd(k).btn,3dip,3dip,lineheight-6dip,lineheight-6dip)
nd(k).pnl.AddView(nd(k).lbl,lineheight,3dip,linewidth-lineheight,lineheight-6dip)
If nd(k).parent.pnl.Top + (k+1)*lineheight > tv.sv.Panel.Height Then ' extend the panel if it is too short...
tv.sv.Panel.Height = tv.sv.Panel.Height + 100
End If
tv.sv.Panel.AddView(nd(k).pnl,nd(k).level*(lineheight-6), nd(k).parent.pnl.Top + (k+1)*lineheight,linewidth,lineheight)
nd(k).parent.child.Add( nd(k))
End Sub
Sub btn_click
Dim b As Button
Dim tnode As node
b = Sender
If b.Text = "." Then ' used as flag between open and closed node
tnode = b.Tag
' get the list of sub nodes
If get_data(tnode.tag) Then ' if list is ok, proceed
b.Text = ""
b.SetBackgroundImage(minus)
Dim nd(datalist.Size) As node
move_nodes( tnode.pnl.Top ,datalist.Size)
For i = 0 To datalist.Size-1 ' assign data items to new nodes
nodeinit(i,datalist.Get(i), tnode)
Next
End If
Else
b.Text = "."
b.SetBackgroundImage(plus)
tnode = b.Tag
delta = 0 ' a counter for collapsed lines
remove_children(tnode )
move_nodes( tnode.pnl.Top ,-delta) ' move lower nodes up
End If
End Sub
Sub move_nodes( top As Int,lines As Int)
Dim v As View
For j = 0 To tv.sv.Panel.NumberOfViews - 1
v = tv.sv.Panel.GetView(j)
If v.top > top Then
v.Top = v.Top + lines * lineheight
End If
Next
End Sub
Sub remove_children(Rnode As node) ' close a node
Dim delnode As node
For i = Rnode.child.Size - 1 To 0 Step - 1
delta = delta + 1
delnode = Rnode.child.Get(i)
' recursion if the sub node is open
If delnode.btn.Text = "" Then remove_children(delnode)
delnode.pnl.RemoveView ' then delete it
Next
Rnode.child.Clear ' zero the child list in the closing node
End Sub
Sub lbl_click
Dim lb As Label
Dim tnode As node
lb = Sender
Msgbox("in this sub do what you want with this selected item" & CRLF & lb.Text & CRLF & " For example - color the panel","")
tnode = lb.Tag
tnode.pnl.Color = Colors.blue
End Sub
Edit: found a bug in sub remove_children, corrected.
edit: arranged the code better.
Attachments
Last edited: