【问题标题】:delphi component with a collection of TPictures带有 TPictures 集合的 delphi 组件
【发布时间】:2016-11-25 05:12:00
【问题描述】:

我正在尝试创建一个像 TImage 这样的 VCL 组件,它可以让我添加可变数量的不同大小的 TPictures。 目标是能够通过属性列表中的 VCL 编辑器分配该数量的 TPictures。

delphi component property: TObjectList<TPicture> 在这里我们得出结论,应该使用带有 TCollectionItems 的 TCollection。这就是我现在正在尝试做的事情,但是在我结束编译器错误之前很多次:“发布的属性'图片'不能是类型数组”在这一行中: property Pictures[Index: Integer]: TPic read GetPic write SetPic;

unit ImageMultiStates;

interface

uses
  Vcl.Graphics, Vcl.StdCtrls, System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Forms, Generics.Collections;

type

  TPic = class(TCollectionItem)
  private
    FPicture: TPicture;
  public
    procedure Assign(Source: TPersistent); override;
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property Picture: TPicture read FPicture write FPicture;
  end;

  TPictures = class(TCollection)
  private
    function GetPic(Index: Integer): TPic;
    procedure SetPic(Index: Integer; APicture: TPic);
  public
    constructor Create;
  published
    property Pictures[Index: Integer]: TPic read GetPic write SetPic;
  end;

  TImageMultiStates = class(TImage)
  private
    FPictures: TPictures;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Activate(Index: Integer);
  end;

procedure Register;

implementation

constructor TPic.Create(Collection: TCollection);
begin
  inherited Create(Collection);
end;

destructor TPic.Destroy;
begin
  FPicture.Free;
  inherited Destroy;
end;

procedure TPic.Assign(Source: TPersistent);
begin
  FPicture.Assign(Source);
end;


constructor TPictures.Create;
begin
  inherited Create(TPic);
end;

procedure TPictures.SetPic(Index: Integer; APicture: TPic);
begin
  Items[Index].Assign(APicture);
end;

function TPictures.GetPic(Index: Integer): TPic;
begin
  Result := TPic(inherited Items[Index]);
end;


constructor TImageMultiStates.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TImageMultiStates.Destroy;
begin
  FPictures.Free;
  inherited Destroy;
end;

procedure TImageMultiStates.Activate(Index: Integer);
begin
  Picture.Assign(FPictures.Items[Index]);
end;

procedure Register;
begin
  RegisterComponents('Standard', [TImageMultiStates]);
end;

end.

由于似乎没有人期望会引发此错误,因此可能与我安装的组件有关?我使用内部的 GetIt Package-Manager 安装 Jedi Code Library 2.8、Jedi Visual Component Library 和 PNGComponents 1.0。就 TImage 相关的组件而言,我想这就是它。也许其中之一用时髦的东西覆盖了我的一些 TImage 内容......

【问题讨论】:

  • 如果您想在设计时使用Object Inspector 分配多个图像,就像编辑任何其他属性一样,那么恐怕您将无法执行此操作。好吧,不能直接使用Object Inspector。您需要做的是创建自己的自定义属性编辑器。我建议检查TImageList 组件的源代码,以便更好地了解它是如何完成的。
  • 距离我上次使用它已经有一段时间了,但是 IIRC,TCollection 不是这样工作的。看看状态栏如何管理其面板或列表视图如何管理其列标题。 AFAIK,两者都使用 TCollection 的后代。
  • 这里有一个很好的解释:atug.com/andypatterns/collections.htm#TCollectionMerits。 Tcollection 最好的部分是它在对象检查器中工作得很好,并且有一个属性编辑器可以让你添加项目。
  • TPic 的构造函数中忘记初始化 FPicture。

标签: delphi vcl


【解决方案1】:

我做了一些实验,并从TPanel 导出了一个TPicturePanel。它有一个Pictures 属性,它是TPictures,是TOwnedCollection 的后代,并且包含TPics。每个TPic 都有一个Picture 属性。我可以安装这个组件,它允许我使用所谓的集合编辑器来编辑Pictures 集合,它允许您添加或删除TPic 实例。如果您在收藏编辑器中选择TPic,则可以将图片分配给其Picture 属性,即从文件加载等。

这是TPicturePanel 的工作代码。您可以在此之后为您的组件建模:

unit PicturePanels;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.Graphics;

type
  TPic = class(TCollectionItem)
  private
    FPicture: TPicture;
    procedure SetPicture(const Value: TPicture);
  public
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TCollection); override;
    destructor Destroy; override;
  published
    property Picture: TPicture read FPicture write SetPicture;
  end;

  TPictures = class(TOwnedCollection)
  private
    function GetItem(Index: Integer): TPic;
    procedure SetItem(Index: Integer; const Value: TPic);
  public
    constructor Create(AOwner: TPersistent);
    property Items[Index: Integer]: TPic read GetItem write SetItem;
  end;

  TPicturePanel = class(TPanel)
  private
    FPictures: TPictures;
    procedure SetPictures(const Value: TPictures);
  published
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Pictures: TPictures read FPictures write SetPictures;
  end;

procedure Register;

implementation

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

{ TPicturePanel }

constructor TPicturePanel.Create(AOwner: TComponent);
begin
  inherited;
  FPictures := TPictures.Create(Self);
end;

destructor TPicturePanel.Destroy;
begin
  FPictures.Free;
  inherited;
end;

procedure TPicturePanel.SetPictures(const Value: TPictures);
begin
  FPictures.Assign(Value);
end;

{ TPic }

procedure TPic.Assign(Source: TPersistent);
begin
  inherited;
  if Source is TPic then
    FPicture.Assign(TPic(Source).FPicture);
end;

constructor TPic.Create(AOwner: TCollection);
begin
  inherited;
  FPicture := TPicture.Create;
end;

destructor TPic.Destroy;
begin
  FPicture.Free;
  inherited;
end;

procedure TPic.SetPicture(const Value: TPicture);
begin
  FPicture.Assign(Value);
end;

{ TPictures }

constructor TPictures.Create(AOwner: TPersistent);
begin
  inherited Create(AOwner, TPic);
end;

function TPictures.GetItem(Index: Integer): TPic;
begin
  Result := inherited GetItem(Index) as TPic;
end;

procedure TPictures.SetItem(Index: Integer; const Value: TPic);
begin
  inherited SetItem(Index, Value);
end;

end.

【讨论】:

  • 我复制了准确​​的代码;我开始使用 CollectionEditor,这很棒。除了它会在打开编辑器和分配图片时引发错误“TPic 无法分配给 TPic”,但重要的是我可以关注一个实际将我带入 Collection 编辑器的工作示例。非常感谢!
  • 哈!根据您的代码,我也为我的组件启动了编辑器。与 TPic 无法分配给 TPic 的错误相同
  • 问题是TPic.Assign:如果你先继承它,当你尝试FPicture.Assign(TPic(Source).FPicture);所以像“开始,如果源是 TPic 然后 FPicture := TPic(Source).FPicture 否则继承;结束;”做这项工作
  • 我修改了上面的代码,但是我发布的原始代码在西雅图运行得很好,我没有收到错误。
【解决方案2】:

您的索引属性使用的语法看起来像是返回一个数组,但它并没有这样做。 pictures 属性返回索引的TPic。它一次只能返回一个TPic

如果你想返回一个数组,你必须这样说:

function GetPictures: TArray<TPicture>;
procedure SetPictures(const value: TArray<TPicture>);
property Pictures: TArray<TPicture> read GetPictures write SetPictures;  

//GetPictures might look something like this:
function TMyClass.GetPictures: TArray<TPicture>;
var
  i: integer;
begin
  SetLength(Result, Self.FPictureCount);
  for i:= 0 to FPictureCount - 1 do begin
    Result[i]:= GetMyPicture[i];
  end;
end;

我不确定您的 TPic 集合是如何工作的,因此您必须对其进行调整以满足您的需求。
显然,如果您愿意,您可以拥有一个TArray&lt;TArray&lt;TPicture&gt;&gt;(又名:array of array of TPicture)。

【讨论】:

  • 我发现 kadner-online.de/delphi/collection.htmlstackoverflow.com/questions/1050724/… 似乎都成功地使用了这种语法,而没有涉及任何数组
  • 在这两种情况下,Array properties 也称为Indexed properties 仅被声明为公开而不是发布。 Object Inspector 无法与已发布的Array properties 一起工作的原因是,为了让Object Inspector 操作它们,您需要能够同时输入两个参数(项目索引和项目值)。或者换句话说,您需要在Object Inspector 中为此类属性提供两个编辑字段。
猜你喜欢
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
相关资源
最近更新 更多