[Lazarus] Collapse/Expand "bug" in VirtualTreeView "fixed".

J├╝rgen Hestermann juergen.hestermann at gmx.de
Tue Aug 23 17:11:37 CEST 2016

I have investigated a bit more into the "bug" in VirtualTreeView where clicking
on the plus or minus left to a node to collapse or expand it only works when
this (main) column is the most left column.
When moving this main column away from the most left position
(either in object inspector or on the fly on program run) then
expanding/collapsing with the mouse no longer works.

After a lot of debugging the whole afternoon I think I now
know the reason of this behaviour:

First step was the VTV procedure DetermineHitpositionLTR.
The first code line is:

MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn;

When, for example, the main column is 5 and I move this
(main) column to the most left of all columns then
both, HitInfo.HitColumn and FHeader.MainColumn are set to 5.
So both match and MainColumnHit is true.
In this case everything works fine and the node is
collapsed/expanded as expected.

But when I have the tree unchanged so that the main column is
still at position 5 then HitInfo.HitColumn suddenly becomes 0!

Going further and checking where HitInfo.HitColumn is defined
led me to HandleMouseDown.
This routine again uses GetHitTestInfoAt to set HitInfo:

HitInfo.HitColumn := FHeader.Columns.GetColumnAndBounds(Point(X, Y), ColLeft, ColRight, False);  // Here HitColumn is correct!
// If auto column spanning is enabled then look for the last non empty column.
if toAutoSpanColumns in FOptions.FAutoOptions then
   InitialColumn := HitInfo.HitColumn;
   // Search to the left of the hit column for empty columns.
   while (HitInfo.HitColumn > NoColumn) and ColumnIsEmpty(HitInfo.HitNode, HitInfo.HitColumn) do // this is true...
     NextColumn := FHeader.FColumns.GetPreviousVisibleColumn(HitInfo.HitColumn); // ... so HitColumn will be decreased down to 0!
     if NextColumn = InvalidColumn then
     HitInfo.HitColumn := NextColumn;

Here HitColumn starts with the correct value 5 but then,
depending on ColumnIsEmpty, is decreased to zero!

Looking at ColumnIsEmpty shows this comment:

// Returns True if the given column is to be considered as being empty. This will usually be determined by
// descendants as the base tree implementation has not enough information to decide.

Its body is:

Result := True;
if Assigned(FOnGetCellIsEmpty) then
    FOnGetCellIsEmpty(Self, Node, Column, Result);

So as default, all cells are considered to be empty!
But when adding an event routine OnGetCellsEmpty that
always sets

IsEmpty := false;

then suddenly everything works as expected and the bug is gone!

I am wondering whether this is all as intended.
Why is the column changed in GetColumnAndBounds
depending on whether a cell is empty?
It makes no sense to me.

More information about the Lazarus mailing list