德尔福组件属性类,具体取决于组件的所有者类



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

我看到尝试在 TForm 上发布属性不是很实用。然后必须将其注册并安装为软件包,然后对于繁重的开发是不切实际的。

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

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

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

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

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

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

每个形式都有一个对应的后代,如下所示:

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

例如:

如果放置组件的窗体是 TBaseForm,则 FProperties 将是 TBaseFormProperties。如果表单是 TSecondForm,则 FProperties 将是 TSecondFormProperties。当然,TSecondFormProperties 将从 TBaseFormProperties 继承。

但是,当我将组件放在窗体上时,它似乎无法检测到组件是哪个类。

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

看起来 TBaseForm(所有者) 部分导致了问题。解释器卡在 TBaseForm 上,不会考虑所有者是 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 不会在设计时实例化您的表单。因此,无论您在窗体类中放入什么代码,IDE 都不会执行该代码。这是因为您没有向 IDE 注册表单。

如果希望 IDE 了解窗体,则需要在 IDE 中注册窗体。在这一点上,你所有的代码都变得不必要了,因为你又回到了你试图避免的事情上。即向 IDE 注册表单。你被困在第22条军规的情况下。如果您需要 IDE 了解表单,则需要注册它们。此时,您也可以直接在对象检查器中显示属性。

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

事实上,你并没有在整个类系列中继承它。

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

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

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

最新更新