delphi - 集合编辑器未针对 TPersistent 属性中的 TCollection 属性打开

标签 delphi delphi-2010 tpersistent

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

但我想将集合属性移动到组件内的 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;

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

Da visualizationz

最佳答案

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

您的集合现在是 TPersistent 属性的成员,而不是组件的直接成员,对于构造函数来说没有区别。

<小时/>

更新

不同之处在于所有权,但在 TPersistent 级别,应该通过 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.

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

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

  • 集合的所有者被声明为 TComponent,它应该是 TPersistent,
  • GetOwner 未针对 TPersistent 属性类实现,并且
  • 教程末尾显示的修复,指出 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 - 集合编辑器未针对 TPersistent 属性中的 TCollection 属性打开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6980401/

相关文章:

multithreading - 在Delphi 中实现C# 的BackgroundWorker 的最佳方法是什么?

delphi - 将数据写入I/O地址

delphi - 如何解决 Delphi 2010 应用程序中未处理的 win32 异常?

delphi - 运行时设计 - 存储和加载表单布局(递归?)

delphi - 编写 C++ Builder/Delphi 组件并将二进制属性保存到 DFM 文件

javascript - 使用 JavaScript 解析 Datasnap 结果

arrays - 在数组中查找圆的算法

delphi - 如何正确使用 TValue.AsType<TNotifyEvent>?

delphi - 在 Delphi 中将 UTF8 转换为 ANSI (ISO-8859-1)

delphi - 从流中读取对象时忽略未知属性