Вопрос: Как назначить данные узлу в VirtualStringTree в Delphi и почему появляется ошибка компиляции "Требуется указатель"?
Описание проблемы:
При попытке назначить данные узлу в VirtualStringTree в событии InitNode возникает ошибка компиляции "Требуется указатель". Нужно назначить указатель на запись объекта в свойство Node.Data контрола дерева, но не получается сделать это правильно.
Пример кода:
type
TDiagData = record
DiagID: Integer;
DiagName: String;
Selected: Byte;
end;
PDiagData = ^TDiagData;
var
FDiagDataList: TObjectList;
c: Integer; // используется как итератор для списка // инкрементируется в vst1InitNode
procedure Btn1Click;
var
DiagData : PDiagData;
begin
try
FDiagDataList := TObjectList.Create; // TODO: Перенести это в конструктор формы
for c := 1 to 10 do
begin
New(DiagData);
DiagData.DiagID := c;
DiagData.DiagName := Format('Диагноз #%d', [c]);
FDiagDataList.Add(DiagData);
end;
c := 0;
vst1.NodeDataSize := SizeOf(TDiagData);
vst1.RootNodeCount := 10; // тест
finally
// FDiagDataList.Free; // TODO: Перенести это в деструктор формы
end
end;
procedure vst1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
var
DiagData: PDiagData;
begin
DiagData := TDiagData(FDiagDataList.Items[c]); // FDiagDataList - это TObjectList
Node.Data^ := DiagData; // <-- это не работает ...
// Ошибка: Требуется указатель.
Inc(c);
end;
Решение проблемы:
Не читать или записывать Node.Data напрямую. Данные, которые вам нужны, не обязательно будут находиться точно по адресу этого поля. Контрол дерева имеет механизм, позволяющий потомкам резервировать дополнительное пространство для данных. Вместо этого вызовите Sender.GetNodeData.
var
NodeData: PDiagData;
begin
NodeData := Sender.GetNodeData(Node);
NodeData^ := TDiagData(FDiagDataList.Items[c]);
end;
Ваш код не работает, потому что Node.Data имеет тип record, и вы не можете разыменовать его с помощью ^. В простом случае значение, возвращаемое GetNodeData, будет равно адресу этого поля (т.е. GetNodeData(Node) = @Node.Data). Но не предполагайте, что все случаи простые. Потомки дерева контрола могут резервировать пространство данных сами, и вам придется делить это пространство с кодом, который находится вне вашего контроля, а управление этим пространством данных возлагается на контрол дерева. Всегда вызывайте GetNodeData.
Кроме того, вы запутались с типами данных. Вы saying, что FDiagDataList - это TObjectList, но вы явно храните в нем нечто, что не является потомком TObject. Когда вы не используете объекты, не используйте TObjectList. Если вы используете версию Delphi earlier than 2009, используйте TList и храните указатели на TDiagData:
NodeData^ := PDiagData(FDiagDataList[c])^;
Если вы используете Delphi 2009 или более позднюю версию, используйте TList<TDiagData>, и затем избавьтесь от типа casts:
NodeData^ := FDiagDataList[c];
В любом случае, вы, вероятно, обнаружите, что управление будет проще, если каждый обработчик событий начнется одинаково, с вызова GetNodeData, чтобы извлечь типобезопасный указатель на данные текущего узла.
Вопрос о решении ошибки компиляции при назначении данных узлу в VirtualStringTree в Delphi и почему появляется ошибка 'Требуется указатель'.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.