7

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;
4

1 に答える 1

6

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;
于 2012-04-15T10:16:09.757 に答える