【问题标题】:Collection editor does not open for a TCollection property in a TPersistent property集合编辑器不会为 TPersistent 属性中的 TCollection 属性打开
【发布时间】:2011-08-08 09:55:46
【问题描述】:

我有我的自定义集合属性,当它是我的组件的直接成员时效果很好。

但我想将集合属性移动到组件中的 TPersistent 属性。现在问题来了,它不起作用:在对象检查器中双击集合属性通常会打开集合编辑器,但它不再起作用了。

首先 - 我应该将什么传递给 TPersistent 属性的构造函数?

TMyCollection = class(TCollection)
  constructor Create(AOwner: TComponent); // TMyCollection constuctor
  ...

我不能通过 Self,所以我应该通过我的持久所有者吗?

constructor TMyPersistent.Create(AOwner: TComponent);
begin
  inherited Create;
  fOwner := AOwner;
  fMyCollection := TMyCollection.Create(AOwner); // hmmm... doesn't make sense
end;

我想我错过了一些东西。如果需要更多代码,请评论这篇文章。

【问题讨论】:

  • TCollection 的构造函数不需要所有者,但需要 TCollectionItemClass。
  • 嗯,但是当我从组件调用它时它运行良好。所以我假设我的 TCollection 和 TCollectionItem 是好的。
  • @NGLN 这是问题的答案。你为什么不这样写。如果你不写答案,那么 JustMe 不能接受!
  • “它不起作用”太模糊而没有意义。究竟会发生什么?它会崩溃吗?如果是,会出现什么错误消息,或者它是否无法编译,如果是,会出现什么错误消息?
  • @Rudy 单击 TCollection 进行编辑后没有任何反应。调试后它是一个 AV

标签: delphi delphi-2010 tpersistent


【解决方案1】:

TCollection 的构造函数不需要 TComponent,而是 TCollectionItemClass。

您的集合现在是 TPersistent 属性的成员,而不是组件的直接成员,这对构造函数没有任何影响。


更新

不同之处在于所有权,但在 TPersistent 级别,应该由GetOwner 的正确实现来管理:

GetOwner 返回对象的所有者。 GetNamePath 方法使用 GetOwner 来查找持久对象的所有者。 TPersistent 中引入了 GetNamePath 和 GetOwner,因此集合之类的后代可以出现在 Object Inspector 中。

您必须告诉 IDE 您的 TCollection 属性归 TPersistent 属性所有,而后者又归组件所有。

The tutorial you are using 有几个关于这个实现的错误:

  • 集合的所有者声明为TComponent,应该是TPersistent,
  • 没有为 TPersistent 属性类实现 GetOwner,并且
  • 教程末尾显示的 fix 声明 TPersistent 属性应该从 TComponent 继承,这是完全错误的;或者更好地说:是不实施 GetOwner 的一种解决方法。

它应该是这样的:

unit MyComponent;

interface

uses
  Classes, SysUtils;

type
  TMyCollectionItem = class(TCollectionItem)
  private
    FStringProp: String;
  protected
    function GetDisplayName: String; override;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property StringProp: String read FStringProp write FStringProp;
  end;

  TMyCollection = class(TCollection)
  private
    FOwner: TPersistent;
    function GetItem(Index: Integer): TMyCollectionItem;
    procedure SetItem(Index: Integer; Value: TMyCollectionItem);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TPersistent);
    function Add: TMyCollectionItem;
    function Insert(Index: Integer): TMyCollectionItem;
    property Items[Index: Integer]: TMyCollectionItem read GetItem
      write SetItem;
  end;

  TMyPersistent = class(TPersistent)
  private
    FOwner: TPersistent;
    FCollectionProp: TMyCollection;
    procedure SetCollectionProp(Value: TMyCollection);
  protected
    function GetOwner: TPersistent; override;
  public
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TPersistent);
    destructor Destroy; override;
  published
    property CollectionProp: TMyCollection read FCollectionProp
      write SetCollectionProp;
  end;

  TMyComponent = class(TComponent)
  private
    FPersistentProp: TMyPersistent;
    procedure SetPersistentProp(Value: TMyPersistent);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property PersistentProp: TMyPersistent read FPersistentProp
      write SetPersistentProp;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TMyComponent]);
end;

{ TMyCollectionItem }

procedure TMyCollectionItem.Assign(Source: TPersistent);
begin
  if Source is TMyCollectionItem then
    FStringProp := TMyCollectionItem(Source).FStringProp
  else
    inherited Assign(Source);
end;

function TMyCollectionItem.GetDisplayName: String;
begin
  Result := Format('Item %d',[Index]);
end;

{ TMyCollection }

function TMyCollection.Add: TMyCollectionItem;
begin
  Result := TMyCollectionItem(inherited Add);
end;

constructor TMyCollection.Create(AOwner: TPersistent);
begin
  inherited Create(TMyCollectionItem);
  FOwner := AOwner;
end;

function TMyCollection.GetItem(Index: Integer): TMyCollectionItem;
begin
  Result := TMyCollectionItem(inherited GetItem(Index));
end;

function TMyCollection.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TMyCollection.Insert(Index: Integer): TMyCollectionItem;
begin
  Result := TMyCollectionItem(inherited Insert(Index));
end;

procedure TMyCollection.SetItem(Index: Integer; Value: TMyCollectionItem);
begin
  inherited SetItem(Index, Value);
end;

{ TMyPersistent }

procedure TMyPersistent.Assign(Source: TPersistent);
begin
  if Source is TMyPersistent then
    CollectionProp := TMyPersistent(Source).FCollectionProp
  else
    inherited Assign(Source);
end;

constructor TMyPersistent.Create(AOwner: TPersistent);
begin
  inherited Create;
  FOwner := AOwner;
  FCollectionProp := TMyCollection.Create(Self);
end;

destructor TMyPersistent.Destroy;
begin
  FCollectionProp.Free;
  inherited Destroy;
end;

function TMyPersistent.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TMyPersistent.SetCollectionProp(Value: TMyCollection);
begin
  FCollectionProp.Assign(Value);
end;

{ TMyComponent }

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FPersistentProp := TMyPersistent.Create(Self);
end;

destructor TMyComponent.Destroy;
begin
  FPersistentProp.Free;
  inherited Destroy;
end;

procedure TMyComponent.SetPersistentProp(Value: TMyPersistent);
begin
  FPersistentProp.Assign(Value);
end;

end.

但我可以说你也可以从TOwnedCollection继承,这使得TMyCollection的使用和声明更加简单:

  TMyCollection = class(TOwnedCollection)
  private
    function GetItem(Index: Integer): TMyCollectionItem;
    procedure SetItem(Index: Integer; Value: TMyCollectionItem);
  public
    function Add: TMyCollectionItem;
    function Insert(Index: Integer): TMyCollectionItem;
    property Items[Index: Integer]: TMyCollectionItem read GetItem
      write SetItem;
  end;

【讨论】:

  • 我在delphi.about.com/library/bluc/text/uc083101e.htm 中所做的完全一样,但是编译后的那些示例也不起作用。
  • Page 4 of that tutorial 声明了一个自己的 TOurCollection 类型,它确实有一个带有 Owner 参数的构造函数,但请注意该构造函数中的 inherited Create(TOurCollectionItem);。
  • 是的,我也是这样做的,但是问题肯定出在其他地方,因为当Collection在TPersistent类中时,点击编辑后这个例子没有弹出集合编辑器。 “ExpandingComponent.pas”
  • TMyPersistent.Assign 中有一个错误。而不是直接分配给 FCollectionProp(从而替换实际对象),您应该只使用 FCollectionProp.Assign(Source)。
  • @Larsdk 好话!修复了它,现在它被委托给了 setter。
猜你喜欢
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 2012-11-29
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多