从自定义类派生的组件属性

Posted

技术标签:

【中文标题】从自定义类派生的组件属性【英文标题】:Component property derived from a custom class 【发布时间】:2013-05-01 07:29:58 【问题描述】:

我创建了自己的类,我想在我的新组件中使用它,但是我收到了一个错误... 代码如下:

type
  TMyClass = class
    Name: string;
    Number: double;
  end;

  TMyComponent = class(TCustomPanel)
  private
    FMyClass: TMyClass;
  public
    procedure SetMyClass(aName: string; aNumber: double);
  published
    property MyClass: TMyClass write SetMyClass;
  end;

procedure SetMyClass(aName: string; aNumber: double);
begin
  FMyClass.Name:= aName;
  FMyClass.Number:= aNumber;
end;

该属性的类型似乎不兼容,我不知道为什么。

有没有人对此有所了解,我该如何解决这个问题。 将 FName 和 FNumber 作为 TMyComponent 中的字段不是一种选择,我的代码更复杂,这是一个解释我的目标的简单示例。

谢谢

【问题讨论】:

【参考方案1】:

目前我认为您的代码有问题的地方是:

    属性设置器必须接收与属性相同类型的单个参数,即TMyClass。 属性设置器必须是该类的成员,但您已将其实现为独立过程。 已发布的属性需要有一个 getter。

所以代码会变成:

type
  TMyClass = class
    Name: string;
    Number: double;
  end;

  TMyComponent = class(TCustomPanel)
  private
    FMyClass: TMyClass;
    procedure SetMyClass(Value: TMyClass);
  published
    property MyClass: TMyClass read FMyClass write SetMyClass;
  end;

procedure TMyComponent.SetMyClass(Value: TMyClass);
begin
  FMyClass.Name:= Value.Name;
  FMyClass.Number:= Value.Number;
end;

此代码不会实例化FMyClass。我猜想实例化FMyClass 的代码是为了这个问题而被删除的较大组件代码的一部分。但显然你确实需要实例化FMyClass

实例化FMyClass 的替代方法是将TMyClass 转换为记录。这是否适合您的需求我无法确定。


您在实例化此对象时似乎遇到了一些问题。这样做:

type
  TMyClass = class
    Name: string;
    Number: double;
  end;

  TMyComponent = class(TCustomPanel)
  private
    FMyClass: TMyClass;
    procedure SetMyClass(Value: TMyClass);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property MyClass: TMyClass read FMyClass write SetMyClass;
  end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited;
  FMyClass:= TMyClass.Create;
end;

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

procedure TMyComponent.SetMyClass(Value: TMyClass);
begin
  FMyClass.Name:= Value.Name;
  FMyClass.Number:= Value.Number;
end;

最后的评论。将MyClass 用于对象是一个坏名字。使用类作为类型,使用对象作为实例。所以,你的属性应该是MyObject,成员字段应该是FMyObject等等。

【讨论】:

感谢您提供的信息,我现在知道我的错误在哪里了。但是我仍然遇到问题,我现在可以编译和安装它,但是当我将组件放在表单上时,我得到一个“地址 00000000 的访问冲突。读取地址 00000000”。并且组件不会出现在表单上。你知道原因吗? 请记住,您没有向我们展示您的代码。您只显示了代码的精简版本。在您的带领下,我的答案中的代码仍然被删减。请注意我对FMyClass 未实例化这一事实的讨论。我们只能评论您向我们展示的代码。你有没有实例化过FMyClass 我在这里发布了一个我自己的代码示例,在这个简单的示例中我也遇到了同样的错误 你的代码必须调用继承;作为构造函数的第一行。 不要忘记 TMyClass 也必须从 TPersistent 派生,以便 DFM 可流式传输,因为它被声明为 published【参考方案2】:

试试这个:

type
  TMyClass = class
    Name: string;
    Number: double;
  end;

  TMyComponent = class(TCustomPanel)
  private
    FMyClass: TMyClass;
  public
    procedure SetMyClass(Value: TMyClass);
  published
    property MyClass: TMyClass write SetMyClass;
  end;

procedure TMyComponent.SetMyClass(Value);
begin
  FMyClass := Value;
end;

【讨论】:

我相信Felipe 的代码是不完整的,我猜想什么不存在。此外不存在 GET 功能,因此不存在风险读取。 您已经接受了这一点,但这不太可能是您的答案。你会在左右和中间泄漏物体。我试图说服大卫讨论这个问题,但到目前为止他还没有答应。奇怪的是,您在问题中的代码将 MyClass 视为一个值,但您接受了一个没有解释就将语义更改为 reference 的答案。【参考方案3】:
unit MyComponentTest2;

interface

uses SysUtils, Classes, Controls, Forms, ExtCtrls, Messages, Dialogs;

type
  TMyClass = class
    Name: string;
    Number: double;
  end;

  TMyComponentTest2 = class(TCustomPanel)
  private
    FMyClass: TMyClass;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure SetMyClass(Value: TMyClass);
  published
    property MyClass: TMyClass read FMyClass write SetMyClass;
  end;

procedure Register;

implementation

constructor TMyComponentTest2.Create(AOwner: TComponent);
begin
  Inherited Create(AOwner);
  FMyClass:= TMyClass.Create;
end;

destructor TMyComponentTest2.Destroy;
begin
  Inherited;
  FMyClass.Free;
end;

procedure TMyComponentTest2.SetMyClass(Value: TMyClass);
begin
  FMyClass.Name:= Value.Name;
  FMyClass.Number:= Value.Number;
end;

procedure Register;
begin
  RegisterComponents('MyComponents', [TMyComponentTest2]);
end;

end.

【讨论】:

这是什么意思?这正是我已经说过的。而且你仍然泄漏,因为没有析构函数。您在构造函数和析构函数方面需要帮助吗? 另一个问题是你错过了对继承构造函数的调用 你说我应该实例化 FMyClass,所以它就在那里: FMyClass:= TMyClass.Create;如果不是这个我不知道如何正确实例化这个类 那一点没问题。但是 create 中缺少的析构函数和继承的缺少仍然在伤害你。 是的,我已经更正了,我忘记了,因为我写了这段代码给你看,但即使仍然存在内存泄漏......

以上是关于从自定义类派生的组件属性的主要内容,如果未能解决你的问题,请参考以下文章

设计时属性的值,不会出现在运行时

如何从自定义 UIView 类调用函数?

如何从自定义类中检索 NSArray

从自定义类管理 NSURLSession 的完成处理程序

Symfony 4,从自定义类(不是控制器类)获取项目的根路径

如何从自定义类创建和取消唯一的 UILocalNotification?