|
There are really five operations you can perform to change the hierarchy - modification, addition, duplication, deletion and relocation. In other words, you now have a functioning treeview control. What to do with it? If you modify it, in this case, it means only that you've renamed an item. You can add new nodes, of course, one by one. That's what was done to intially fill out the treeview. You can delete one node, or that and every sublist under it. You can move, or relocate, one node, and every sublist under it, either just within the same sorted list, or to another level entirely (to keep this simple, in the following examples, the lists are simply sorted alphabetically - not by any sort scalar). And you can copy a node, and even every sublist under it (which might be particularly handy for alternate treatments or languages, for ex; copy the whole 'book' at once). Of course, as with getting data into the treeview, none of this is built into the treeview control itself. All the treeview does is display whatever hierarchy is 'hard-coded' into it for that session. You have to create routines to do all of this, to both change the treeview, and change any underlying data in the table. One operation which doesn't change the data is, of course, searching. The treeview makes it easy since you can find a node based on the node's key. And here that key is based on the unique id of the underlying record in the table. Just run a query SELECT to find the unique id, and prefix the "a" to it. It does raise the question with regard to querying such an 'adjacency list', however.
One can change the text shown in the treeview. In the properties box/window for the control, it should have its Label Edit property set to twvAuto, or 0. Then if you click and hold down the mouse button for a second or so, then release without moving, the entry should go into edit mode. You type in the new text, hit the Enter button. And not only will it be changed in the treeview, but you want the underlying table to reflect that same modification:
Modification amounts to renaming a node. The renaming is caught when the Enter key is pressed. That also suggests that if the Enter key is not pressed, but simply that another node is clicked, that the change won't be reflected in the data, since it won't come through here. Now one could probably just use a SELECT (lookup) and UPDATE on the top, for the Enter key. But since a recordset is otherwise used, here, it's just as easy to use that. And note that when the node is renamed, that the superior node has to have Sorted again set, as noted previously.
The same short routine also covers the call to the insertion/deletion of a single new node. You can see that inserting/adding a new node passes control to another function, the subroutine, sInsertNode:
Here a flag is sent to indicate whether the new node goes in the same level/list as the clicked node, or whether it goes in the sublist of that node. Again, the sort isn't a factor, since the sublists are alphabetically sorted, automatically, by the setting of the Sorted property. Personally, I think it's a needless complication. It's as easy to click on the superior node, and just always add to the sublist, period. Because one can move nodes around, if that isn't suitable, one can just relocate the node manually, in the treeview. Anyhow. And again, this reads/writes via a recordset, when a SELECT and UPDATE might be just as good. The tree itself has another property - selecteditem - which is obviously useful. So by clicking or moving in the treeview, it's known which node is in question. This is assigned to a node type. And it's probably wise to check for duplicate text, as done here - though I suppose it's not absolutely necessary (it's the key that has to be unique). The assumption is that if there is no strKey, that it must be a top level node. So that gets a 0, in in that case. But if this toggle/switch is off, then any new node goes at the same level/list. That means the superior node is that which is superior to the selected node. Since this uses an auto-generated autonumber unique key for the records in the table, the final bookmark gets back to the record just created so that the newly generated id can be read. The only other thing is that the node must be correctly placed in the tree. If the toggle is on, it means place in the sublist, under the node; or same level if not. So here the node's parent property, seen above, is used if the toggle is off. And that's about that.
And again the same short routine, previously, also included a deletion method. Click on the node, and hit the Delete key. The logical thing is that the node, and all sublists under it, are deleted. That's just what the remove method of Nodes does. But that has to be then reflected in the underlying table:
I can almost hear some saying, finally, he got sensible and started using SQL, which is how Access can work at its best. It just was particularly suitable, here. To clear out all the sublists in the table, it's really pretty straightforward. No recursion is needed. One just makes a hole by deleting the selected node. Then its sublist, if one exists, is just hanging there. The superior node to which all the items point, is now gone. That unique number for the superior node is no longer found in the table. So you can just collect the 'strays'. And delete them. Then if those each had sublists, suddenly those sublists are left hanging. And all those items become 'strays'. They can be collected and simply deleted at once. And this just continues in a loop until no more 'strays' are found. Simple. It's also a bit self-correcting if 'strays' were created by program glitches or some other cause. This doesn't care how the 'strays' were created. It just burns every one, any time you delete so much as a single node from the treeview. The "(0)" after SELECT Count(*) is just a shorthand to read the actual count of records matching the criteria. And the fGetThisDB is just the equivalent of CurrentDB. It came out of some brief online discussions about earlier Office versions and whether CurrentDB, alone, was always reliable. So just for curiosity, here's the fGetThisDB. Probably quite unnecessary. CurrentDB should be just fine, instead:
So that only leaves Relocation and Duplication. |