TFrame继承重构

4

我又有一个关于TFrame IDE注册组件的问题。感谢所有程序员的帮助。:)

通过尝试Darrian的TFrame继承建议here,我发现:

具体内容:

基本上,我有一个基于TFrame的组件已经成功地注册到IDE中。现在我正在开发几个“姐妹”组件,它们将共享大量现有组件的非可视功能和属性。因此,将这些功能和属性移动到父类/超类中,并使新旧组件都可以从中继承,这是很有意义的。

如何以最佳方式“重构”TFrame继承呢?(这也可能适用于TForm类的后代,不确定)。有哪些注意事项和需要注意的问题?

例如:

例如,我尝试创建一个新的TFrame,并将其命名为TMyBaseFrame,然后修改现有组件的类定义(我们称其为TMyFrameTreeView),使其继承自TFrame而不是原来的父类。它编译得很好,但当我试图将其拖放到表单上时,会出现“未找到ClientHeight”(或“未找到ClientHeight属性”)的错误,并且无法将其放置在表单上。从相关DFM中删除ClientHeight和ClientWidth会造成严重问题,并且它们最终会在调整大小时被替换。我注意到后代类中存在ExplicitHeight和ExplicitWidth,并认为这与从继承值覆盖属性值有关,但我不确定。通过New->Inherited Items重新创建全新的框架,然后复制所有内容,也没有取得很好的结果。
最后说明:
我意识到这可能会很快变得混乱,涉及DFM文件和多个后代代数等等...这也是我要求整体“注意事项”的概念方面的一部分,但也提供了一个具体的现实世界中更简单的问题版本(我认为应该是可行的)。
我创建了一个小测试包以进行学习尝试,学到了很多,但进展缓慢,非常感谢您这些 Delphi "Jedi 大师" 的任何指导/见解。:) 回答稍后更新: 下面的两个答案都很有帮助。此外,创建一个“基本框架类”,它与普通的 TFrame 没有任何更改,然后继承自该类,再添加任何属性、方法等,似乎可以极大地稳定继承流。不确定为什么,但目前为止是这样的。
2个回答

12
除了将 TMyFrameTreeView 的基类更改为 TMyBaseFrame,还需将 TMyFrameTreeView 在 dfm 文件中的第一个单词从 object 更改为 inherited

我想我在过去的10年里遇到了这种情况3次,每次都会来到这里...再次感谢。也许下一次我会记得。 - Darian Miller

4
我现在正在开发几个“姐妹”组件,它们将共享大量现有组件的非可视功能和属性。因此,将很多这些内容移动到一个父类/超类中,然后新旧组件都可以从中继承,这是有意义的。
在您上面的文本中,重点可能是“组件的非可视功能”。因此,在这种情况下,我认为最好将可视和非可视层分开。
因此,也许更好使用装饰器:
```python class NonVisualComponent: def __init__(self, component): self.component = component
# non-visual functionality here class VisualComponent: def __init__(self, component): self.component = component
# visual functionality here class MyComponent(NonVisualComponent, VisualComponent): pass ```
这样,您可以将所有非可视功能放在`NonVisualComponent`中,将所有可视功能放在`VisualComponent`中,并使用`MyComponent`来继承这两个组件。
TMySharedEngine = class(Whatever)
property LinkedFrame: TFrame;
property P1;
property P2;
...
procedure Proc1;
procedure Proc2;
... //etc.
end;

你需要在“姐妹”框架中使用它的实例:

var
TMyFrame1 = class(TFrame)
...
FDecorator: TMySharedEngine;
  ...
  public
  property MySharedPart: TMySharedEngine read FDecorator;
  constructor Create(AOwner: TComponent); override;
  ...
end;

constructor TMyFrame1.(AOwner: TComponent); override;
begin
  inherited;
  FDecorator:=TMySharedEngine.Create; //ok, ok do not forget to Free it .Destroy
  FDecorator.LinkedFrame:=Self;
  ...
end;

另一方面,如果您想使用您的方法,您可以使用Visual Form Inheritance(如Darian所建议的)或者(更灵活的方式)您可以手动完成:使用IDE创建以下框架:TBaseFrame,TChildFrame1,TChildFrame2 ...等。现在进入TChildFrame1的单元并手动更改它的类定义从TChildFrame1 = class(TFrame)到TChildFrame1 = class(TBaseFrame)。编译。应该可以工作。建议TBaseFrame为空,以避免可能的小问题(功能冲突等)。
希望对您有所帮助。

1
到目前为止,似乎“完全清空TBaseFrame”是避免许多小故障的关键。此外,在后续类中确保DFM文件以“inherited”开头而不是“object”也很重要。我也会考虑你的装饰器想法 - 谢谢! - Jamo
到目前为止,似乎“完全清空TBaseFrame”是避免很多小毛病的关键。是的,请记住这是“按设计”(也就是说不会更改)- Delphi必须尽可能灵活-因此您很容易自食其果。这就是为什么像我说的那样更安全。 - John Thomas
感谢您对上面装饰器方法的想法等的贡献。 - Jamo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接