【问题标题】:Delphi component property class depending on the component's Owner classDelphi 组件属性类取决于组件的 Owner 类
【发布时间】:2015-02-23 01:09:40
【问题描述】:

我正在使用 RAD Studio XE5 构建我的应用程序。

我发现尝试在 TForm 上发布属性不是很实用。然后它必须注册并安装为一个包,那么它对于大量的开发是不切实际的。

因此,我决定创建一个非可视组件 (TFormPropertiesEditor),用于填充表单属性。一种标准化我的表格的方法。

组件将被放置在基本表单上,其他所有表单都继承该表单(我们称之为 TBaseForm)。因此,该组件只会在“基础”表单上删除一次,然后通过继承,其他所有表单也会拥有它。

创建的组件将检测其所有者的类(BaseForm 或其后代)并创建一个可通过“Properties”属性访问的对象,该对象的类将取决于所有者类。

这样,当检查 TBaseForm 上的组件时,我只能访问 TBaseFormProperties。检查 TSecondForm 上的组件时,我还可以访问 TSecondFormProperties。只是,该组件将足够智能以检测它应该将哪个 PropertyClass 公开为 Properties 属性。

组件将通过GetPropertiesClass检查表单,定义为:

function TBaseForm.GetPropertiesClass : TPropertiesClass;
begin
  Result := TBaseFormProperties;
end;

function TSecondForm.GetPropertiesClass : TPropertiesClass;
begin
  Result := TSecondFormProperties;
end;

每个表单都有一个对应的 TProperties 后代,如下所示:

TBaseForm ------------ TSecondForm ------------- ...
    |
TBaseFormProperties -- TSecondFormProperties --- ...

例如:

如果放置组件的 Form 是 TBaseForm,则 FProperties 将是 TBaseFormProperties。如果表单是 TSecondForm,则 FProperties 将是 TSecondFormProperties。自然地,TSecondFormProperties 将继承自 TBaseFormProperties。

不过,当我将组件放在表单上时,似乎无法检测到该组件是哪个类。

function TFormPropertiesEditor.GetPropertiesClass: TFormPropertiesClass;
begin
  Result :=  TBaseForm(Owner).GetPropertiesClass;  
end;

看起来是 TBaseForm(Owner) 部分导致了问题。解释器卡在 TBaseForm 上,不会考虑 Owner 是 TSecondForm 还是 TThirdForm 类型。

接口

所以,为了绕过 TBaseForm(Owner) 类型转换,我决定使用接口。因此,如果我使用声明 GetPropertiesClass 的接口:

IMasterForm = interface(IInterface)
  ['{B6122F34-65C4-4701-8A5E-50C8DABF5516}']
  function GetPropertiesClass : TFormPropertiesClass;
  end;


type
  TBaseForm = class(TForm, IMasterForm)
    MyFormPropertiesEditor1: TMyFormPropertiesEditor;
  private
    { Déclarations privées }
  public
    function GetPropertiesClass : UCommon.TFormPropertiesClass;
  end;     

以下内容:

function TFormPropertiesEditor.GetPropertiesClass : TFormPropertiesClass;
begin
  Result := (Owner as IMasterForm).GetPropertiesClass;
end;

导致不支持接口错误。

抽象祖先方法

然后,我决定添加一个额外的祖先层。我添加了一个类 TMasterForm,TBaseForm 继承自该类。此 TMasterForm 将 GetPropertiesClass 声明为抽象和虚拟:

TMasterForm = class(TForm, IMasterForm)
    public
      function GetPropertiesClass : TFormPropertiesClass; virtual; abstract;
  end;


type
  TBaseForm = class(TMasterForm)
  private
    { Déclarations privées }
  public
    function GetPropertiesClass : UCommon.TFormPropertiesClass; override;
  end;

但是,我得到了一个 AV,因为我认为 IDE 试图访问 TMasterClass.GetPropertiesClass,这当然没有实现。

如何实现这种类型转换?知道我该怎么做吗?

非常感谢您

下载示例项目 https://www.wetransfer.com/downloads/b524438609fc04257af803a8e3dd2eca20141225161239/764d108d335b9d296c3004dfea04a54620141225161240/9c8cc0

【问题讨论】:

  • 您没有在 IDE 中注册基本表单。因此,在设计时,您看到的表单不是TBaseForm 类型。你正在尝试的东西是行不通的。我认为你所有的工作都是徒劳的。回到绘图板。
  • 也许你需要RegisterCustomModule...
  • @DavidHeffernan 我不认为他会以错误的方式解决这个问题。某些组件的自定义属性编辑器是否使用类似的方法。
  • @Silver 我看不到 IDE 将如何实例化 TBaseForm 或任何派生类。它怎么知道这样做?
  • 关于你的编辑,你读过我的 cmets 吗? IDE 将如何执行您的代码?

标签: delphi vcl design-time


【解决方案1】:

这里的基本问题是 IDE 不会在设计时实例化您的表单。因此,无论您在表单类中放入什么代码,IDE 都不会执行它。这是因为您没有在 IDE 中注册表单。

如果您希望 IDE 了解您的表单,那么您需要在 IDE 中注册它们。到那时,你所有的代码都变得不必要了,因为你又回到了你试图避免的事情上。即向 IDE 注册表单。你陷入了第 22 条军规的境地。如果您需要 IDE 了解表单,则需要注册它们。此时,您也可以直接在 Object Inspector 中显示属性。

【讨论】:

    【解决方案2】:

    代码中的问题是您没有正确继承 GetPropertiesClass 方法。

    事实上,您并没有在整个类家族中继承它。

    在您的代码中,每个类类型都有自己的 GetPropertiesClass 方法版本,因此,由于您将 Owner 类型转换为 TBaseForm 类,因此即使 Owner 属于 TSecondForm 类,也会使用来自 TBaseForm 的方法。

    因此,您需要确保 TBaseForm 类中的 GetPropertiesClass 是虚拟的,并且 TSecondForm 中的方法 GetPropertiesClass 被覆盖。

    这将确保 TSecondForm.GetProperties 方法将被调用,即使当所有者是 TSeconfForm 类时,您将 Owner 类型转换为 TBaseClass。

    【讨论】:

    • 感谢您的回答。我确实这样做了。我什至添加了另一个类,TMasterForm = class(TForm),它具有 GetPropertiesClass 抽象和虚拟,TBaseForm 从中继承。 TBaseForm 的 GetPropertiesClass 被声明为覆盖。尽管如此,当我将组件放在表单上时,IDE 现在会尝试访问 TMasterForm 的 GetPropertiesClass,这会导致 AV,因为此方法是抽象的。
    猜你喜欢
    • 1970-01-01
    • 2018-12-25
    • 2017-05-11
    • 1970-01-01
    • 2018-10-01
    • 2020-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多