【问题标题】: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 中的字段不是一种选择,我的代码更复杂,这是一个解释我的目标的简单示例。

谢谢

【问题讨论】:

    标签: delphi class components


    【解决方案1】:

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

    1. 属性设置器必须接收与属性相同类型的单个参数,即TMyClass
    2. 属性设置器必须是该类的成员,但您已将其实现为独立过程。
    3. 已发布的属性需要有一个 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 中缺少的析构函数和继承的缺少仍然在伤害你。
    • 是的,我已经更正了,我忘记了,因为我写了这段代码给你看,但即使仍然存在内存泄漏......
    猜你喜欢
    • 2012-06-02
    • 2021-09-02
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 2014-06-11
    相关资源
    最近更新 更多