TVirtualStringTree: data changed between the OnMeasureItem event and the OnGetText event

I have an array whose data will be presented on TVirtualStringTree. This array is thread safe and blockable. And grew up with another thread.

My problem is that when the VST fires the OnMeasureItem event to measure the height of the node, the data used for the measurement can change when it comes to the print point of the data with the OnGetText event.

I checked the order of the events and this is not good for my design. First, it fires the OnMeasureItem event for all nodes that are not initialized, then it starts to raise OnGetText events. I mean, suppose we have 3 nodes, events will be fired in the following 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 block:

 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 keep the data received between OnMeasureItem and OnGetText events synchronized?

I do not want to block my array in all OnMeasureItem () and OnGetText () events.

Thanks.

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; 
+6
source share
1 answer

I would try to force the item to be manually measured by removing the vsHeightMeasured states from the node and then calling the MeasureItemHeight method. It will launch OnMeasureItem again. The problem is here again, because you do not have to measure the element more than once, the text of the node changes, but you still have to handle OnMeasureItem because of this scroll.

So, as you mentioned in your comment, you can include your own NodeMeasured flag in your data structure and reset when the node text changes (when some data in the log element changes) and set it after you pass the OnGetText event with a forced node height measurement. Here is the pseudo code:

 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 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 text and unlock your thread safe list CellText := ThreadList[Node.Index].SomeText; finally ThreadList.UnlockList; end; end; 

And in your stream, when the data is changed, you should 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; 
+5
source

Source: https://habr.com/ru/post/913230/


All Articles