How do I use or resolve issues with visual form inheritance in Delphi?

16,928

Solution 1

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.

Solution 2

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
Share:
16,928
Rob
Author by

Rob

I'll fill this out someday.

Updated on June 06, 2022

Comments

  • Rob
    Rob about 2 years

    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.
  • Erick Sasse
    Erick Sasse over 15 years
    The global var is not required.
  • Jason 'Bug' Fenter
    Jason 'Bug' Fenter over 15 years
    The global variable is only required if you let Delphi "Auto-create" the form (you can set this in the Project Options dialog).
  • Rob
    Rob over 15 years
    You guys are right. I just double checked that out. I'll edit the post, thanks.
  • Jeroen Wiert Pluimers
    Jeroen Wiert Pluimers over 14 years
    See also these two blog posts that explain Frame and DataModule inheritance: wiert.wordpress.com/2009/07/22/… and wiert.wordpress.com/2009/08/20/… Those articles contain pictures of good and bad situations.
  • raju
    raju over 13 years
    For the C++Builder people you can pretty much follow the same instructions. The only caveat I have is that TAncestorForm cannot be within its own namespace (i.e. must be in global namespace). At least this was my finding.
  • Bizmarck
    Bizmarck over 7 years
    I ran into the same problem, but in my case both the descendant and the ancestor already existed. In the project, however, the ancestor's DFM was not included in the project files. I had to remove the ancestor, then right click the project and Add > , the ancestor again. This time the DFM was included.
  • Arioch 'The
    Arioch 'The almost 6 years
    I wonder if what is needed to make it work would be just mentioning the unit in the DPR file or adding the form/frame comment too. Because having those parent forms in BPLs, putting "in" clause into DPR would be cheating at best. There is another workaround though, github.com/the-Arioch/XE2_AutoOpenUnit
  • Arioch 'The
    Arioch 'The almost 6 years
    So, I tried unAncestor {AncestorForm}, without in 'unAncestor.pas' in my DPR and my Delphi XE2 acts so weirdly... It does try to auto-open something, but... Well, it throws an exception that it can open file DPR-PATH\AncestorForm ! So without in-clause it takes comment for the file name relative to DPR folder and then tries to open it without checking if the file exists! Weird
  • Arioch 'The
    Arioch 'The almost 6 years
    For removing in-clause in DPR for BPL-contained units there are two abstract and one practical reasons: 1) it is anti-documentation. You document in DPR that the unit is compiled into EXE, while in reality it is compiled into BPL the EXE uses; 2) violation of single responsibility: the path to unit should be specified in one place: DPK 3) consequently I faced a situation when I had several versions of the unit in different folders. DPK and DPR chanced to point at different ones. So the real code used DPK-provided unit, while IDE pointed at DPR-documented (falsely) one. Confusing a lot.
  • Server Overflow
    Server Overflow over 3 years
    Interesting.... Which of the steps above are automatically done by the IDE and which ones you need to do manually? Also, do you need to open the ancestor form BEFORE you open the inherited form?