Board index » delphi » Confused about ancestor/descendent component inheritance

Confused about ancestor/descendent component inheritance

I've read every word in the documentation and help files but I'm still
confused. I created a class called TStdForm that descends from TForm.
This form has some common controls on it. Using the Object Repository,
I created 3 more forms that descend from TStdForm.

1) Is there a more efficient way for an ancestor to check for the
existence of some component on a descendent than: for i := 0 to
ComponentCount - 1 ?

2) My TStdForm ancestor and all descendants have a method called
SetColor. Is it possible for the ancestor to execute the SetColor
method for the descendants?

3) I renamed a panel in TStdForm. The descendants all have components
placed within this panel.  Compiled fine, but at runtime the forms
failed to open with an error referring to the original name of the
panel.  Did I do something wrong?

Thanks,
Steve

 

Re:Confused about ancestor/descendent component inheritance


Stephen Smith schrieb:

Quote
> I've read every word in the documentation and help files but I'm still

> confused. I created a class called TStdForm that descends from TForm.
> This form has some common controls on it. Using the Object Repository,

> I created 3 more forms that descend from TStdForm.

> 1) Is there a more efficient way for an ancestor to check for the
> existence of some component on a descendent than: for i := 0 to
> ComponentCount - 1 ?

if the components you wold to check are decendants form call TControl
you can check the list Controls of the form.A more efficaient way don't
exist.

Quote
> 2) My TStdForm ancestor and all descendants have a method called
> SetColor. Is it possible for the ancestor to execute the SetColor
> method for the descendants?

If the ancestor shall use the SetColor methode of its descendants you
have to declare the SetColor methode in the class
TStdForm as virtual or dynamic. The descendants have to override this
methode.
TStdForm an its descendants uses the same Vitual Methode Table and the
same SetColor methode.

Quote
> 3) I renamed a panel in TStdForm. The descendants all have components
> placed within this panel.  Compiled fine, but at runtime the forms
> failed to open with an error referring to the original name of the
> panel.  Did I do something wrong?

   You remaned the panel to TStdForm?

To make a TPanel to the ancestor of TStdForm use this decleration:

TStdForm=class(TPanel)
...
...
end;

Regards Bernd

Re:Confused about ancestor/descendent component inheritance


Quote
Stephen Smith wrote:

> I've read every word in the documentation and help files but I'm still
> confused. I created a class called TStdForm that descends from TForm.
> This form has some common controls on it. Using the Object Repository,
> I created 3 more forms that descend from TStdForm.

> 1) Is there a more efficient way for an ancestor to check for the
> existence of some component on a descendent than: for i := 0 to
> ComponentCount - 1 ?

This is the correct way to iterate through the owned components of any
TComponent descendant (which includes TForm).

Just for clarification: There is no way for an "ancestor" to iterate its
"descendant" components. Descendant components inherit everything in
their ancestors, they do not store a separate "copy" of anything and
there is no way to distinguish between them. So when you create an
instance of TStdForm2, which descends from TStdForm, the ComponentCount
property and the Components property will contain *all* owned components
defined by both the ancestor and the descendant classes.

Quote
> 2) My TStdForm ancestor and all descendants have a method called
> SetColor. Is it possible for the ancestor to execute the SetColor
> method for the descendants?

No, but there is no need to. If you have made the SetColor method
virtual in the ancestor, and have redefined the SetColor method in the
descendant using the override directive, then the correct version of the
SetColor method will automatically be called for you according to the
type of the descendant). You can then (optionally) call the inherited
version of SetColor to allow the ancestor's version to also execute.

Depending on what SetColor does, you may not need to override it at all,
if SetColor iterates through the Components array property (re: question
#1) looking for components of certain types so it can set the (e.g.)
Color property, then you do not need to override this in any descendant
- it will work correctly for any and all descendants you define without
any extra work on your part - this is one of the fundamental purposes of
inheritance in Object-Oriented design.

Quote
> 3) I renamed a panel in TStdForm. The descendants all have components
> placed within this panel.  Compiled fine, but at runtime the forms
> failed to open with an error referring to the original name of the
> panel.  Did I do something wrong?

Sounds like, when you created the descendant forms, you made a *copy* of
the ancestor instead of actually inheriting from it. However, I have
very little experience specifically with Form inheritance, so I will
turn this one back to the forum for someone else to answer better.

--
* Wayne Niddery - WinWright Consulting
* Host of RADBooks at http://home.ican.net/~wniddery/RADBooks.html
* -- Amazon.com Associate -- Delphi, C++Builder, JBuilder, InterDev
* ...remove X when replying...

Re:Confused about ancestor/descendent component inheritance


Hey Wayne.

Quote
>No, but there is no need to. If you have made the SetColor method
>virtual in the ancestor, and have redefined the SetColor method in the
>descendant using the override directive, then the correct version of the
>SetColor method will automatically be called for you according to the
>type of the descendant). You can then (optionally) call the inherited
>version of SetColor to allow the ancestor's version to also execute.

I don't specify Virtual or any overrides. This is the TStdForm code:

procedure TStdForm.SetFormColor;
begin
  HeaderPanel.Color := CAPTION_COLOR;
end;

And this is from one of the descendants:

procedure TInquiryForm.SetFormColor;
begin
  inherited;
  if HICOLOR_MODE then begin
    Icon.Handle := LoadIcon(hInstance, 'INQUIRY256S');
    Image1.Picture.Icon.Handle := LoadIcon(hInstance, 'SEARCH256');
  end else begin
    Icon.Handle := LoadIcon(hInstance, 'INQUIRY16S');
    Image1.Picture.Icon.Handle := LoadIcon(hInstance, 'SEARCH16');
  end;
end;

Quote
>Depending on what SetColor does, you may not need to override it at all,
>if SetColor iterates through the Components array property (re: question
>#1) looking for components of certain types so it can set the (e.g.)
>Color property, then you do not need to override this in any descendant
>- it will work correctly for any and all descendants you define without
>any extra work on your part - this is one of the fundamental purposes of
>inheritance in Object-Oriented design.

The SetFormColor procedure is called at startup, but is also be called
during runtime if something like CAPTION_COLOR changes.  Right now, I
have to tell each TStdForm descendent (but not TStdForm itself) to
SetFormColor individually. I can't have TStdForm.SetFormColor iterate
through a descendent's ComponentList since each descendent needs
unique code in their SetFormColor procedures (eg. each has its own
form icon).

Thus I was wondering if there was something simple I could do in
TStdForm that would make all instantiated TStdForm descendants execute
their SetFormColor procedures.

Quote
>> 3) I renamed a panel in TStdForm. The descendants all have components
>> placed within this panel.  Compiled fine, but at runtime the forms
>> failed to open with an error referring to the original name of the
>> panel.  Did I do something wrong?

>Sounds like, when you created the descendant forms, you made a *copy* of
>the ancestor instead of actually inheriting from it. However, I have
>very little experience specifically with Form inheritance, so I will
>turn this one back to the forum for someone else to answer better.

I think I inherited from my TStdForm. I used the "New..." menu item on
the File menu to launch the Object Repository, which included a tab
with the same name as my open project. This tab included all the forms
in my project. I selected my TStdForm and then dropped additional
controls onto it.

Thanks,
Steve

Re:Confused about ancestor/descendent component inheritance


Hey Bernd.

Quote
>If the ancestor shall use the SetColor methode of its descendants you
>have to declare the SetColor methode in the class
>TStdForm as virtual or dynamic. The descendants have to override this
>methode.
>TStdForm an its descendants uses the same Vitual Methode Table and the
>same SetColor methode.

OK, I need to study up on virtual and dynamic...

Quote
>> 3) I renamed a panel in TStdForm. The descendants all have components
>> placed within this panel.  Compiled fine, but at runtime the forms
>> failed to open with an error referring to the original name of the
>> panel.  Did I do something wrong?

>   You remaned the panel to TStdForm?

>To make a TPanel to the ancestor of TStdForm use this decleration:

>TStdForm=class(TPanel)
>...
>...
>end;

I used "New..." on the File menu and selected TStdForm to create the
descendants.  This created empty forms that displayed all the controls
on TStdForm, including a panel on TStdForm that  I renamed *on*
TStdForm itself.  I recompiled and then found the runtime error.  I
looked in the descendant's .dfm files and found them still referencing
the panel via the old name.

Thanks,
Steve

Re:Confused about ancestor/descendent component inheritance


Stephen Smith <smi...@removethis.imagesoftcorp.com> wrote in article

Quote
> I don't specify Virtual or any overrides. This is the TStdForm code:

> procedure TStdForm.SetFormColor;
> begin
>   HeaderPanel.Color := CAPTION_COLOR;
> end;

> And this is from one of the descendants:

> procedure TInquiryForm.SetFormColor;
> begin
>   inherited;
>   if HICOLOR_MODE then begin
>     Icon.Handle := LoadIcon(hInstance, 'INQUIRY256S');
>     Image1.Picture.Icon.Handle := LoadIcon(hInstance, 'SEARCH256');
>   end else begin
>     Icon.Handle := LoadIcon(hInstance, 'INQUIRY16S');
>     Image1.Picture.Icon.Handle := LoadIcon(hInstance, 'SEARCH16');
>   end;
> end;

Look at this code:

TStdForm = class(TForm)
...
public
...
    procedure SetFormColor; virtual;   { A virtual function could be
overridden by descendants }
end;
....

TInquiryForm = class(TStdForm)
...
public
    procedure SetFormColor; override;  { The virtual function is overridden

Quote
}

end;

Use inherited as you already does. In this case an instance of TStdForm or
any descendants of TStdForm will call it's appropriate SetFormColor. If you
don't want the inherited forms SetFormColor to be called take away
inherited;

Quote
> >> 3) I renamed a panel in TStdForm. The descendants all have components
> >> placed within this panel.  Compiled fine, but at runtime the forms
> >> failed to open with an error referring to the original name of the
> >> panel.  Did I do something wrong?
> I think I inherited from my TStdForm. I used the "New..." menu item on
> the File menu to launch the Object Repository, which included a tab
> with the same name as my open project. This tab included all the forms
> in my project. I selected my TStdForm and then dropped additional
> controls onto it.

It sounds as you have done the correct thing when you created your
descendants Forms. If you rename a TPanel in TStdForm it should also be
renamed in the others. (At least this works perfectly for me using the same
approach as you. I do this all the time actually.) You can check this
viewing your Form as text. Check that 'inherited' is written before the
TPanel, and not 'object'===> this indicates that a new object is created,
and you want to use the old one.

--
Edgar Vorland
{Remove X and Y from my mailadress, this is to avoid spawn}
Xevorl...@Yreadmatre.no

Re:Confused about ancestor/descendent component inheritance


Hey Edgar.

On 16 Dec 1997 12:33:50 GMT, "Edgar Vorland" <Xevorl...@Yreadmatre.no>
wrote:

Quote

>Look at this code:

>TStdForm = class(TForm)
>...
>public
>...
>    procedure SetFormColor; virtual;   { A virtual function could be
>overridden by descendants }
>end;
>....

>TInquiryForm = class(TStdForm)
>...
>public
>    procedure SetFormColor; override;  { The virtual function is overridden
>}
>end;

>Use inherited as you already does. In this case an instance of TStdForm or
>any descendants of TStdForm will call it's appropriate SetFormColor. If you
>don't want the inherited forms SetFormColor to be called take away
>inherited;

OK. I just did as you suggested and... ah! that's what I was look for!
I was forced to repeat the exact same code in every one of my TStdForm
descendants for a variety of things, but now I can consolidate all
those separate procedures into a single procedure in TStdForm!

Geez. I read and re-read the (minimal) D3 help on virtual methods but
I guess I just didn't get it. Duh. Time to buy some Delphi books...

- Show quoted text -

Quote
>> >> 3) I renamed a panel in TStdForm. The descendants all have components
>> >> placed within this panel.  Compiled fine, but at runtime the forms
>> >> failed to open with an error referring to the original name of the
>> >> panel.  Did I do something wrong?
>> I think I inherited from my TStdForm. I used the "New..." menu item on
>> the File menu to launch the Object Repository, which included a tab
>> with the same name as my open project. This tab included all the forms
>> in my project. I selected my TStdForm and then dropped additional
>> controls onto it.

>It sounds as you have done the correct thing when you created your
>descendants Forms. If you rename a TPanel in TStdForm it should also be
>renamed in the others. (At least this works perfectly for me using the same
>approach as you. I do this all the time actually.) You can check this
>viewing your Form as text. Check that 'inherited' is written before the
>TPanel, and not 'object'===> this indicates that a new object is created,
>and you want to use the old one.

Hmmm. I just tried it again and had the same problem. I renamed a
panel on TStdForm from HeaderPanel to NewHeaderPanel. When I click on
this same panel as displayed in Delphi on my form descendants, the
name is changed. I recompile and then get this error at runtime:
Ancestor for 'HeaderPanel' not found.

I open up a TStdForm descendant .dfm file find inherited HeaderPanel:
TPanel which should be inherited NewHeaderPanel: TPanel, shouldn't it?
When I reopen the project in Delphi, I get errors opening my
descendant forms because there is no longer a panel in TStdForm named
HeaderPanel.

I don't see any reference to TStdForm in the descendant's .dfm file.
Should I see something or is TInquiryForm = class(TStdForm) in the
.pas file all that is needed?

Thanks,
Steve

Re:Confused about ancestor/descendent component inheritance


Stephen Smith <smi...@removethis.imagesoftcorp.com> wrote in article

Quote
> Hmmm. I just tried it again and had the same problem. I renamed a
> panel on TStdForm from HeaderPanel to NewHeaderPanel. When I click on
> this same panel as displayed in Delphi on my form descendants, the
> name is changed. I recompile and then get this error at runtime:
> Ancestor for 'HeaderPanel' not found.

> I open up a TStdForm descendant .dfm file find inherited HeaderPanel:
> TPanel which should be inherited NewHeaderPanel: TPanel, shouldn't it?
> When I reopen the project in Delphi, I get errors opening my
> descendant forms because there is no longer a panel in TStdForm named
> HeaderPanel.

> I don't see any reference to TStdForm in the descendant's .dfm file.
> Should I see something or is TInquiryForm = class(TStdForm) in the
> .pas file all that is needed?

This should be seen at the top of your descendant's .dfm file :
   inherited InquiryForm: TInquiryForm

This indicates that TInquiryForm is an inherited form.

I have no idea how you' ve got this wrong, because it seems to me that you
are doing the correct thing when creating your descendant forms!

Hope this helps!
--
Edgar Vorland
{Remove X and Y from my mailadress, this is to avoid spawn}
Xevorl...@Yreadmatre.no

Other Threads