I have an array holds data will be represented on TVirtualStringTree. This array is thread-safe and lockable. And grown by another thread.
My problem is that, when VST executes OnMeasureItem event to measure height of the node, data used for measurement can change when it come to the point of printing data with OnGetText event.
I have checked the execution order of events and it is not good for my design. First It fires OnMeasureItem event for all nodes which is not initialized then it starts calling OnGetText events. I mean, suppose we have 3 nodes, events will be fired in that order:
OnMeasureItem for node 1
OnMeasureItem for node 2
OnMeasureItem for node 3
OnGetText for node 1
OnGetText for node 2
OnGetText for node 3
But I need something like this so that I can lock:
OnMeasureItem for node 1
OnGetText for node 1
OnMeasureItem for node 2
OnGetText for node 2
OnMeasureItem for node 3
OnGetText for node 3
What is the best way to maintain synchronization of data obtained between OnMeasureItem and OnGetText events?
I don't want to lock my array during all OnMeasureItem() and OnGetText() events.
Thank you.
Added onTimer:
procedure TMainForm.SyncHexLog;
begin
HexLog.BeginUpdate;
Try
if (HexLog.RootNodeCount <> FirpList.ComOperationCountLagged) then
begin
HexLog.RootNodeCount := FirpList.ComOperationCountLagged;
// measure for fast scrolling
HexLog.ReInitNode(HexLog.GetLastNoInit(), True);
if FAutoScroll then
begin
HexLog.ScrollIntoView(HexLog.GetLast, False, False);
end;
end;
Finally
HexLog.EndUpdate;
End;
end;
I would try to force the item measurement manually by removing the vsHeightMeasured
from node's states with subsequent calling of the MeasureItemHeight
method. It will trigger the OnMeasureItem
again. The problem is the again here, because you shouldn't measure the item more than once the text of the node is changed, but still have to handle the OnMeasureItem
because of that scrolling stuff.
So as you mentioned in you comment you may include your own NodeMeasured
flag into your data structure and reset it when the text of the node will change (when some data in your log item are changed) and set it after you pass the OnGetText
event with the forced node height measurement. Here is a pseudocode:
procedure TForm1.VirtualStringTreeGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
begin
ThreadList.LockList;
try
// check if the own flag which indicates that the text is new, that
// the data has changed since the last time you were here in OnGetText
// is False and if so, force the node measurement to set current node
// height and set this flag to True to remember we already did this
if not ThreadList.Items[Node.Index].NodeMeasured then
begin
// fake the node measurement, remove the measured flag
Exclude(Node.States, vsHeightMeasured);
// this will trigger the OnMeasureItem again because of removed
// vsHeightMeasured flag from the node's state
VirtualStringTree.MeasureItemHeight(VirtualStringTree.Canvas, Node);
// set the NodeMeasured flag to remember we've measured the item
ThreadList.Items[Node.Index].NodeMeasured := True;
end;
// here set the node's text and unlock your thread safe list
CellText := ThreadList[Node.Index].SomeText;
finally
ThreadList.UnlockList;
end;
end;
And in your thread when the data gets changed, you have to set this NodeMeasured
flag to False.
if LogHasChanged then
begin
ThreadList.LockList;
try
ThreadList.Items[X].NodeMeasured := False;
ThreadList.Items[X].SomeText := 'Something new';
finally
ThreadList.UnlockList;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With