从自定义类派生的组件属性
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 中缺少的析构函数和继承的缺少仍然在伤害你。 是的,我已经更正了,我忘记了,因为我写了这段代码给你看,但即使仍然存在内存泄漏......以上是关于从自定义类派生的组件属性的主要内容,如果未能解决你的问题,请参考以下文章