Запись данных в PVirtualNode без установки каждого значения поля вручную - PullRequest
2 голосов
/ 05 августа 2011

Допустим, у меня есть запись данных этого узла:

Type
  PPerson = ^TPerson;
  TPerson = record
   Name: String;
   Age: Integer;
   SomeBool: Boolean;
  end;

Чтобы заполнить мое VirtualStringTree, я бы сделал это:

Procedure AddToTree(Person: TPerson);
Var
 Node: PVirtualNode;
 Data: PPerson;
Begin
 Node := VT.AddChild(nil);
 Data := VT.GetNodeData(Node);
 Data.Name := Person.Name;
 Data.Age  := Person.Age;
 Data.SomeBool := Person.SomeBool;
End;

Procedure TMyForm.MyButtonClick(Sender: TObject);
Var
 Person: TPerson;
Begin
 Person.Name := 'Jeff';
 Person.Age := 16;
 Person.SomeBool := False;
 AddToTree(Person);

End:

Теперь, хотя это прекрасно работает, я хотел бы упростить его, поэтому всякий раз, когда я добавляю новые записи в запись, мне не нужно изменять метод AddToTree.

Итак, я попробовал это:

Procedure AddToTree(Person: TPerson);
Begin
 VT.AddChild(nil,@Person);
End;

Это компилирует, , но кажется, что PVirtualNode не получил данные, потому что мой VT ничего не отображает, и при разрыве в событии OnGetText я вижу, что переменные пусты.

Что я делаю не так? :)

Ответы [ 4 ]

5 голосов
/ 06 августа 2011

Записи поддерживают оператор присваивания:

procedure AddToTree(const Person: TPerson);
var
  Node: PVirtualNode;
  Data: PPerson;
begin
  Node := VT.AddChild(nil);
  Data := VT.GetNodeData(Node);
  Data^ := Person;
end;
3 голосов
/ 25 сентября 2012

Лучший способ хранения данных в VTV при использовании записей в качестве держателей данных - хранить только указатели на записи, тогда как сами записи хранятся отдельно в списке / массиве. Это также соответствует виртуальной парадигме MVC, когда визуальный компонент фактически не владеет данными. Итак, схема добавления записи:

  • Выделите память для записи (!), Используя AllocMem, New, ...
  • Заполните его поля
  • Добавить его в список / массив
  • Добавить новый узел в VTV с NodeData = PNewRecord

и схема удаления записи:

  • Удалить соответствующий узел из VTV
  • Завершение записи с помощью Finalize (!), Что позволяет избежать утечек памяти при подсчитанные поля
  • Утилизировать выделенную память с помощью FreeMem, Dispose, ...
  • Удалить элемент из списка / массива
3 голосов
/ 05 августа 2011

Вы не читаете инструкцию:)

ОК, в данном случае источником является руководство - цитата из источника AddChild():

UserData может использоваться для установки первых 4 байтов области пользовательских данных в начальное значение, которое можно использовать в OnInitNode, а также будет вызывать событие OnFreeNode (если <> nil), даже если узел еще не "официально" инициализирован.

Я хочу, чтобы он не использовался так, как вы его ожидаете / ожидаете, что он будет работать.

Кстати, почему вы копируете данные? Почему бы не иметь

type
  PTreeData = ^TTreeData;
  TTreeData = record
   Data: PPerson;
  end;

и распределять записи с помощью New(), сохранять их в дереве и затем Dispose(), когда дерево очищается?

0 голосов
/ 05 августа 2011

Еще один «я нашел ответ через 2 минуты после того, как задал вопрос» - насколько унизительно ...: (

В любом случае, так что - это можно сделать с помощью CopyMemory, например так:

Procedure AddToTree(Person: TPerson);
Var
 Data: PPerson;
 Node: PVirtualNode;
Begin
 // add node
 Node := VT.AddChild(nil);
 // Get data of the node
 Data := VT.GetNodeData(Node);
 // Copy the Person stuff to the Node's data.
 CopyMemory(Data,@Person,SizeOf(Person));
End;
...