[Lazarus] Problem with TCustomTreeView

Tony Whyman tony.whyman at mccallumwhyman.com
Fri Dec 5 11:25:37 CET 2014


Am I missing something, or is just a bit too much information kept in
private properties without enough virtual methods to this class.

I am trying to create a component that presents a hierarchically
structured set of data using a treeview. I want to both present the data
in its natural structure, and add, edit and delete nodes with the
changes refected back to the original dataset, including moving nodes
between parent nodes. Only problem is that I don't seem to be able to do
this with the standard TCustomTreeView. Nor can I meet this requirement
with a standard TTreeView component and using its events to synchronise
the dataset.

Loading the TreeView:

The initial load of the Tree View is easy enough. I can maintain a link
to my original data by subclassing TTreeNode and adding additional
information. TCustomTreeView.CreateNode is virtual and overriding this
allows me to use my own TTreeNode subclass. Alternatively, I could use
the TTreeNode.Data property to contain some link to original data record.

Insert:

This also works fine. Overriding TCustomTreeView.Added allows my
component to react to all added nodes after the initial load. I could
also use the OnAddition event for the same purpose.

Node Move between parents:

TTreeNode.MoveTo is virtual and I can override this to notify my
component when the parent changes. However, there does not seem to be
any TTreeView event that could be used to notify external
synchronisation code. The "OnChange" event seems only to be fired when
the selection is changed.

Changing the Node Text;

This is really tricky, especially as neither TCustomTreeView.BeginEdit
nor EndEdit are virtual and the FEditingItem is private.
TCustomTreeView.EditorEndDone is virtual but this does not give out any
information about which node was edited. For external synchronisation,
the "OnEdited" event does work and gives the Node that was edited. For a
component derived from TCustomTreeView it seems that you have to use the
Event Handler to get at this information (not very nice).

However, more generally, there seems to be no way to react to the
TTreeNode.Text being modified programmatically as this event is not
reported by the TTreeNode to the parent view.

Deleting a Node:

TCustomTreeView.Delete is virtual and fires the OnDeletion event and so
this should work - except that this can be called/fired for multiple
reasons and not just in response to a node being removed from the tree.
E.g. It can be called for housekeeping reasons in response to:

- TTreeNodes.Clear (when the tree is reset or being destroyed)
- TTreeNode.Collapse (when the visible tree is being pruned - but this
should not affect the dataset).

Inspection of TTreeNodes.FStates or TTreeNode.FStates could tell you why
TTreeView.Delete was called but as these are private...

There seems to be no way to safely react to TTreeView.Delete

Proposed Changes:

I would like to submit a patch that changes the following in
TCustomTreeView:

1. It would be nice if TCustomTreeView.Change was called when the
TTreeNode.Text (or Data) changed, or when the node changed parents.
Although for backwards compatibility, this probably has to be a new
virtual method/event. So propose to add:

TCustomTreeView.NodeChanged(Node: TTreeNode); virtual;

and which calls a new event "OnNodeChanged". TCustomTreeView.NodeChanged
is called from TTreeNode whenever the Text, Data or Parent is changed.

2. TTreeNode.FStates and TTreeNodes.FStates are made visible as a public
read only property.

3. Although not essentially, TCustomTreeView.BeginEdit and EndEdit
should be virtual and FEditingItem made visible as a protected read only
property.

Any comments?

Tony Whyman
MWA




More information about the Lazarus mailing list