Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 使用tpagecontrol时的所有权原则_Delphi_Generics - Fatal编程技术网

Delphi 使用tpagecontrol时的所有权原则

Delphi 使用tpagecontrol时的所有权原则,delphi,generics,Delphi,Generics,两天前,我对此给出了一个公认的答案(这是最困扰我的): 我已经尽我所能分析了这段代码,这些是我的结果 第1行:我创建了一个ttabsheet,其中pagecontrol1作为父级/所有者(基于下面的构造函数) 然后,我在变量Newtabsheet中存储了对它的引用(此回复基于@David Heffernan对我的一个问题的回答) 第2行:我使用引用将pagecontrol1分配给属性.pagecontrol 这是设置方法的代码: procedure TTabSheet.SetPageContro

两天前,我对此给出了一个公认的答案(这是最困扰我的):

我已经尽我所能分析了这段代码,这些是我的结果

第1行:我创建了一个
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;