Delphi 使用tpagecontrol时的所有权原则
两天前,我对此给出了一个公认的答案(这是最困扰我的): 我已经尽我所能分析了这段代码,这些是我的结果 第1行:我创建了一个Delphi 使用tpagecontrol时的所有权原则,delphi,generics,Delphi,Generics,两天前,我对此给出了一个公认的答案(这是最困扰我的): 我已经尽我所能分析了这段代码,这些是我的结果 第1行:我创建了一个ttabsheet,其中pagecontrol1作为父级/所有者(基于下面的构造函数) 然后,我在变量Newtabsheet中存储了对它的引用(此回复基于@David Heffernan对我的一个问题的回答) 第2行:我使用引用将pagecontrol1分配给属性.pagecontrol 这是设置方法的代码: procedure TTabSheet.SetPageContro
ttabsheet
,其中pagecontrol1
作为父级/所有者(基于下面的构造函数)
然后,我在变量Newtabsheet
中存储了对它的引用(此回复基于@David Heffernan对我的一个问题的回答)
第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;
程序TTabSheet.SetPageControl(APageControl:TPageControl);
开始
如果FPageControl APageControl,则
开始
如果FPageControl为零,则
FPageControl.RemovePage(Self);
父项:=APageControl;
如果APageControl为零,则
APageControl.InsertPage(Self);
结束;
结束;
基于此,我认为(可能是错误的)它将现有父级与新传递的参数进行比较,如果存在不同的参数,那么如果parentnil
从以前的pagecontrol
(视觉效果)中删除此newtabsheet
,并将其分配给新的父级/所有者,然后,如果新的parentnil
将其插入新的pagecontrol
(视觉效果)
因此,这一行是不必要的(可能是错误的),因为我已经在第一行中这样做了
第3行:我使用引用将选项卡页的标题指定为“tab1”
第5行:我使用add方法存储对选项卡列表tabs:TList中的tabsheet
的引用代码>泛型
这就是事情开始从我头上飞过的地方
我认为父/所有者是tabs
,但是pagecontrol1
仍然显示该选项卡(根据对此更改的公认答案,父/所有者从pagecontrol1
中直观地删除tabsheet
),但它没有
现在这可能是错误的,但是如果它只是一个参考,那么为什么当我通过执行pagecontrol1.ActivePage.free
从pagecontrol1
删除tabs.count
时,tabs.count保持不变
如果我从选项卡中删除tabsheet
,则pagecontrol1
上的tabsheet
不会被删除(以可视方式删除)
从这一点上,我了解到泛型成为父类/所有者,您不必担心从pagecontrol1
中释放tabsheet
,因为tabs是父类,您只需将其从tabs
中释放即可
我的问题:这段代码中发生了什么,我为什么要面对这种行为
澄清
驱动问题的是,当我在pagecontrol中删除ttabsheet时,当我尝试使用列表中对它的引用时,为什么它没有引发错误?它们是两个不同的对象。所有者负责内存管理。将TPageControl
指定为TPageControl
的所有者,意味着TPageControl
将在TPageControl
被销毁时销毁TPageControl
。Owner
和ownee包含指向彼此的指针,因此它们可以相互通知与内存管理相关的重要事件
父级
负责窗口管理和可视化演示。将TPageControl
指定为TPageControl
的父项
,意味着TPageControl
窗口是TPageControl
窗口的子窗口,并将显示在TPageControl
窗口的客户端区域内。父项和子项包含指向彼此的指针,以便它们可以相互通知与窗口管理相关的重要事件
Owner
和Parent
是两个不同的东西。它们可以是相同的对象,但不一定是(以点为例-在设计时创建的组件总是由正在设计的TForm
、TFrame
或TDataModule
所拥有,但可以是容器组件的子组件,如TPanel
,等等)
TList
不负责任何事情。它只是一个任意值的动态数组,在本例中正好是TTabSheet
指针。没别的了。t列表
和t表
之间根本没有所有者/父关系
当TTabSheet
被销毁时,它本身与其TPageControl
之间存在关系链接。TTabSheet
从其TPageControl
的管理中删除自身。它不再属于TPageControl
,也不再是TPageControl
的子项。这两个对象清除彼此的指针
TTabSheet
和TList
之间根本没有关系链接。t表格
甚至不知道t列表
是否存在。当TTabSheet
添加到TList
并从中删除时,TList
只是添加/删除指向TTabSheet
对象的指针。t列表
不会通知t表
有关插入/删除的信息。而且从TTabSheet
到TList
没有指针,因此当TTabSheet
被销毁时,没有允许从TList
删除指向该TTabSheet
的指针的机制。指针保留在列表中,您可以继续使用指针(用于比较等),只要您这样做
constructor TTabSheet.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Align := alClient;
ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible,
csParentBackground, csPannable];
Visible := False;
FTabVisible := True;
FHighlighted := False;
end;
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;
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;
TMyForm = class(TForm)
...
private
tabs: TObjectList<TTabSheet>;
...
end;
...
procedure TMyForm.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent is TTabSheet) then
tabs.Extract(TTabSheet(AComponent)); // <-- HERE
end;