两天前,我给出了question的接受答案(最让我困扰的是):
newtabsheet:=ttabsheet.Create(PageControl1);
NewTabSheet.PageControl := PageControl1;
newtabsheet.Caption:='tab1';
i1:=tabs.Count;
tabs.Add(newtabsheet);
我已尽力分析此代码,这些是我的结果。
第1行:我创建了一个ttabsheet
,pagecontrol1
作为父/所有者(基于下面的构造函数)。
constructor TTabSheet.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Align := alClient;
ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible,
csParentBackground, csPannable];
Visible := False;
FTabVisible := True;
FHighlighted := False;
end;
然后我在变量Newtabsheet
中存储了对它的引用(这个转换基于@David Heffernan给出one我的问题的答案。)
第2行:我使用该引用将pagecontrol1
分配给了属性.pagecontrol
。
这是设置方法的代码:
procedure TTabSheet.SetPageControl(APageControl: TPageControl);
begin
if FPageControl <> APageControl then
begin
if FPageControl <> nil then
FPageControl.RemovePage(Self);
Parent := APageControl;
if APageControl <> nil then
APageControl.InsertPage(Self);
end;
end;
基于此我认为(可能是错误的)它是将现有父项与新传递的参数进行比较,如果存在不同的话,那么parent<>nil
将从前一个{{1}中删除此newtabsheet
(视觉效果)并将其分配给新的父/所有者,然后如果新的pagecontrol
将其插入新的parent<>nil
(视觉效果)。
所以这条线是不必要的(也许是错误的),因为我已经在第一行中做到了。
第3行:我使用引用将pagecontrol
的标题指定为&#39; tab1&#39;。
第5行:我使用add方法存储对标签列表tabsheet
中tabsheet
的引用。
这是事情开始在我脑海中浮现的地方。
我认为父母/所有者是tabs:TList<ttabsheet>;
,但tabs
仍然显示标签(根据此question的已接受答案,更改父级会直观地移除pagecontrol1
1}}来自tabsheet
),但它没有。
现在这可能是错误的,但如果它只是一个参考,那么为什么当我通过pagecontrol1
从tabsheet
删除pagecontrol1
PageControl1.ActivePage.free
时tabs.count
保持不变。
如果我从标签中删除tabsheet
,则tabsheet
上的pagecontrol1
不会被删除(直观删除)。
从此question我了解到仿制品成为了父母/所有者,您无需担心从tabsheet
释放pagecontrol1
,因为制表符是父级,您只需要将其从tabs
中解放出来。
我的问题:此代码中发生了什么以及我为什么会遇到这种行为?
当我在页面控件中删除ttabsheet时,为什么当我尝试在列表中使用对它的引用时,为什么它没有引发错误,它是两个不同的对象。
答案 0 :(得分:3)
Owner
负责内存管理。将TPageControl
指定为Owner
的{{1}}表示TTabSheet
会在TPageControl
被销毁时销毁TTabSheet
。 TPageControl
和ownee包含彼此的指针,因此他们可以相互通知与内存管理相关的重要事件。
Owner
负责窗口管理和视觉演示。将Parent
指定为TPageControl
的{{1}}表示Parent
窗口是TTabSheet
窗口的子窗口,并将显示在TTabSheet
窗口的客户区域内。 TPageControl
和子项包含彼此的指针,以便他们可以相互通知与窗口管理相关的重要事件。
TPageControl
和Parent
两个不同的东西。他们可以是同一个对象,但他们不必(例如 - 在设计时创建的组件始终归Owner
所有,{{1} },或正在设计的Parent
,但可以是容器组件的子代,如TForm
等。
TFrame
负责没有。它只是一个任意值的动态数组,在这种情况下恰好是TDataModule
个指针。而已。 TPanel
和TList
之间没有所有者/家长关系。
当TTabSheet
被销毁时,它本身与其TList
之间存在关系链接。 TTabSheet
从TTabSheet
的管理层中删除了自己。它已不再归TPageControl
所有,并且不再是TTabSheet
的子级。这两个对象清除了彼此的指针。
TPageControl
和TPageControl
之间没有关系链接。 TPageControl
没有TTabSheet
甚至存在的概念。当TList
添加到TTabSheet
并从TList
中删除时,TTabSheet
只是添加/删除指向 TList
对象的指针。 TList
未通知TTabSheet
有关插入/移除的信息。并且没有从TList
到TTabSheet
的指针,因此当TTabSheet
被销毁时,没有适当的机制允许指向TList
的指针已从TTabSheet
中移除。指针保留在列表中,您可以继续使用指针(用于比较等),只要您不取消引用它以访问被破坏的TTabSheet
。
如果您想要在TList
被销毁时自动从TTabSheet
删除TTabSheet
指针,则需要拨打TList
&#39; s {{ 1}}方法。然后,您的TTabSheet
回调可以从TTabSheet
移除FreeNotification()
指针以响应Notification()
通知,例如:
TTabSheet
如果您希望TList
从opRemove
移除TMyForm = class(TForm)
...
private
tabs: TList<TTabSheet>;
...
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override; // <-- ADD THIS
...
end;
...
procedure TMyForm.DoSomething;
var
NewTabSheet: TTabSheet;
...
begin
...
NewTabSheet := TTabSheet.Create(PageControl1);
NewTabSheet.PageControl := PageControl1;
NewTabSheet.Caption := 'tab1';
tabs.Add(NewTabSheet);
NewTabSheet.FreeNotification(Self); // <-- ADD THIS
...
end;
procedure TMyForm.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent is TTabSheet) then
tabs.Remove(TTabSheet(AComponent)); // <-- HERE
end;
时,会自动从TTabSheet
移除指针,请切换为TPageControl
。默认情况下,其TList
属性为true,因此当使用TObjectList
或OwnsObjects
方法从列表中删除指针时,它将销毁TTabSheet
。 Remove()
方法不会销毁Delete()
,因此请在Extract()
回调中使用TTabSheet
代替Remove()
,例如:
Notification()