TVirtualStringTree'nin Kök Düğümünün Üst Öğesi

Sep 18 2020

Belgelere göre, TVirtualStringTree'nin RootNode özelliği, kullanıcı tarafından oluşturulan tüm düğümlerin ebeveyni olan gizli bir düğümdür. Ancak Kök Düğümün Üst Öğesi ayarlanmıştır. Şu problemle karşı karşıyayım:

Bazen içinde TVirtualStringTree bulunan bir formu kapatırken erişim ihlali hatası alıyorum. Hata ayıklama, bileşen bileşeninin Name özelliğine (virtualstringtree) erişmek için tryng olduğunda hata oluşur. Name özelliğini değerlendirmeye çalışırsam, "Erişilemez değer" alıyorum. Sorunu derinlemesine inceleyerek, bir bileşenin Name özelliğinin çalışma zamanında değiştirilemeyeceğini öğrendim :

Uyarı: Çalışma zamanında Ad'ın değiştirilmesi, eski ada yapılan tüm başvuruların tanımsız kalmasına neden olur. Eski adı kullanan sonraki herhangi bir kod bir istisnaya neden olacaktır.

Bunu kodumda değiştirmediğim için mutluyum. Name özelliğinde bir veri kesme noktası kullanarak, bunun bir virtualstringtree döngüsünde değiştiğini gördüm, bunun gibi bir şey (sorunu test etmek için örnek bir uygulamada kullandığım örnek kod, ancak üretim kodu benzer):

var
  N: PNode;
  P: PVirtualNode;
begin
  P := tree.FocusedNode;
  while Assigned(P) do
  begin
    N := tree.GetNodeData(P);
    P := P.Parent;
  end;

GetNodeData aşağıdaki gibidir:

 if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then
    Result := nil
  else begin
    Result := PByte(@Node.Data) + FTotalInternalDataSize;
    Include(Node.States, vsOnFreeNodeCallRequired); // We now need to call OnFreeNode, see bug #323
  end;

Aşağıdaki ağaca sahip olduğum için:

Node 1
  Node 2
    Node 3

Düğüm 3 seçildiğinde, döngü 5 kez yürütülür. Oluşturduğum düğümlerde 3, ardından Kök Düğüm (gizli) ve ardından kökün Üst Öğesi. Yalnızca ana kök düğümün Üst öğesi sıfırdır. GetNodeData yönteminde kök düğüm olup olmadığı doğrulanır, nil döndürür. Ancak, kökün bu ebeveyni için, kök olmadığı için else kodunu girer. Şuan burada bir problem yaşıyoruz:

Virtualstrintree'nin Name özelliğinin adresi 141B9768 $ 'dır.

Kök düğümün ebeveyninin Durumlar özelliğinin adresi $ 141B976A'dır.

Veri kesme noktasını Name özelliğine koyarken, şu noktada değiştirilir:

Include(Node.States, vsOnFreeNodeCallRequired);

ve AV'nin oluşturulması.

Kök düğümü doğru bir şekilde kontrol etmek için döngüyü değiştirebileceğimi biliyorum , ancak bunu anlamak istiyorum, bu yüzden belki kodum yerine bileşeni (bir bileşen hatasıysa) düzeltebilirim.

Kod:

type
  TNode = record
    Text: string;
  end;
  PNode = ^TNode;
...
procedure TForm1.FormCreate(Sender: TObject);
var
  N1, N2, N3: TNode;
  TreeNode: PVirtualNode;
begin
  N1.Text := 'Node 1';
  TreeNode := tree.AddChild(nil, PNode(N1));

  N2.Text := 'Node 2';
  TreeNode := tree.AddChild(TreeNode, PNode(N2));

  N3.Text := 'Node 3';
  TreeNode := tree.AddChild(TreeNode, PNode(N3));
end;

Sadece forma bir ağaç ve bir düğme koyun, düğmeyi tıklayarak döngüyü koyarım.

Yanıtlar

2 TomBrunberg Sep 18 2020 at 14:19

İlk olarak, dokümantasyon: (örneğin) https://documentation.help/VirtualTreeview/TBaseVirtualTree_RootNode.html

diyor (vurgu benim)

özellik RootNode: PVirtualNode;

Açıklama

Ağaç hiyerarşisini sabitlemek için, çoğunlukla diğer herhangi bir ağaç düğümü gibi olan, ancak bazen farklı şekilde ele alınan bir iç ağaç düğümü tutulur. Kök düğüm her zaman genişletilir ve başlatılır. Üst üyesi, düğümün ait olduğu ağaç görünümüne işaret eder ve PreviousSibling ve NextSibling üyeleri, bu düğümü gerçekten tanımayı mümkün kılmak için kök düğümün kendisine işaret eder .

Notlar

Ağaçta yineleme yapmak için kök düğümü kullanmamalısınız. Yalnızca herkes tarafından erişilebilir çünkü tüm üst düzey düğümlerin ebeveynidir ve bir düğümü en üst düzey düğüm olup olmadığını test etmek için kullanılabilir.

İkincisi

Kodunuzda

var
  N: PNode;
  P: PVirtualNode;
begin
  P := tree.FocusedNode;
  while Assigned(P) do
  begin
    N := tree.GetNodeData(P);
    P := P.Parent;
  end;

iç kök düğümü koşulsuz olarak yukarı doğru ilerliyorsunuz çünkü Pkarşılaştırarak tree.RootNode(veya karşılaştırarak P.NextSibling) dahili kök olup olmadığınızı kontrol etmiyorsunuz .

Belki değiştirerek

while Assigned(P) do

şartı

while P <> tree.RootNode do

sana uyar

1 RodrigoCaetano Sep 18 2020 at 19:57

Yani, Tom'un cevabı ve bileşenin dokümantasyonu sayesinde, RootNode'un ebeveyni aslında ağacın kendisidir. İle döngü yaparken Yani, Parent = nilebeveynin kök (ağacı) eriştiklerinde durağı noktası olarak, kod Includeiçinde GetNodeDatabenim durumumda, idam edilir ve erişirken, Statemülkiyet, kendi adres treee İsim adresine çok yakındı , çünkü "düğüm" adresi ağaçtı.

Yani, kontrol etmek için döngü düzeltmek Node <> Tree.RootNodeve aynı zamanda düzeltmek GetNodeDataDüğüm Öz ise de kontrol etmek: or (Node = Pointer(Self), (2 milyondan fazla kod eski) sadece durum diğer kodunda benim uygulamada aynı yanlış döngü kullanır :

Önce:

function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer;
begin
  Assert(FNodeDataSize > 0, 'NodeDataSize not initialized.');
  if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then
    Result := nil
  else begin
    Result := PByte(@Node.Data) + FTotalInternalDataSize;
    Include(Node.States, vsOnFreeNodeCallRequired); // We now need to call OnFreeNode, see bug #323
  end;
end;

Sonra:

function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer;
begin
  Assert(FNodeDataSize > 0, 'NodeDataSize not initialized.');
  if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) or (Node = Pointer(Self)) then
    Result := nil
  else begin
    Result := PByte(@Node.Data) + FTotalInternalDataSize;
    Include(Node.States, vsOnFreeNodeCallRequired); // We now need to call OnFreeNode, see bug #323
  end;
end;