TPersistent属性中的TCollection属性不会打开集合编辑器 [英] Collection editor does not open for a TCollection property in a TPersistent property

查看:109
本文介绍了TPersistent属性中的TCollection属性不会打开集合编辑器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我的自定义集合属性,当它是我的组件的直接成员时,这是非常有用的。



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



拳头所有 - 我应该怎么传递给TPersistent属性的引用?

  TMyCollection = class(TCollection)
构造函数创建(AOwner:TComponent); // TMyCollection constuctor
...

我不能通过自我,所以我应该通过我的永久主人?

 构造函数TMyPersistent.Create(AOwner:TComponent); 
开始
继承创建;
fOwner:= AOwner;
fMyCollection:= TMyCollection.Create(AOwner); //嗯...没有意义
结束;

我想我错过了一些东西。如果需要更多的代码,请发表评论。



解决方案

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



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






更新



什么是不同的是所有权,但是在TPersistent级别,应该由正确的 GetOwner : p>


GetOwner返回对象的所有者。 GetOwner由GetNamePath方法用于查找持久对象的所有者。 GetersPath和GetOwner在TPersistent中引入,所以后缀如Collection可以出现在Object Inspector中。


你必须告诉IDE你的TCollection属性由TPersistent属性拥有,而该属性又由组件所有。



您正在使用的教程有关于此实现的几个错误:




  • 该集合的所有者被声明为TComponent,它应该是TPersistent,

  • 对于TPersistent属性类,GetOwner不被实现,而

  • 本教程末尾显示的修复表示TPersistent属性应该继承自TComponent,这是明文错误的;或者更好地说:相对于不实现GetOwner的解决方法。



这是它应该如下所示:

  unit MyComponent; 

接口

使用
类,SysUtils;

type
TMyCollectionItem = class(TCollectionItem)
private
FStringProp:String;
protected
function GetDisplayName:String;覆盖
public
procedure Assign(Source:TPersistent);覆盖
发布
属性StringProp:String读取FStringProp写入FStringProp;
结束

TMyCollection = class(TCollection)
private
FOwner:TPersistent;
函数GetItem(Index:Integer):TMyCollectionItem;
procedure SetItem(Index:Integer; Value:TMyCollectionItem);
protected
函数GetOwner:TPersistent;覆盖
public
构造函数创建(AOwner:TPersistent);
function Add:TMyCollectionItem;
函数Insert(Index:Integer):TMyCollectionItem;
属性项目[索引:整数]:TMyCollectionItem读取GetItem
写入SetItem;
结束

TMyPersistent = class(TPersistent)
private
FOwner:TPersistent;
FCollectionProp:TMyCollection;
procedure SetCollectionProp(Value:TMyCollection);
protected
函数GetOwner:TPersistent;覆盖
public
procedure Assign(Source:TPersistent);覆盖
构造函数Create(AOwner:TPersistent);
析构函数覆盖
发布
属性CollectionProp:TMyCollection读取FCollectionProp
写入SetCollectionProp;
结束

TMyComponent = class(TComponent)
private
FPersistentProp:TMyPersistent;
procedure SetPersistentProp(Value:TMyPersistent);
public
构造函数Create(AOwner:TComponent);覆盖
析构函数覆盖
发布
属性PersistentProp:TMyPersistent读取FPersistentProp
写入SetPersistentProp;
结束

程序注册;

执行

程序注册;
begin
RegisterComponents('Samples',[TMyComponent]);
结束

{TMyCollectionItem}

程序TMyCollectionItem.Assign(来源:TPersistent);
begin
如果Source是TMyCollectionItem然后
FStringProp:= TMyCollectionItem(Source).FStringProp
else
inherited Assign(Source);
结束

函数TMyCollectionItem.GetDisplayName:String;
begin
结果:= Format('Item%d',[Index]);
结束

{TMyCollection}

函数TMyCollection.Add:TMyCollectionItem;
begin
结果:= TMyCollectionItem(继承添加);
结束

构造函数TMyCollection.Create(AOwner:TPersistent);
begin
继承Create(TMyCollectionItem);
FOwner:= AOwner;
结束

函数TMyCollection.GetItem(Index:Integer):TMyCollectionItem;
begin
结果:= TMyCollectionItem(继承的GetItem(Index));
结束

函数TMyCollection.GetOwner:TPersistent;
begin
结果:= FOwner;
结束

函数TMyCollection.Insert(Index:Integer):TMyCollectionItem;
begin
结果:= TMyCollectionItem(继承的Insert(Index));
结束

procedure TMyCollection.SetItem(Index:Integer; Value:TMyCollectionItem);
begin
继承了SetItem(Index,Value);
结束

{TMyPersistent}

过程TMyPersistent.Assign(Source:TPersistent);
begin
如果Source是TMyPersistent,然后
CollectionProp:= TMyPersistent(Source).FCollectionProp
else
inherited Assign(Source);
结束

构造函数TMyPersistent.Create(AOwner:TPersistent);
开始
继承创建;
FOwner:= AOwner;
FCollectionProp:= TMyCollection.Create(Self);
结束

析构函数TMyPersistent.Destroy;
begin
FCollectionProp.Free;
继承了Destroy;
结束

函数TMyPersistent.GetOwner:TPersistent;
begin
结果:= FOwner;
结束

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

{TMyComponent}

构造函数TMyComponent.Create(AOwner:TComponent);
begin
继承Create(AOwner);
FPersistentProp:= TMyPersistent.Create(Self);
结束

析构函数TMyComponent.Destroy;
begin
FPersistentProp.Free;
继承了Destroy;
结束

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

结束。

但是我可以说你也可以从 TOwnedCollection ,这使得TMyCollection的使用和声明更简单: / p>

  TMyCollection = class(TOwnedCollection)
private
函数GetItem(Index:Integer):TMyCollectionItem;
procedure SetItem(Index:Integer; Value:TMyCollectionItem);
public
function Add:TMyCollectionItem;
函数Insert(Index:Integer):TMyCollectionItem;
属性项目[索引:整数]:TMyCollectionItem读取GetItem
写入SetItem;
结束


I've got my custom collection property which is working great when it is a direct member of my component.

But I want to move the collection property to a TPersistent propery within my component. And now comes the problem, it doesn't work: double clicking on the collection property in the object inspector normally opens the collection editor, but it does not anymore.

Fist of all - what should I pass to the contructor of the TPersistent property?

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

I can't pass Self, so should I pass my persistent owner?

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

I think I'm missing something. If more code is needed just please comment this post.

解决方案

A TCollection's constructor does not need a TComponent, but a TCollectionItemClass.

Your collection now being a member of a TPersistent property instead of being a direct member of the component makes no difference for the constructor.


Update

What dóes differ is the ownership, but then at the TPersistent level, which should be managed by a correct implementation of GetOwner:

GetOwner returns the owner of an object. GetOwner is used by the GetNamePath method to find the owner of a persistent object. GetNamePath and GetOwner are introduced in TPersistent so descendants such as collections can appear in the Object Inspector.

You have to tell the IDE that your TCollection property is owned by the TPersistent property, which in turn is owned by the component.

The tutorial you are using has several errors regarding this implementation:

  • The owner of the collection is declared as TComponent, which should be TPersistent,
  • GetOwner is not implemented for the TPersistent property class, and
  • The fix shown at the end of the tutorial, stating that the TPersistent property should inherit from TComponent instead, is plain wrong; or more nicely said: is rather a workaround for not implementing GetOwner.

This is how it should look like:

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.

But may I say that you can also inherit from TOwnedCollection, which makes the use and the declaration of TMyCollection much simpler:

  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;

这篇关于TPersistent属性中的TCollection属性不会打开集合编辑器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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