The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,862 other subscribers

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.:

  1. the components on the frame are locked when you put that frame control on a form or other frame
  2. 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 a spring. 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

This site uses Akismet to reduce spam. Learn how your comment data is processed.