TPersistent属性中的TCollection属性不会打开集合编辑器 [英] Collection editor does not open for a TCollection property in a TPersistent property
问题描述
我有我的自定义集合属性,当它是我的组件的直接成员时,这是非常有用的。
但是我想将集合属性移动到在我的组件中保持一致。现在遇到问题,它不起作用:双击对象检查器中的集合属性通常打开集合编辑器,但不再是。
拳头所有 - 我应该怎么传递给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屋!