使用tpagecontrol时的所有权原则 [英] Ownership principles when using tpagecontrol

查看:62
本文介绍了使用tpagecontrol时的所有权原则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

两天前,我对此问题(这是让我最困扰的地方):

Two days ago I gave an accepted answer for this question (that is what bothering me the most):

  newtabsheet:=ttabsheet.Create(PageControl1);
  NewTabSheet.PageControl := PageControl1;
  newtabsheet.Caption:='tab1';
  i1:=tabs.Count;
  tabs.Add(newtabsheet);

我已经尽力分析了这段代码,这就是我的结果.

I have analysed this code the best I can, and these are my results.

第1行:我创建了一个ttabsheet,其中pagecontrol1作为父级/所有者(基于下面的构造函数).

Line 1: I create a ttabsheet with pagecontrol1 as the parent/owner (based on the constructor below).

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给

Then I stored a reference to it in the variable Newtabsheet (this remarque is based on an answer @David Heffernan gave to one of my questions).

第2行:我使用引用将pagecontrol1分配给属性.pagecontrol.

Line 2: I used the reference to assign pagecontrol1 to the property .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从先前的pagecontrol中删除此newtabsheet(视觉影响)并将其分配给新的父级/所有者,然后将新的parent<>nil插入到新的pagecontrol(视觉效果)中.

Based on this I think (maybe wrong) it is comparing the existing parent to the new passed parameter, if there is a different then if the parent<>nil removes this newtabsheet from the previous pagecontrol (visual affects) and assign it to the new parent/owner, then if the new parent<>nil insert it in the new pagecontrol(visual affects).

所以这一行是不必要的(可能是错误的),因为我已经在第一行中做了.

So this line is unnecessary (maybe wrong), because I already did that in the first line.

第3行:我使用引用为tabsheet的标题分配了'tab1'.

Line 3: I use the reference to assign the caption of the tabsheet with 'tab1'.

第5行:我使用add方法将对tabsheet的引用存储在选项卡列表tabs:TList<ttabsheet>;通用中.

Line 5: I use the add method to store a reference to the tabsheet in the tabs list tabs:TList<ttabsheet>; a generic.

这是我头顶飞舞的地方.

Here is where things start to fly over my head.

我认为父母/所有者是tabs,但是pagecontrol1仍在显示选项卡(基于对此

I think that the parent/owner is tabs, but the pagecontrol1 is still showing the tab (based on the accepted answer to this question changing the parent visually removes the tabsheet from pagecontrol1), but it does not.

现在这可能是错误的,但是如果它只是一个参考,那为什么当我通过执行PageControl1.ActivePage.free tabs.countpagecontrol1中删除tabsheet时仍保持不变.

Now this could be wrong, but again if it is just a reference then why when I delete the tabsheet from pagecontrol1 by doing PageControl1.ActivePage.free the tabs.count remains constant.

如果我从选项卡中删除tabsheet,则pagecontrol1上的tabsheet不会被删除(以可视方式删除).

And if I delete the tabsheet from tabs then the tabsheet on the pagecontrol1 is not deleted (removed visually).

从此问题我知道,泛型成为了父级/所有者,您不必担心从pagecontrol1中释放tabsheet,因为制表符是父级,您只需要从tabs中释放它即可.

From this question I understood that generics becomes the parent/owner and that you do not need to worry about freeing tabsheet from pagecontrol1, because tabs is the parent and you only need to free it from tabs.

我的问题:这段代码中发生了什么以及为什么我会遇到这种情况?

My question: What is happening in this code and why I'm facing this behavior?

引起问题的是,当我删除pagecontrol中的ttabsheet时,为什么当我尝试使用列表中的ttabsheet是两个不同的对象时,它没有引发错误.

What is driving the question is when I delete the ttabsheet in the pagecontrol why it is not raising an error when I try to use the reference to it in the list are they two different objects.

推荐答案

Owner负责内存管理.将TPageControl分配为TTabSheetOwner意味着TPageControl将在TPageControl被销毁时销毁TTabSheet. Owner和所有者拥有彼此指向的指针,因此它们可以相互通知与内存管理有关的重要事件.

The Owner is responsible for memory management. Assigning the TPageControl as the Owner of the TTabSheet means the TPageControl will destroy the TTabSheet when the TPageControl is destroyed. The Owner and ownee contain pointers to each other so they can notify each other of important events related to memory management.

Parent负责窗口管理和视觉呈现.将TPageControl分配为TTabSheetParent表示TTabSheet的窗口是TPageControl窗口的子级,并将显示在TPageControl的客户区中窗户. Parent和child包含彼此的指针,因此它们可以相互通知与窗口管理相关的重要事件.

The Parent is responsible for window management and visual presentation. Assigning the TPageControl as the Parent of the TTabSheet means the TTabSheet's window is a child of the TPageControl's window, and will be displayed inside the client area of the TPageControl's window. The Parent and child contain pointers to each other so they can notify each other of important events related to window management.

OwnerParent两种不同的东西.它们可以是同一对象,但不必相同(例如-设计时创建的组件始终由TFormTFrameTDataModule拥有)正在设计中,但可以是容器组件(例如TPanel等)的子代.

The Owner and Parent are two different things. They can be the same object, but they don't have to be (case in point - components created at design-time are always owned by the TForm, TFrame, or TDataModule that is being designed, but can be children of container components, like TPanel, etc).

TList不承担任何责任.它只是一个任意值的动态数组,在这种情况下,它们恰好是TTabSheet指针.而已. TListTTabSheet之间根本没有所有者/父母关系.

The TList is responsible for nothing. It is just a dynamic array of arbitrary values, which in this case happen to be TTabSheet pointers. Nothing more. There is no Owner/Parent relationship between the TList and TTabSheet at all.

TTabSheet被销毁时,其自身与TPageControl之间存在关系链接. TTabSheet将从其TPageControl的管理中删除.它不再由TPageControl拥有,并且不再是TPageControl的子级.这两个对象彼此清除了指针.

When the TTabSheet is destroyed, there are relational links between itself and its TPageControl. The TTabSheet removes itself from its TPageControl's management. It is no longer owned by the TPageControl, and is no longer a child of the TPageControl. The two objects clear their pointers to each other.

TTabSheetTList之间根本没有关系链接. TTabSheet甚至不存在TList的概念.将TTabSheet添加到TList和从其中删除时,TList只是在添加指向TTabSheet对象的指针. TList不会将插入/移除通知TTabSheet.而且,没有从TTabSheetTList的指针,因此当TTabSheet被销毁时,没有适当的机制允许从TList删除指向该TTabSheet的指针.指针仍保留在列表中,只要不取消引用指针即可访问已破坏的TTabSheet.

There is no relational link between the TTabSheet and the TList at all. The TTabSheet has no concept that the TList even exists. When the TTabSheet is added to and removed from the TList, the TList is simply adding/removing a pointer to the TTabSheet object. The TList does not notify the TTabSheet about the insertion/removal. And there is no pointer from the TTabSheet to the TList, so when the TTabSheet is destroyed, there is no mechanism in place that allows the pointer to that TTabSheet to be removed from the TList. The pointer remains in the list, and you can continue using the pointer (for comparisons, etc) as long as you do not dereference it to access the destroyed TTabSheet.

如果要在TTabSheet被销毁时自动从TList中删除TTabSheet指针,则需要调用TTabSheetFreeNotification()方法.然后,您的Notification()回调可以从TList中删除TTabSheet指针,以响应opRemove通知,例如:

If you want to remove the TTabSheet pointer from the TList automatically when the TTabSheet is destroyed, you need to call the TTabSheet's FreeNotification() method. Your Notification() callback can then remove the TTabSheet pointer from the TList in response to opRemove notifications, eg:

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;

如果要在从TList中删除TTabSheet的指针时自动从TPageControl中删除TTabSheet,请切换到TObjectList.它的OwnsObjects属性默认情况下为true,因此当使用Remove()Delete()方法从列表中删除指针时,它将破坏TTabSheet. Extract()方法不会破坏TTabSheet,因此请在Notification()回调中使用它代替Remove(),例如:

If you want the TTabSheet to be removed from its TPageControl automatically when its pointer is removed from the TList, switch to TObjectList instead. Its OwnsObjects property is true by default, so it will destroy the TTabSheet when the pointer is removed from the list using the Remove() or Delete() method. The Extract() method will not destroy the TTabSheet, so use that instead of Remove() in your Notification() callback, eg:

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;

这篇关于使用tpagecontrol时的所有权原则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆