Using helper objects doesn't mean, though, that you need to avoid
inheritance. In your case you could create descendant nodes for no other
reason than to store a helper object (and maybe carry out a few maintenance
operations). You could create a new custom node for each kind of helper
object, or (as you hinted at in the e-mail you sent me privately) use
interfaces to work with a standard set of methods on any kind of object - a
much cleaner solution in my opinion.

The components I have made by descending from TCustomTreeView, TTreeNodes,
and TTreeNode are generic. They have simply adapted the TTreeview to allow
any kind of node(s) to be stored inside it as long as they are descendants
of TTreeNode. In your case, it would be useful for no other reason than to
allow you to store a node that new how to talk to your helper objects. This
may be trivial but infact it allows a significant code-reuse benefit the
next time you have to do a similar treeview on a different form or with
different data because all the code for adding and talking to the helper
objects is encapsulated in your TTreeNode descendant ("encapsulated" is a
good OOD word :-). And you still have the NodeObject property to play with.

Now if only someone was able to answer my first query about the
Items.clearcache call in the CustomSort routine :-(

Phil.

[Mark Said]

I take your point, but it begs the question of the architecture you are
using, and more importantly where you put what code.

I have a real-world example that does a very similar job to the structure
you outline, but with a custom-drawn canvas and attributes that determine
the structure being drawn. It had a fairly sophisticated hierarchy when I
got involved, though nothing to do with treeviews, which had broken because
it had become too complex (the original design had become too stretched).

We considered various approaches to showing the structure using a treeview,
which they now saw as the silver bullet, but settled on keeping the objects
outside the tree. Partly this was because the eventual objects reflected a
strong hierarchy of their own, but mostly because we decided the tree was
simply a graphical representation of the "real world", and not the
hierarchy itself.

To cut a long story short, all the traditional "tree" code got moved out to
the objects. We also simplified the hierarchy with some judicious decisions
on what was really different at each level. So the "helper" objects did all
the work, including popup menus and various other things, and the tree
simply became a display shell that knew how to ask for, and create, the
next level of nodes below the current one. So rather than the tree being
the hierarchy, it just became a display device for the objects, which had
the nice side effect of being able to produce other sorts of UI without
much work.

I'm not saying this is the "best" approach, but it did work well in this
instance and it did greatly simplify the core of the project, and therefore
improved the ability of other developers to use it reliably.

It is just an alternative way of casting the solution.

Max

[Phil Said]

That may work, but now you have used up the object holder for each Node's
object. That means that your implementation cannot be descended from
correctly if that place holder is required in the descendant class. The
argument for using helper classes is fine but your new class shouldn't have
less functionality than the descendant class (in this case the NodeObject).
Consider this example:



A Treeview must display a heirarchy  of animals structured according to
their species. As each folder in the treeview is opened (eg "dog") a panel
on the right displays generic information about dogs, plus an icon for each
folder below it (eg "retriever", "poodle"). If the "Retriever" folder is
opened then the panel displays some information about retrievers plus a
list view of summary information about each retriever below it. If a
"Golden Retriever" node is selected from below the retriever folder then
the panel on the right displays detailed information about the golden
retriever, plus an imbeded movie. The kind of infomation displayed is
completely different for other species of animals.



This is just a made up example but it will do. Using an inheritance
structure each node can be added as a (eg.) TRetrieverNode or a TDogNode.
The TDogNode knows how to display the information on the right, and knows
what to pass to and from a persistence mechanism. All the calling code has
to do is call a new "Draw" method, passing in the canvas to draw it's
information to (in this case the panel on the right). The calling code
doesn't care what the node/folder is that is selected because it knows how
to draw itself.

Now if someone wanted to re-use these new TTreeNode descendants and
associate a quick menu (via right mouse) with each kind of node, they can
do it. The quick menu can be stored in the NodeObject for each node because
it hasn't been used.

That won't work as cleanly if you use the helper object approach. Each node
doesn't really know what kind of information it is, it relies on the stored
object to do all the work - but what if the stored object is missing?!?
Could happen - but not if the information is built in to the node itself.
Worse, because the ObjectNode is already used up with the new information
for each node, it is no longer available for use to hold the quick menu.

An even more fundamental problem with the helper object approach in this
case is code reuse. The code for adding the object and calling the relevant
methods and filling the relevant data has to be repeated (or adapted) each
time you want a new treeview. You haven't actually created a new component
that you can reuse later. All you have done is used the TTreeView component
an (I assume in you main code) manged the nodes and objects.



Hope I haven't missunderstood you.



Phil.



---------------------------------------------------------------------------
    New Zealand Delphi Users group - Delphi List - [EMAIL PROTECTED]
                  Website: http://www.delphi.org.nz

Reply via email to