Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Help with Tree View 2

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
So after a few have suggested that for one of my more complex relationships that a Tree View might be an easier form of navigation, I decided to give it a try.

But wow... this is one of the more daunting controls, and I remember now why I always avoided it in the past. I've read through a lot of the site posts, many of which have links to articles that no longer exist... (pity that wasn't thought ahead and had some of the core bits brought into the post instead of linked outside the site). Of the few I found, they still seemed to be so different in their example, and compared to the example in the SAMPLES section of VFP, I still don't "get it".

In particular, I see in code references to a "node" property, but the ActiveX control I see only "NodeChec" and "NodeClick" methods, and no other properties related to node. So I don't understand how to write these.

One example creates a "procedure" called PopulateTreeView, I'm not sure if that's the same as a "Refresh" clause on the Treeview control, or is it better to add this method?

I suppose in general what I'm looking for out of all this data is, what's the best way to approach this class? Great that they created this very powerful "base class" but it's so sparse in it's otherwise implementation.

I think maybe it's best to describe as well, what I envision is having a "Root" node that is populated from one table, and then the child records for the root nodes added to the table. (There are grand-child and great-grandchild, but I suspect if I can get Parent (root) and child then the rest should be just cascading that.)

Appreciate your help on guiding me through this, I've never used this class before.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
What Tamar said.

Treeview (not unlike FoxPro itself) is easier to use than it is to learn. Doug Hennig's articles demystify it.
 
Also do yourself a favour and use another treeview. The MS Treeview Control is a very basic treeview. Dbi and Exontrol offer ActiveX controls with VFP sample code, for example. And their treeview also is usable as a tree/grid mix. Dbi had a free library of controls as Sedna was releaased, I don't know if that offering is still kept. The offering page is still there ( but Free Download leads to the normal download section.

Bye, Olaf.
 
Thanks Tamar,
The article is useful and nice that it's a PDF, but I have to admit, it's still beyond me. It seems to assume you know an awful lot about a number of things I still can't track down. (SFTreeViewContainer)? LoadImages method (I can't find this, though it also references the container I can't find nor create with the same methods, is this a custom method? It doesn't mention that... so I don't know if I should be adding this method to the existing ActiveX control, or I'm missing some component that needs to make this work?

It also seems to be incomplete from some article for a magazine, and references "in the next article, we'll discuss handling node selection, drag and drop, and other behavior, then look at a form class that ties SFTreeViewContainer to a pageframe of properties for the selected node", but this is a PDF, and there's no link to "the next article".

It did have a nice list of things that you need to be aware of, but this has just added to my confusion over this control...

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott,

I'm sure I could talk you through all the steps of building and accessing a tree via the Treeview control - as could several of the other forum regulars here. But, you know, that's asking quite a lot. As you have discovered, it is a complex control, and there's a lot you need to know even just to get started.

That said, let me try to give you a few pointers, just to get you started:

1. A treeview is a collection of nodes. Each node represents one of the items in the tree.

2. To build a tree, you add nodes to the collection. You do that with the Add method.

3. The Add method takes the following parameters:

- Reference Key. The index or key of the node to which the new node is related (see third param).

- Relative Index. Says how the new node is related to the reference key (see below).

- Key. A unique identifier for this node; can be numeric or character.

- Text. The text that appears in the node.

- Image and SelectedImage. Used to add icons to nodes. Since we are only taking the first steps here, ignore these until later.

4. The second of these parameters (Relative Index) can take the following values:

0: The new node is added to the top of the tree.

1: The new node is added to the bottom of the tree.

2: The new node is placed after the one referenced by the Reference Key.

3: The new node is placed before the one referenced by the Reference Key.

4: The new node is placed one level below the one referenced by the Reference Key.

So, here is an example of what we've got so far:

Code:
THIS.nodes.add(, 1, "A1", "Sales Department")  && top node
THIS.nodes.add("A1", 4, "A2", "Section 1")  && 2nd level
THIS.nodes.add("A1", 4, "A3", "Section 2")
THIS.nodes.add("A1", 4, "A4", "Section 3")
THIS.nodes.add("A2", 4, "A5", "Team A")  && 3rd level

5. When the user clicks on a node, the NodeClick event fires. This event receives a parameter, this being a Node object.

6. The Node object has methods, properties and events of its own, including the following properties:

- Children: says if the node has any child nodes.

- Expanded: says if the node is expanded.

- FullPath: Concatenation of the text values of all the nodes leading to this node.

- Index: The index of the node within the Nodes collection.

- Key: The unique identifier of the node.

- Text: The text that appears in the node.

You can use the above parameters to tell you which node was clicked, and to take action accordingly.

A trivial example:
Code:
* NodeClick event
LPARAMETERS Node
MESSAGEBOX("You clicked on " + Node.Text)

OK, I'll stop there. Play around with the above (assuming you haven't decided to abandon the Treeview), then come back with some specific questions.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,
Thanks very much. I hate having to be spoon fed, but this one is really clobbering me.
In taking what I read in Doug's paper, and what you've just described above, is it (best practice) to put the Treeview control into a container? I think I'm starting to see what Doug was driving at, particularly around the "gotcha's" and how the container helps manage some of them, and I think what you're equipping me with here is "one step at a time" which I appreciate very much. I suppose I could build this first and then put that in the container later.

It's also strange, as I work with this control when following intelisense it seems that some properties appear there that don't appear in the properties screen. So that's a bit confusing. But then, I guess this acts a little more like the Grid control too, where there are other objects that you cant' see until you actually put one on a form, so I'll "have faith" for now, and start breaking things. :)


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
I wouldn't usually put a treeview in a container. But I can see some possible benefits of doing so. If you are building a re-usable treeview class, you might want to bundle it in a container along with an ImageView control, which you use to add icons to the tree. But in keeping with the one-step-at-a-time approach, I suggest you ignore that for now.

Re the properties, the VFP properties window should show all the properties of the treeview, but not those of its contained objects. In addition, you can right-click on the treeview (in design mode) and select TreeCtrl Properties; this will open a dialogue where you can access a sub-set of the properties (mainly those affecting the tree's appearance).

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,
Ok! Great explanation, I now have the first level of the tree populating. I'm assuming now that a "Node" object is really an array of information about the item (much like other objects). I think I can tinker around now to get some of the others working.
One question here... for the "Key" if I have a unique key for the item already (from a table, like ContactID) is it good practice to use this as the key in the tree, so that it follows other database relationship key integrity? I don't know if numeric is allowed as the example shows "A1", etc, but either way I can convert the int values if need be. (Sorry, explaining this "out loud" helps me understand, and if I've got it wrong, someone can correct me.)
Cheers!

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Yes, it is indeed good practice to use the same primary key (or other unique key) from the table and for the node - provided of course that all the nodes come from the same table. If you have a typical parent-child relationship in the tree, you might need to concatenate the key with the table name, or some other way of uniquely identifying the table.

As far as the Node object is concerned, it is just that: an object, with its own properties and methods. I mentioned some of the properties in my earlier post.

But be careful. As well as the Node object, there is a Nodes collection (not the plural). This is itself an object, with methods such as Add and Remove. As with all collections, you can loop through it using FOR EACH:

Code:
FOR EACH oNode in THIS.Nodes
  ? oNode.Text
ENDFOR

You can also reference individual nodes via the collection:

Code:
? THIS.Nodes(1).Text  && first node
? THIS.Nodes("A5").Text  && nodes whose key is A5

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
If you want quick results, you can use the attached class.

It's a class for representing cursor in a tree, using VFP grid.
I've created this class to overcome the limitations on the number of columns and lines of the "treeview"
It's an old, but reliable class. It has an awful programming style. You can improve it.
But I have used the class with large tables and with up to ten level of depth

A node is a row of the grid and the node can have multiple columns (like any grid).

Example
******************
If you have the cursor cTest with the following fields
[pre]Adress city country amount
A1 London UK 250
V2 Bristol UK 300
s2 London UK 100
s33 New-York USA 45
zzaa Bristol UK 15[/pre]

and you want to display like this

[pre]UK 665 (total = 250+300+100+15)
London 350 (= 250+100)

A1 250
s2100
Bristol 315 (= 300+15)
V2 300
zzaa 15
USA 45
New-York 45

s33 45[/pre]

All you have to do is to call
Thisform.gride1.cur2tree('cTest','adress,amount','Country,City','adress','Invoices','sum(amount)')

Parameters explained
1) the table/cursor source is 'cTest'
cur2tree('cTest'

2) the visible fields are: adress,amount
cur2tree('cTest','invoice_id,adress,amount'

3) the hierarchy (grouping) fields are: Country,City
cur2tree('cTest','invoice_id,adress,amount','Country,City'

4) The parent nodes (country and city) must be displayed in the tree in the "adress" column
cur2tree('cTest','invoice_id,adress,amount','Country,City','adress'

5) If you want, you may add a (unique) root node, called 'Invoices'
cur2tree('cTest','invoice_id,adress,amount','Country,City','adress','Invoices'

6) the amount must be totalised (subtotals)
cur2tree('cTest','invoice_id,adress,amount','Country,City','adress','Invoices','sum(amount)')
**********************

If you want the terminal nodes have a symbol / graphic, you can attach it to the button control (cmdtree of VCX).

You can test either by launching test0. prg...test7.prg (the basic settings), or by launching grdtree.scx from grdtree.pjx (more settings)

Thevcx.zip contains :
- grdtree.vcx (the main class is gridtree)
- class_col_tree.prg and class_head_tree.prg (two prg containing the column and header classes used by the grid)
- grdtree.pjx (a demo project)
- grdtree.scx (a demo form)
- NodMinus1.bmp and NodPlus1.bmp two pictures used by expanded / collapsed nodes
- test0.PRG...test7.PRG (eight demonstrative prgs, that show step by step the main settings)

The demo form (grdtree.scx) contains four examples (form methods ex1, ex2, ex3, ex4)


Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
 http://files.engineering.com/getfile.aspx?folder=9f5969af-000f-4428-9328-69510b6e05ea&file=thevcx.zip
Sounds interesting, Vilhelm-Ion. I'll maybe take a look at this when I get a moment. In the meantime, let me check one point. Is your control in fact a native VFP grid which is made to simulate a tree?

If so, there will clearly be important cosmetic differences with the Microsoft Treeview control. No doubt, Scott will judge these for himself. But there will also be one significant advantage. It's likely that the performance will be much better, because - as we know - a grid populates very quickly. In contrast, populating a Treeview with a large volume of data can be very slow. (I believe Doug Hennig's class partly overcomes that by deferring the building of lower-level nodes until the parent nodes are expanded.)

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Indeed, the baseclass is a native VFP grid.

The speed is good, but depends on some settings and the tree structure.
I'm sure the speed can be improved, but it's really an old class with successive improvements. Still, its the core is old.

I believe the maximum tree depth is 20-25 levels, which is far too much for my needs.

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
That's just amazing.
I'm actually feeding from multiple grids... (or their parent table, still trying to work out what works best).
I think it will be faster from table, since first, build the grid, then build the tree, or just build tree from table.
But I'm also toying with a similar idea of Doug's, where only building child when it expands.

One question maybe you guys can answer... in a Gird, I think it was Doug mentioned, when dynamically rebuilding:
This.Gridsource = ""
at start, and then
This.Gridsrouce = "<gridname>"

Is there a similar philosophy in trees?
So let's say, I have a tree that's based on a Company Record, which has branches:
Locations
Employees

Where both may have multiple.
So when the company changes, in this Tree view, I need the "new company" record, and it's children.
How do you "wipe" the existing tree and start a new one? What I've seen so far is, ADD, just adds more roots and trees, but what if I want a "reset" and start a new tree?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Can anyone explain the "Relationship as Variant"? In the example Mike gives, in the first case it shows 1, then in 2nd and 3rd it shows 4. What does this represent, and does it increase at lower child levels?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
How do you "wipe" the existing tree and start a new one?

[tt]this.nodes.clear[/tt]

But you don't need to wipe the entire tree if only one company changes. You can delete an individual node:

this.nodes.remove(<index of node to be removed>)

and then add a new one. Or you can simply change the text of an existing node: just assign a new value to its Text property.

Keep in mind too that you can allow the user to edit a node directly, just by clicking on it. But you need to call the tree's AferLabelEdit to apply the change to the underlying record.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I've got it working to 2 layers deep, but not the 3rd. I'm not sure why. Trying to sort that out.

The example I asked about changing it was intended to just showing the children on one parent at a time (use a grid to step through parent, use a tree to show relationships).
Still playing with this idea. For now I'm listing all parents.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Ah, got next layer down working. Gets a bit trickier as you go, but it was a stupid mistake I was making before.
Mind you this is just the "population" of the tree, it's not doing anything else for now, but even getting it populated properly is a nice thing to see. Very cool.

Oh, and one other point Mike, about only showing 1 top level...
In some cases, data is confidential. And if I have a client looking at the screen, I need to be able to show them ONLY their record, which is easy with a "Hide Companies" feature I had on my grids (just a simple filter).

But I assume for the tree, I need to clear it, and rebuild it then showing only the records from that company, and it's associated tree. So sometimes, yes, I have to clear it all, and build a new one.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
I should have pointed you to Doug's papers page rather than right to the particular paper.
He has a link for the sample code as well. I don't know offhand which was the paper that followed this one, but you can probably figure it out.

Tamar
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top