Search code examples
delphitpagecontrolttabsheetclass-helpers

How to add a property to TTabSheet such that it can be used at design time with TPageControl


I would like to add "MyProperty" to TTabSheet and work with it at design time. However if I subclass it I fear I will need to also subclass TPageControl, since it internally creates/manages the TTabSheets.

I believe this would require duplicating the TTabSheet management code to reference TMyTabSheet instead of TTabSheet, since it will need to invoke TMyTabSheet.create. This feels like something I will regret when a new version of Delphi updates TPageControl and I forget to update TMyPageControl.

I am also researching "class helpers" as another option.

Does anyone have advice on how to best accomplish this?

Thanks!


Solution

  • Type Helpers are merely compile-time sugar, they would cause no effect over the already compiled code, that stock VCL is together with TPageControl and TForm. That is a dead-end.

    However you have a slight misconception here that TPageControl... internally creates... the TTabSheets. Indeed, when you create the sheets by the means of TPageControl itself, like right-clicking it and selecting "New Tab" that si what happens. But when you create the living form object out of DFM file (or DFM resource in your compiled EXE) that is TForm itself that creates ALL the components, including both page control and its tabsheets.

    Just see my answer at How to efficiently let a `ParentFont = False` child control to use same font name as parent? - that would show you how far it is about the owner - TForm, not about TPageControl or other parent components when it comes about selecting specific classes for the actual tabs or other elements..

    So you are free to pursue subclassing tabsheets only.

    • Create the TMyTabsheet = class(TTabSheet) component
    • Create and install into IDE the design-time package that would introduce new subclassed tab sheet to Delphi Form Editor
    • In your form put the stock TPageControl and create all the needed tabs regular way
    • in IDE form Editor right-click over the form free space and in the menu do the "View As Text Alt-F12" command - you would see the text content of your form's DFM file
    • in those DFM sources find your tab sheets and change their stock TTabSheet class to be your derived sub-class
    • right-click the text editor and choose "View As Form Alt-F12" command
    • If all was done correct then Delphi would recreate the form with your new-class sheets now. Find your new properties in Object Inspector and change them.
    • Now switch to .Pas sources of your form and find the declarations of those tab sheets and change their type too. That is only required if you would have to access your new properties from the Delphi sources. If not you can leave their declaration as TTabSheet in pas-file as your class is direct descendant from it. You may leave those declarations as they were - but then you would have to add RegisterClass(TMyTabSheet); call into the very initialization section at the bottom of your unit, so when the form would construct itself out of the DFM it would be able to find the class implementation by the name. If you would change the declaration (at least one of those) then your form would automagically call all needed RegisterClass before streaming out of DFM. Choose any option you like.
    • Optionally and later, extend your design-time package to find and hijack IDE Form Editor's right-click menu for TPageControl and add "New My Subclassed Tab" command there. Just to avoid manual post-factum DFM editing. if you would do it often

    This feels like something I will regret when a new version of Delphi updates TPageControl

    After you created and tuned the form and saved it into DFM - it would be TForm that creates all the components out of the saved DFM-data, and that includes your tabs too. Unless very improbable event EMBT would kill the whole VCL streaming (made back in Delphi 1 in 1995) and redesign it from scratch (killing all the compatibility with existing Delphi sources at once), there should be no problem with forward compatibility with specifying your class in DFM. It is just the standard way VCL is designed - to get specific component types from the DFM.