B4A Library [Class] Treeview Class (Tree and Node)

After finding how to communicate between classes I improved the previous version and since it is completely different, I opened a new thread for it.

There is a Tree class, in which you have to define the nature of the tree (what database it displays). This class manages the nodes which are defined by another class.

I implemented a horizontal "scroll panel" to compensate for the scrollview's lack of it.

The main is a demo with one tree in portrait and two trees in landscape node.

Edit: Version 3 has automatic setting of the treeview panel height and width, so linewidth is calculated, not supplied.
The datalist is sorted.
Arrows added to the slidepanel to hint about its use.
Edit: version 3 updated to have automatic width reduction when nodes close.
Version 4 can scroll horizontally thanks to Informatix additions.
Edit: version 5 use Informatix new 2D ScrollView.

Edit: Updated to ver. 6 :
- The tree is isolated from the specific use (like file manager or family tree), the definition of the data that populates the nodes is done at the calling activity using sub GetData which is called by the tree when required.( Edit: not all the way, in the node_open you still have to change the tag and the text of the new nodes to suit other kinds of trees...)
- LongClick on a node is passed for action to the calling activity to a sub NodeLongClicked.
- OpenRoot method enables display of the root node open (by code, the user can of course open it by pressing the + button)
- NullImages - Possibility to remove the images of file and folder (the label will move left accordingly).
- Wait cursor activated smartly (!!) only when opening nodes with many children, not to slow the program too much.

Edit: Updated to ver. 7 :
See details in this post. http://www.basic4ppc.com/forum/addi...ss-treeview-class-tree-node-3.html#post149450

Edit: updated to ver. 8, the only change from 7 is that data type is in the tree class , not in the main.
Also the Reflection library is not used and can be ticked off.

Edit: update to ver 9. I saw that with new devices of high resolution the lineheight is too large so I adjusted it to give better results for all devices.
If you encounter line size problems please tell me (with the specific device parameter).

Edit: see post #85 for a method to open all nodes of the tree by code.

Looking forward to get feedback !

Note: For B4A ver. 7 replace in tree line 190 Doevent with sleep(0)
 

Attachments

  • screen3.png
    screen3.png
    58.8 KB · Views: 2,420
  • screen4.png
    screen4.png
    57.7 KB · Views: 2,097
  • Treeview9.1.zip
    24.6 KB · Views: 544
Last edited:

Informatix

Expert
Licensed User
Nice improvement.

There's still place for some improvements: a waiting cursor when you open a node with a lot of children, an automatic horizontal scrolling, and a horizontal scrolling with a finger move on the main view (I didn't understand when I tried the demo the first time why there's a grey bar at the bottom). Do you agree with that ? If I have free time this week-end, I'll try to help you (I have some ideas on how to solve these problems). If that doesn't bother you...
 

Informatix

Expert
Licensed User
I tried to make changes to your code, but I ran into frequent StackOverflow crashes, so I decided to give up. I don't have enough time to find the reason of theses crashes (it's not related to a path not allowed).
However, as I promised, here is a sample demonstrating how to do a TwoDScrollview. It needs the AHViewPager and Reflection libraries.

Fred
 

Attachments

  • TwoDScrollView.zip
    6.9 KB · Views: 417

derez

Expert
Licensed User
Informatix
It is even simpler than that.
I only added reflector and touch event for the SV (treeview in my app), and the following subs:
B4X:
Sub treeview_touch(ViewTag As Object, Action As Int, X As Float, Y As Float, MotionEvent As Object) As Boolean
   HorizontalScroll( Action, X , Y )
End Sub

Private Sub HorizontalScroll( Action As Int, X As Float, Y As Float) 
Dim q As Float
   Select Case Action
      Case 0
         x0 = X
      Case 2
         q =  TRP.Left + X - x0
         If q > Lmin Then 
            TRP.Left = Lmin
         Else If q < Lmax-TRP.Width  Then 
            TRP.Left = Lmax- TRP.Width
         Else
            TRP.Left = q
         End If 
   End Select
End Sub

I removed the slidepanel and it works.
The only problem is that you have to take care to touch where there is no label, otherwise the label takes the touch event as click or longclick.
 

Informatix

Expert
Licensed User
The only problem is that you have to take care to touch where there is no label, otherwise the label takes the touch event as click or longclick.

Easy to solve:
1) Make HorizontalScroll public
2) Add in the node class (after initializations):
B4X:
Dim r As Reflector
r.Target = TN.pnl
r.SetOnTouchListener("touched")
r.Target = TN.lbl
r.SetOnTouchListener("touched")
r.Target = TN.btn
r.SetOnTouchListener("touched")
3) Add this event in the node class:
B4X:
Sub touched(ViewTag As Object, Action As Int, X As Float, Y As Float, MotionEvent As Object) As Boolean
   Cmodule.HorizontalScroll(Action, X, Y)
End Sub
 

derez

Expert
Licensed User
I haven't tried it yet but I believe that the label event is cancelled, because it is passed to the HoreizontalScroll sub.
 

derez

Expert
Licensed User
Informatix
It works but it is jumpy and sometimes the labels get clicked when I don't mean it.
I prefer the slidepanel solution but of course once it is in the thread, everyone can select his own way of use in his application.
Thank you very much for teaching me the use of reflector for touch, I didn't know about it and it does give me more flexibility in some applications that I'm going to improve right away..
 

Informatix

Expert
Licensed User
Informatix
It works but it is jumpy

In fact, to get a really good result, it is a bit more complicated than that. You have to take into account factors like finger wandering (ScaledTouchSlop) or velocity (ScaledMinimumFlingVelocity). See here. It's easier to do with a Java lib than directly with B4A.

the labels get clicked when I don't mean it.
??? That shouldn't happen. My current app uses a lot this technique (with a few improvements) and I have no problem of this kind. Maybe I forgot something in my code samples.
 

derez

Expert
Licensed User
??? That shouldn't happen

It is not a bug, it is only the slight difference between a touch and a click. Since I need the label click, sometime the touch is taken to be a click. This is the main reason I prefer the slidepanel - it has its own place and the user touch/click exactly to do what he means to do.

It's easier to do with a Java lib than directly with B4A.
I was just looking at the source code of scrollview in Java before seeing your post. I am not going to dive in to this. I guess there is a reason why scrollview is only one-dimension-scroll...
 
Last edited:

Informatix

Expert
Licensed User
It is not a bug, it is only the slight difference between a touch and a click. Since I need the label click, sometime the touch is taken to be a click. This is the main reason I prefer the slidepanel - it has its own place and the user touch/click exactly to do what he means to do.

I modified your files to do quite the same thing I do in my custom ViewPager lib (it seems that the simpler version I put here is not enough). I don't handle velocity and flings, but I find the experience satisfying. Tell me. You can fine tune the scrolling smoothness by changing the value of pxTouchSlop.
The timer is juste there to take your remark into account and provide an additional method to distinguish touch and tap, but it is not necessary at all in my own projects (the difference is made by the amount of move).
All the code I added or modified is enclosed between long comment lines.
 

Attachments

  • TreeviewWith2DScroll.zip
    24.6 KB · Views: 374

derez

Expert
Licensed User
Thank you, I'll check it later.
In the meantime I updated to version 3 with automatic adjustment of height and width of the panel.
 

derez

Expert
Licensed User
Informatix
I checked it on an emulator - smooth like butter :sign0188:
I'll combine your solution with version 3 modifications.
 

derez

Expert
Licensed User
Version 4 added to the first post, with Informatix horizontal Scroll functionality.
 

derez

Expert
Licensed User
I suggest a last thing: replacing the sort by a case insensitive sort.

The sorting belongs to the application, not to the tool. It is for the application developer to decide if and how to sort, in accordance with the nature of his database.
 

Informatix

Expert
Licensed User
The sorting belongs to the application, not to the tool. It is for the application developer to decide if and how to sort, in accordance with the nature of his database.
Yes, but:
1) What I see is a class displaying files in a treeview and these files are not sorted in a useful way. If someone wants to use your class as is, he has to fix the sorting before adding it in his app. I know of no good reason to let a bug somewhere.
2) I strongly agree with the fact the sort function belongs to the app more than the class, but why, in this case, is it in the class ?
You designed your class in a strange way (to my eyes). There's no possibility to feed the treeview with data outside the class. So I wonder how to use this class in a real app if I have to display different contents (e.g. a file treeview here, an option tree there).
 
Top