2012-04-15 11 views
6

配列を保持しているデータがTVirtualStringTreeに表示されます。この配列はスレッドセーフでロック可能です。別のスレッドで成長しました。TVirtualStringTree:OnMeasureItemイベントとOnGetTextイベントの間でデータが変更されました

私の問題は、ノードの高さを測定するために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

質問に追加。 –

+0

あなたが 'toVariableNodeHeight'を使用しているのを忘れてしまったので、最後のコメントを削除しました。ちょうど追加(多分無関係)の質問。 VirtualTreeViewのどのバージョンを使用していますか? – TLama

+0

最新だと思います。私はSVNからチェックアウトしました。 // Version 5.0.0 –

答えて

5

私はMeasureItemHeightメソッドのその後の呼び出しで、ノードの状態からvsHeightMeasuredを除去することにより、手動で項目の測定を強制しようとするだろう。再度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; 

そして、あなたのスレッド内のデータが変更された場合、あなたはFalseにこのNodeMeasuredフラグを設定する必要があります。ここでは擬似コードです。

if LogHasChanged then 
begin 
    ThreadList.LockList; 
    try 
    ThreadList.Items[X].NodeMeasured := False; 
    ThreadList.Items[X].SomeText := 'Something new'; 
    finally 
    ThreadList.UnlockList; 
    end; 
end; 
+0

「Exclude(Node.States、vsHeightMeasured)」とすれば十分です。 MeasureItemHeight()を呼び出す必要はありません。 vsHeightMeasuredを削除した後に私の問題が消えたようです。 –

+0

ノード状態から 'vsHeightMeasured'フラグだけを削除すると、' OnMeasureItem'を起動して現在のノードの高さを設定する必要があります。これは、ツリーが描画されるたびに発生しますが、ノードのデータ(テキスト)が 'OnMeasureItem'と' OnGetText'の間で変更される可能性があるので、スレッドリストが100にロックされているときに手動で起動する必要がありますあなたが表示する同じテキストの高さを測定していることを確認してください。 – TLama