Forum > Packages and Libraries

[Resolved] VirtualTreeView and a dynamic Array: what's wrong with this code?

(1/1)

Nimral:
Hi,

I have have some troubles with the VirtualTreeView component, and need advise from more experienced users.

Using the following definitions.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type  PPayload = ^TPayload;  TPayload = record    ID:Integer;    Name: string[50];  end;  TArrPayload = array of TPayload;
the attached test project is supposed to do the following:

- Create a dynamic array of records and populate it with some test data
- Store a pointer to each rec in a VirtualStringTree


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.FormCreate(Sender: TObject); const  NumItems = 10; var  i: integer;  rec: TPayload; begin  VirtualStringTree1.NodeDataSize := SizeOf(PPayload);  // populate the array  ArrPayload := TArrPayload.Create;  for i := 1 to NumItems do  begin    rec.ID := i;    rec.Name := Format('Node %d', [i]);    Insert(rec,ArrPayload,MaxInt);  // append tail  end;  // initalize the nodes  for rec in ArrPayload do     VirtualStringTree1.AddChild(nil,@rec);end;
- In VirtualStringTree.GetText: retrieve the record, and display the test data


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;  var CellText: String); var  p:PPayload; begin  assert(assigned(Node),'VirtualStringTree1GetText: Node not assigned');  p := Sender.GetNodeData(Node);  CellText := p^.Name;end;
Problems with the enclosed demo code:

The number of nodes displayed is OK, but the node captions are all garbage.
The project crashes on exit, obviously memory corruption. Seems to be caused by FreeAndNil of the dynamic array.

This seems to work, but why? Coincidence?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.FormDestroy(Sender: TObject); begin  // FreeAndNil(ArrPayload);  ArrPayload := Nil;end;  
I can't find any obvious error in hours, who can help me out?

Thnx, Armin

P.S. I think I solved the memory corruption problem: though the syntax of dynamic arrays does somewhat mimic object syntax, dynamic arrays are not descendants of TObject, and so using FreeAndNil with a dynamic arry is not valid. Correct? But why, then, doesn't FreeAndNil complain that it hasn't been passed an object reference?

In fact, FreeAndNil seems not to care about anything, because this code compiles, and does also crash on exit:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.FormDestroy(Sender: TObject); var  x:integer; begin  ArrPayload := nil;  FreeAndNil(x);end;  

Nimral:
Finally I found it.

GetNodeData returns a pointer to the data, not the data itself. To get at the actual data, which in this case happens to be another pointer, I need to dereference what comes back from GetNodeData and cast the result to a pointer to the actual data.

This code sequence works:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;  var CellText: string); var  p: PPayload; begin  assert(assigned(Node), 'VirtualStringTree1GetText: Node not assigned');  p := PPayload(Sender.GetNodeData(Node)^);  CellText := p^.Name;end;
Furthermore, I analysed the pointers passed, and, to my great astonishment, I found that there is a difference between "for variable in array" and "for i := low(array) to high(array)" ... array[ i ]:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  // initalize the nodes  // for rec in ArrPayload do  //   VirtualStringTree1.AddChild(nil, @rec);   for i := low(ArrPayload) to high(ArrPayload) do  begin    p := @ArrPayload[i];    VirtualStringTree1.AddChild(nil, p);  end;
The upper code (commented out) will always pass the same address (like if rec was a separate variable and not an address following the Array records). Huh?

I'll open a separate question about this strange behaviour of for ...

Thanks to all who already looked into my post and tried to help,

Armin.

Navigation

[0] Message Index

Go to full version