TVirtualStringTree:OnMeasureItem事件和OnGetText事件之间的数据发生了变化

Meh*_*ide 6 delphi virtualtreeview tvirtualstringtree

我有一个数组保存数据将在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
Run Code Online (Sandbox Code Playgroud)

但是我需要这样的东西才能锁定:

OnMeasureItem for node 1
OnGetText for node 1

OnMeasureItem for node 2
OnGetText for node 2

OnMeasureItem for node 3
OnGetText for node 3
Run Code Online (Sandbox Code Playgroud)

保持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;
Run Code Online (Sandbox Code Playgroud)

TLa*_*ama 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;
Run Code Online (Sandbox Code Playgroud)

在您的线程中,当数据发生更改时,您必须将此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;
Run Code Online (Sandbox Code Playgroud)