我有一个数组保存数据将在TVirtualStringTree上表示。该阵列是线程安全且可锁定的。并由另一个线程增长。
我的问题是,当VST执行OnMeasureItem事件以测量节点的高度时,用于测量的数据在使用OnGetText事件打印数据时可能会发生变化。
我检查了事件的执行顺序,这对我的设计不利。首先它为未初始化的所有节点触发OnMeasureItem事件,然后它开始调用OnGetText事件。 我的意思是,假设我们有3个节点,事件将按此顺序触发:
OnMeasureItem for node 1
OnMeasureItem for node 2
OnMeasureItem for node 3
OnGetText for node 1
OnGetText for node 2
OnGetText for node 3
但我需要这样的东西才能锁定:
OnMeasureItem for node 1
OnGetText for node 1
OnMeasureItem for node 2
OnGetText for node 2
OnMeasureItem for node 3
OnGetText for node 3
维护OnMeasureItem和OnGetText事件之间获得的数据同步的最佳方法是什么?
我不想在所有OnMeasureItem()和OnGetText()事件中锁定我的数组。
谢谢。
添加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;
答案 0 :(得分:5)
我会尝试手动强制项目测量,方法是从节点的状态中删除vsHeightMeasured
,然后调用MeasureItemHeight
方法。它会再次触发OnMeasureItem
。问题是再次,因为你不应该多次测量项目的节点文本被更改,但由于滚动的东西,仍然必须处理OnMeasureItem
。
正如您在评论中提到的那样,您可以在数据结构中包含自己的NodeMeasured
标志,并在节点文本发生变化时(日志项中的某些数据发生更改时)重置它并进行设置使用强制节点高度测量传递OnGetText
事件后。这是一个伪代码:
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;
在您的线程中,当数据发生变化时,您必须将此NodeMeasured
标志设置为False。
if LogHasChanged then
begin
ThreadList.LockList;
try
ThreadList.Items[X].NodeMeasured := False;
ThreadList.Items[X].SomeText := 'Something new';
finally
ThreadList.UnlockList;
end;
end;