При работе с компонентом TVirtualStringTree в Delphi вы можете столкнуться с ошибкой доступа к памяти, когда пытаетесь закрыть форму, содержащую это дерево. В этой статье мы рассмотрим причину этой ошибки и предложим решение.
Причина ошибки
Ошибка возникает из-за того, что родитель корневого узла TVirtualStringTree фактически является самим деревом. Это описано в документации к компоненту:
Корневой узел — это внутренний узел дерева, который служит для привязки иерархии дерева. Этот узел всегда развернут и инициализирован. Jego родительский член указывает на компонент TVirtualStringTree, к которому принадлежит узел, а его PreviousSibling и NextSibling указывают на сам корневой узел, чтобы сделать возможным распознавание этого узла.
При использовании цикла, который не проверяет, является ли текущий узел корневым, вы можете дойти до родителя корневого узла, который является самим деревом. При попытке получить данные этого узла в методе GetNodeData компонента происходит изменение недопустимого участка памяти, что и вызывает ошибку доступа к памяти.
Решение проблемы
Чтобы устранить эту ошибку, вам необходимо изменить цикл, чтобы он не шел за пределы корневого узла. Для этого проверьте, не равен ли текущий узел корневому узлу дерева:
Перед:
while Assigned(P) do
begin
N := tree.GetNodeData(P);
P := P.Parent;
end;
После:
while P <> tree.RootNode do
begin
N := tree.GetNodeData(P);
P := P.Parent;
end;
Кроме того, чтобы предотвратить возможные проблемы в будущем, вы можете изменить метод GetNodeData, чтобы он также проверял, не является ли узел самим деревом:
Перед:
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;
После:
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;
Эти изменения помогут вам избежать ошибки доступа к памяти при закрытии формы с TVirtualStringTree в будущем.
В статье описано решение проблемы с ошибкой доступа к памяти, возникающей при закрытии формы с TVirtualStringTree в Delphi из-за цикла, который пытается получить данные родителя корневого узла дерева.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.