views:

439

answers:

2

Yet another TFrame IDE-registered-component question from me. Thanks for all the help, fellow programmers. : )

Playing around with Darrian's TFrame inheritance suggestion here:

Specifics:

Basically, I have a TFrame-based component that I've registered to the IDE, and it has worked wonderfully. I'm now developing a few "sister" components which will share a great deal of the existing component's non-visual functionality and properties. It makes sense, then, to move a lot of that to a parent/superclass which both the new and the old components can then inherit from.

What is the best way to "refactor" TFrame inheritance in this way? (This may apply to TForm-class descendants too, not sure). What are the caveats and things to watch out for?

Example:

I tried, for example, creating a new TFrame, with nothing on it, and calling that frame TMyBaseFrame. Then modified the class definition of my existing component (Let's call it TMyFrameTreeView) to inherit from that rather than TFrame.

It compiled fine, but when I tried dropping it on a form, I got "ClientHeight not found" (or "ClientHeight property not found"), and it wouldn't drop on the form. Deleting ClientHeight and ClientWidth from the related DFM wreaked havoc, and they ended up replaced upon resizing anyway. I noticed ExplicitHeight and ExplicitWidth in descendent classes, and am thinking that relates to property-value overrides from inherited values, but am not sure. Recreating an entirely new frame via New -> Inherited Items, and then copying everything over, hasn't yielded great results yet either.

Final Note

I realize this could get messy quickly, with streaming DFM files and multiple generations of descendants, etc.... which is part of why I'm asking for the overall "things to look out for" conceptual aspect, but also giving a specific real-world simpler version of the problem as well (which seems to me, ought to be doable).

I've created a little test package to hack around in learning attempts, and am learning a great deal, but it's slow-going, and any guidance/insight from you Delphi "Jedi Masters" out there would be MOST appreciated. : )



Answer update later:

Both of the answers below were helpful. As well, creating a "Base Frame Class" which has NO changes from the normal TFrame, and THEN inheriting from that before adding any properties, methods, etc. seems to stabilize the inheritance streaming tremendously. Not sure why, but so far it has.

+3  A: 

In addition to changing base class of TMyFrameTreeView to TMyBaseFrame change the first word in the dfm file for TMyFrameTreeView from object to inherited.

+2  A: 

I'm now developing a few "sister" components which will share a great deal of the existing component's non-visual functionality and properties. It makes sense, then, to move a lot of that to a parent/superclass which both the new and the old components can then inherit from.

What is the best way to "refactor" TFrame inheritance in this way?

The crux of your text above perhaps is "component's non-visual functionality". So, in this case, IMHO it's best to separate the visual and non-visual layers.

So, perhaps it's better to use a decorator:

TMySharedEngine = class(Whatever)
property LinkedFrame: TFrame;
property P1;
property P2;
...
procedure Proc1;
procedure Proc2;
... //etc.
end;

and in your 'sister' frames to use instances of it:

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;

OTOH, if you want to use your approach you can use Visual Form Inheritance (as Darian suggested) or (more flexible) you can do it by hand: Create, using the IDE the following frames: TBaseFrame, TChildFrame1, TChildFrame2 ... etc. Now go on TChildFrame1's unit and change by hand it's class definition from TChildFrame1 = class(TFrame) to TChildFrame1 = class(TBaseFrame). Compile. It should work. It's recommended though that when you'll do this trick TBaseFrame to be empty in order to avoid possible small quirks (feature collisions etc.)

HTH.

It's seeming thus far that "having TBaseFrame TOTALLY empty" is key to avoiding MANY little glitches. Also making sure DFM file begins with "inhertied" rather than "object" in later classes. Will think about your decorator idea as well -- thanks for that!
Jamo
"It's seeming thus far that "having TBaseFrame TOTALLY empty" is key to avoiding MANY little glitches" - Yeah. And keep in mind that this is 'by design' (IOW will not change) - Delphi must be flexible as it gets - so you can very easily shoot yourself in the foot. That's why it's safer as I said.
Thanks for your ideas re: decorator approach above, etc.
Jamo