The spring (a twig) components – How to improve the use of Delphi Frames – Stack Overflow
Posted by jpluimers on 2025/08/19
In [Wayback/Archive] components – How to improve the use of Delphi Frames – Stack Overflow (thanks [Wayback/Archive] Brian Frost for asking!) I referred to a blog post I wrote more than 15 years ago about registering Delphi frames as components in Delphi: Delphi – Frames as visual Components – don’t forget your Sprig!
It is still a technique few use, but it is very powerful as it resolves many design time issues that arise when using Delphi frames in a normal fashion especially:
- when using form/frame inheritance: accidentally moving around components on the frame and breaking inherited forms/frames
- because you can accidentally delete the components on the frame as these are visible in the structure pane (this causes access violations at design time making the IDE unstable to the point where all kinds of things fail like for instance compiling to invalid code that crashes at run-time, debugger getting out of sync, and eventually the IDE itself crashing)
In the blog post, I described a technique I learned from Ray Konopka by using sprigs.
For people unfamiliar to the English language, the meaning of a sprig is not immediately clear as it can have various meanings like for instance:
- a small twig (very small branch), see the Wikipedia article Twig
- a small twig containing crown and roots which can be cut off and used to growing the twig on soil or water (see Wikipedia article Sprigging, Rhizome and Stolon)
That’s why I wrote the below answer and comment of the above mentioned Stack Overflow article (but forgot to blog post about it until now):
A
Registering your frames as a component solves both 1. and 2.:
- the components on the frame are locked when you put that frame control on a form or other frame
- you will get a component (actually: control) that you can design visually
But: there are a few catches (which can be solved, see article link), of which the most important is this one:
When you put components on your frame, and later drop that frame as a component on a Delphi form or frame, the components are visible in the Structure Pane.
The problem is that because they are visible in the structure pane, you can delete them, causing access violations.
The trick to solve this to not forget the ‘sprig’.
I learned that valuable lesson from Ray Konopka during DelphiLive 2009.Since the lesson is so valuable, I wrote a blog post on it that describes it in detail.
The essential portion is this little piece of code (more details in the blog post):
procedure RegisterFramesAsComponents(const Page: string; const FrameClasses: array of TFrameClass); var FrameClass: TFrameClass; begin for FrameClass in FrameClasses do begin RegisterComponents(Page, [FrameClass]); RegisterSprigType(FrameClass, TComponentSprig); end; end;C
@ExternalServerError if the blog article is not clear enough, maybe the explanation by Ray Konopka is more clear: codeverge.com/public.delphi.vcl.writing/visual-compound-component-design-wi/1087914
C
@ExternalServerError, that’s right: it is why Ray explains about a
sprig, not aspring. A sprig is a kind of branch conduit between components and the IDE designers. There is hardly any documentation about it, but if you look at the Delphi 7 VCL hierarchy poster, you can find out some of the names used and from there Google for their context. scribd.com/document/17544777/Delphi-7-VCLHierarchyPoster
Before continuing with references, there is also another thing I discovered while researching this blog post and might need in the future: allowing the object inspector to access various Frame properties. I archived this stackoverflow question and answers as their moderators tend to delete relevant data without understanding that they are relevant.
[Wayback/Archive] delphi – Showing TFrame descendant’s additional properties on the object inspector – Stack Overflow (thanks [Wayback/Archive] Serguzest and [Wayback/Archive] Mad Scientist)
Keywords in that page:
- RegisterCustomModule(TMyFrame, TCustomModule);
- RegisterCustomModule(TYourFrameClass, TFrameModule); // for frames
RegisterCustomModule(TYourModuleClass, TDataModuleCustomModule); // for data modules - function Nestable: Boolean; override;
- RegisterCustomModule(TYourFrameClass, TNestableWinControlCustomModule);
- TCustomModule => DesignEditors
TDataModuleCustomModule => DMForm (designide.dcp)
TWinControlCustomModule => WCtlForm (designide.dcp)
TFrameModule => VCLFormContainer (vcldesigner.dcp)
TCustomFormCustomModule
TIDESourceModuleCustomModule
References
Referenced blog post: Delphi – Frames as visual Components – don’t forget your Sprig!
Referenced dead links (archives have 2009 content; actual links are now dead, so I quoted their content):
- [Wayback/Archive] Raize Software Events
DelphiLive!
Location San Jose, California Date/Time May 13-16, 2009 Sessions Presented by Ray Konopka 
Creating Composite VCL Controls 
Creating Custom WPF Controls in Delphi Prism 
Creating Custom VCL Components (Tutorial) Raize Software Participation 
Vendor Exhibit For more info… http://www.delphilive.com/ - [Wayback/Archive] DelphiLive (held in 2009 and 2010 in San Jose, California, USA)
Delphi Live ! – The Delphi Developer Conference!
Delphi Live! 2009 will take place for the first time in San Jose, not far from Delphi’s birthplace in the Silicon Valley. The programming language / development tool Delphi has been sold more than 1,500,000 times and is used in millions of applications around the world.
S&S Media is a media company and conference producer for the European IT industry for more than 15 years. This year we bring together the best speakers of our industry with Delphi developers from all over the US to share the latest information on Delphi developments
Delphi & more
Delphi Live! gives the Delphi community an ideal opportunity to get an update on state-of-the-art technology. Delphi Live! will play an important role as the community event for all developers working with Delphi. On top of that you have the chance to get informed on the latest products, tools, services and additional technologies available on the market at the exhibition hosting numerous sponsors and exhibitors.
Delphi Live! 2009 –Information, information, information!
In countless sessions and workshops internationally renowned speakers pass on their knowledge to the attendees and provide them with everything they need to be successful in their projects. In this way you will obtain your latest update and ensure your competitive edge!
The Delphi VCL post link above works (I archived it: [Wayback/Archive] Delphi 7 – VCLHierarchyPoster | PDF | Computer Companies Of The United States | Software Engineering); other links to it are available via my blog post Online Delphi manuals.
Live link, but still quoted the relevant parts as web-content tends to die: [Wayback/Archive] Visual [Compound] Component Design with TFrame [Edit] – public.delphi.vcl.writing
…
Thanks for sending the component source code. I rebuilt the component package and loaded it into Delphi. I then created a new application and dropped an instance of the component onto the form. The component worked as I expected. That is, I was not able to select any of the individual controls by clicking on them in the Form Designer. Also, I did not see any of the sub-components listed in the Object Inspector, which is also what I expected. However, I believe I finally understand what you are running into. The sub-components *DO* show up in the Structure Pane. And as you have pointed out, when you select them in the Structure Pane, you can then edit their properties in the Object Inspector. I was also very surprised to see that you can delete the controls as well, which can cause all kinds of problems in the Form Designer. Clearly, this is not desired behavior. Fortunately, it is possible to alter the behavior of the Structure Pane by registering a new sprig class for your frame component. First, you need to modify the component package as follows: package TFrame2006; {$R *.res} (* Other compiler directives deleted *) requires rtl, vcl, DesignIDE; // Add this line contains untTFrame2006 in 'untTFrame2006.pas'; end. Next, you need to modify the Register procedure in your component unit to the following: uses TreeIntf; procedure Register(); begin // Register component and add to Tool Palette RegisterComponents('TFrame Component Test', [TFrame2006]); RegisterSprigType( TFrame2006, TComponentSprig ); end; By default, the Delphi IDE uses a special sprig class when displaying controls that can contain other controls such as a TPanel, a TForm, or a TFrame. The RegisterSprigType call above forces the simple TComponentSprig to be used in the Structure Pane. After rebuilding the package and reloading into Delphi, you will notice that you can no longer select the sub-components of the frame component in the Structure Pane. Ray…
The compiling problem you are now facing is a result of creating a component package that is serving as both a runtime package *and* a design package. In order to compile correctly, you will need to create two packages. The first package will be a runtime only package and will only contain the frame component unit. The Register procedure along with the reference to TreeIntf will need to be moved to a separate registration unit. Also, the DesignIDE reference in the requires clause of the runtime package will need to be removed. The design package will contain the registration unit (which contains the Register procedure), and the requires clause of the design package will list the DesignIDE package. Also, the design package will also require the runtime package you created above. For example, // Runtime package package TFrame2006; {$R *.res} (* other compiler directives *) {$RUNONLY} requires rtl, vcl; contains untTFrame2006 in 'untTFrame2006.pas'; end. // Design Package package TFrame2006_Design; {$R *.res} {$R TFrame2006_Reg.dcr} {$ALIGN 8} (* other compiler directive *) {$DESIGNONLY} requires vcl, DesignIDE, TFrame2006; contain TFrame2006_Reg; end. If you decide to create a component icon for the frame component, it should be placed in a dcr file that is linked into the design package. This is what the {$R TFrame2006_Reg.dcr} statement is for. Also, the TFrame2006_Reg unit is the registration unit that simply contains the Register procedure and registers both the frame component and the sprig. Also note that the design package is dependent on the runtime package. Ray…
> If possible, I would also like to selectively expose (or hide) the component's TFrame ancestor properties and events If would be possible ho inherit from TCustomFrame instead of TFrame, and continue have the ability to use the designer to design your frame, alf of this was solved. As this is not possible (as far as I know) you can, at least, hide the frame properties from object inspector using the method "UnlistPublishedProperty". This will only hide them from the inspector, but the frame properties will still be accessible via code, and stored in the .DFM file. Example: procedure Register; begin DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Align'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'AlignWithMargins'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Anchors'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'AutoScroll'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'AutoSize'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'BiDiMode'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Color'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Constraints'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Ctl3D'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Cursor'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'DockSite'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'DragCursor'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'DragKind'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'DragMode'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Font'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'HelpContext'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'HelpKeyword'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'HelpType'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Hint'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'HorzScrollBar'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Margins'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'Padding'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ParentBackGround'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ParentBiDiMode'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ParentColor'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ParentCtl3D'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ParentFont'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ParentShowHint'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'PopupMenu'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'ShowHint'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'TabOrder'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'TabStop'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'VertScrollBar'); {Event's properties can't be hidden by this method? :-( DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnAlignInsertBefore'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnAlignPosition'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnCanResize'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnConstrainedResize'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnContextPopup'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnDblClick'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnDockDrop'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnDragOver'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnEndDock'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnEndDrag'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnEnter'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnExit'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnGetSiteInfo'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseActivate'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseDown'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseEnter'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseLeave'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseMove'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseUp'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseWheel'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseWheelDown'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnMouseWheelUp'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnResize'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnStartDock'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnStartDrag'); DesignIntf.UnlistPublishedProperty(TYourFrameComponent, 'OnUnDock'); } RegisterSprigType(TYourFrameComponent, TComponentSprig); end; Hope this helps!
--jeroen






Leave a comment