12
votes

I've been working on a project in Delphi 7 where I wanted to have forms inherit components from other forms. I was able to get this working, but came across the following issues (and I'm going to post the solutions to hopefully help others in the future):

  1. In the .pas file of a form, I would change the form to inherit from some other form, but it wouldn't get the components from the ancestor form.
  2. For certain descendant forms, I would get the following error message when opening the form at design time: "Error creating form: Ancestor for 'TAncestorForm' not found." I would have to first manually open the ancestor form, and then I could open the descendant form.
2

2 Answers

27
votes

First, for those who don't know how to inherit a form visually, you create the ancestor form as usual. Then go to File > New > Other. Select the tab with the name of the current project, and choose the form you want to inherit from. If you want to inherit from a form that's not part of the current project, open that form, right click it, and choose Add to Repository. Then you will be able to go to File > New > Other and select that form from the appropriate tab.

Given that, I came across issues because some of the descendant forms were already created, so I couldn't follow the process above. Also, I made some changes to forms from the standard code Delphi creates. I was able to resolve all issues with visual form inheritance using the following guidelines:

  • The .pas file of the descendant form must have the form's class inherit from the correct ancestor class, e.g.:
    type TMyForm = class(TAncestorForm)
  • The first line in the .dfm of the descendant form must have the word inherited instead of object, e.g.:
    inherited MyForm: TMyForm
  • EDIT: After double checking, the following is NOT required: The .pas file of the ancestor form must have the standard global variable that Delphi creates, e.g.:
    var AncestorForm: TAncestorForm;
  • The uses section of the .dpr file of the project must have that same global variable as a comment after the unit's file name, e.g.:
    unAncestor in 'unAncestor.pas' {AncestorForm}

Notes/Tips:

  • Both the ancestor form and the descendant form are allowed to be non-auto created if you want (Set in Project > Options > Forms > Auto-create forms).
  • To revert a property on a descendant form to the ancestor form's value, right click on the property in the Object Inspector, and choose Revert to inherited.
  • To revert all property values of a component to the ancestor's values, right click the component and choose Revert to inherited.
1
votes

The DPR seems a little bit trickier than that. In my case, I created an ancestor derived from TFrame. I then derived multiple frames from TAncestorFrame. My DPR's uses clause then looked like:

uses
  Forms,
  ancestorFrame in 'ancestorFrame.pas' {AncestorFrame : TFrame},
  frame1Unit in 'frame1Unit.pas' {frame1:TFrame},
  frame2Unit in 'frame2Unit .pas' {frame2:TFrame},

The DPROJ file should look like:

<DCCReference include="frame1Unit.pas">
  <Form>frame1</Form>
  <DesignClass>TFrame</DesignClass>
</DCCReference>

Derived Frames should look like:

TFrame1 = class(TAncestorFrame)

And Derived Frames .DFM files should say:

inherited Frame1:TFrame1