我有一个调用某种形式的函数的线程来更新这个表单。任务完成后,使用Synchronize
形成带有结果的线程更新,并且在程序运行时一切正常。
问题发生在线程运行时我关闭程序我遇到了访问冲突。它是由已经发布的线程更新表单引起的。重新排列表单创建顺序(调用Application->CreateForm
)后,它工作正常,因为现在保存线程代码的表单是在更新的表单之前创建的。似乎破坏的顺序与创建顺序相反。
我还在表单析构函数中添加了一些代码,以确保在使用线程代码在表单之前销毁表单时终止线程。因此,在表单析构函数中重新排列表单创建顺序和/或代码可以解决问题。
但我有3个问题:
创建表单的销毁顺序是什么?是否与我现在假设的创建顺序相反?
是否有更好的方法来完成上述任务 - 在线程完成处理数据后更新表单GUI项目。现在我使用Synchronize
从线程本身做到这一点,但有线程经验的人可能有更好的想法。我的另一个想法是甚至删除由编译器生成的一堆CreateForm
并手动创建它们,只使用CreateForm
创建主表单以更好地控制销毁顺序(正如Rob Kennedy所建议的那样 - {{ 3}})。
典型应用程序中动态表单创建/销毁的成本是多少?使用表单隐藏并保留在内存中或在关闭时将其销毁是否更好?
答案 0 :(得分:3)
使用Owner
创建组件时,Owner
会将您的组件添加到其拥有的组件列表中。这种情况发生在这段代码中:
procedure TComponent.Insert(AComponent: TComponent);
begin
if FComponents = nil then FComponents := TList<TComponent>.Create;
FComponents.Add(AComponent);
if FSortedComponents <> nil then
AddSortedComponent(AComponent);
AComponent.FOwner := Self;
end;
如您所见,该组件已添加到列表的末尾。
当所有者被销毁时,它会调用DestroyComponents
:
procedure TComponent.DestroyComponents;
var
Instance: TComponent;
begin
FreeAndNil(FSortedComponents);
while FComponents <> nil do
begin
Instance := FComponents.Last;
if (csFreeNotification in Instance.FComponentState)
or (FComponentState * [csDesigning, csInline] = [csDesigning, csInline]) then
RemoveComponent(Instance)
else
Remove(Instance);
Instance.Destroy;
end;
end;
如您所见,循环首先处理最后一个成员。因此,组件以相反的顺序销毁。
我个人不会依赖销毁令。如果表单需要确保在销毁表单之前终止线程,我会在表单的析构函数中编写代码来强制执行该操作。
使用Synchronize
是解决许多问题的完美方案。无论是否是解决问题的最佳方案,我都不可能说,因为您还没有完全描述您的问题。
典型应用程序中动态表单创建/销毁的成本是多少?
不是很好。通常,表单是响应于用户交互而示出的。程序可以比用户处理表单更快地创建表单。因此,动态创建表单很少是个问题。如果你想创建并销毁数以千计的表单,这可能是一个问题。但那会很奇怪。