Share My Creation Treeview

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 !

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

  • treeview.jpg
    treeview.jpg
    35 KB · Views: 13,654
  • Treeview.zip
    8.3 KB · Views: 1,752
Last edited:

rtesluk

Member
Licensed User
Longtime User
How to play an audio file with Derez' TreeView

In Sub lbl_click if the file selected is an audio file how can you get the app to play it.

BTW excellent coding!

Ray Tesluk
Port Hope Ontario
Canada
 

rtesluk

Member
Licensed User
Longtime User
Adding Audio To Derez's TreeView

Thanks nfordbscndrd!

for pointing me in the right direction with that link to MediaPlayerAndroid.zip.

I added the appropriate code to treeview and 'push'ed some wav files unto the emulator and everything worked like a charm.
 

rtesluk

Member
Licensed User
Longtime User
Programmably opening a specific node

Hi David Erez

Is there a method in code to open up a specific node in treeview?

I would like to open up a specific folder on sdcard in my code.

Ray Tesluk
 

derez

Expert
Licensed User
Longtime User
I added a small code part taken from btn_click and slightly modified it to suit the case, opening one of the first list of directories:
B4X:
Sub Activity_Create(FirstTime As Boolean)
Dim tnode As node
Dim store As Int

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)
      If nd(i).tag = "/mnt/sdcard/Codes" Then store = i  ' find the count number of the requitred directory "Codes"
   Next
Else
   Msgbox("Files not accessible","")
End If

                ' this part will open the "Codes" directory
tnode = nd(store)  
If get_data(tnode.tag) Then ' if list is ok, proceed
   tnode.btn.Text = "" 
   tnode.btn.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

End Sub
 

rtesluk

Member
Licensed User
Longtime User
Opening A Specific Node In Treeview

David, you just cut my programming time by 90%!!!

That snippet of code did the trick.

Thank you.

Ray:sign0098:
 

rtesluk

Member
Licensed User
Longtime User
TreeView Using ListView

Jun 14 2011
13:00 Hours

Hi David

Is there a way to use ListView in TreeView so that an icon can be added to the label?

ScrollView has Addview as one of its properties.

ListView has AddTwoLinesAndBitmap as one of its properties.

The icon could identify the 'type' of file e.g. audio or image file

Ray Tesluk :sign0085:
 

rtesluk

Member
Licensed User
Longtime User
Jun 18 2011

Hi

How can I place an icon (bitmap) on the same level as a label (lbl) in TreeView?

Thanks,

Ray Tesluk :sign0085:
 

derez

Expert
Licensed User
Longtime User
How can I place an icon (bitmap) on the same level as a label (lbl) in TreeView?

The Treeview is just a framework for things that you can do with the existing tools of B4a.
Adding a bitmap to each node can be done by adding an imageview to the node type:
instead of
B4X:
Type node(pnl As Panel,lbl As Label,btn As Button, tag As String,level As Int, parent As node, child As List)
write
B4X:
Type node(pnl As Panel,lbl As Label,btn As Button, tag As String,level As Int, parent As node, child As List, [B]img as imageview [/B])
, don't forget to modify the nodeinit sub to initialize the imageview as well as the label and button, and to "addview" it to the node's panel. You'll have to make space for the imageview, between the button and the label.
Also please see the note here :
B4X:
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.

It means that in the example I used the tag for holding the path of the item, to be used as file manager. If you added another view to the node, you can use it's tag to hold additional data and use it as necessary.


Is there a way to use ListView in TreeView so that an icon can be added to the label?

I don't see how, as a listview is a complete structure like the treeview is. I believe the above provide the needed additions you want.
 
Last edited:

derez

Expert
Licensed User
Longtime User
I made the changes in the attached file, but I use the same image file for all lines. To make it specific to the line you need to pass the image file name as parameter to the nodeinit sub and then init the bmp with it before allocating it to the imageview.
 

Attachments

  • treeviewbmp.zip
    16.5 KB · Views: 661
  • tvbmp.jpg
    tvbmp.jpg
    41.2 KB · Views: 959

rtesluk

Member
Licensed User
Longtime User
Another Feature For The Treeview Project

Jun 18 2011
09:35 Hours

David Erez, my man! You have done it again!

I made your changes to my project and it worked perfectly.

I had a solution using the label's background property and placing an image with a transparent background and the icon in the left lower corner, but your way with much more elegant.

Thank you again for your efforts in this matter.

Ray :sign0098:
 

philgoodgood

Member
Licensed User
Longtime User
hi
@derez : this code is a little marvel ... a big thank for all this
 
Top