Delphi – Frames as visual Components – don’t forget your Sprig!
Posted by jpluimers on 2009/07/16
I have been using Delphi Frames as visual components for quite some time now.
They make it really easy to use the Delphi IDE to visually design your component.
This makes the development process for creating visual components much easier and faster.
There are some things you need to watch when doing this, so I’ll devote a few blogs posts on this topic over the next couple of months.
A few of the things are:
- 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
Visible
property is ignored at design time. - You need to watch resizing.
- Frames do not have
OnCreate
andOnDestroy
events. - Error messages about a missing
ClientHeight
property. - You can still drop other components on your frame.
- … probably some more that I forgot right now…
The first blog on this series is about the first issue:
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 bad thing about this is that you can now delete the components on the frame using the structure pane.
This leads to all sorts of problems (mostly access violations).
When I’m in component trouble, I usually ask my long time friend [Wayback/Archive] Ray Konopka who has been publishing and speaking about Delphi component creation a lot.
This time I asked him at the [Wayback] Delphi Live conference, so he invited me to his session about [Wayback] Creating Composite VCL Controls.
Since that didn’t clash with any of my [Wayback] scheduled talks, I already decided to go to his talk anyway, so I was anxious to see his solution.
Edit 20211220: Ray also explains the below in the thread [Wayback/Archive] Visual [Compound] Component Design with TFrame [Edit] – public.delphi.vcl.writing.
Back home, I found out he already wrote about this problem in a CodeGear Delphi forum posting earlier this year.
The trick is to call RegisterSprigType
for your frame class, registering TComponentSprig
.
A Sprig is what tells the Structure Pane how to behave: TComponentSprig
makes it behave as it would do for normal components in stead of frames.
When you know it, it is dead simple.
A quick sample registering TMyFrameComponent
is below.
Since both RegisterSprigType
and TComponentSprig
are in the TreeIntf
unit, you need
- The
TreeIntf
unit in youruses
list. - The
DesignIDE
package in your required packages list - Your Registration to be in a design-time package (which is should be anyway).
So here is the code, centralizing the logic in the RegisterFramesAsComponents
method, which works analogous to the RegisterComponents
method from the Classes
unit:
{$I Defines.inc} unit ComponentsRegistrationUnit; interface procedure Register; implementation uses Classes, TreeIntf, MyFrameComponentUnit; type TFrameClass = class of TFrame; 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; procedure Register; begin RegisterFrameAsComponents('bo', TMyFrameComponent); end; end.
Delphi Komponenten mit dem Formular-Designer entwerfen - Seite 2 - Delphi-PRAXiS said
[…] […]
Ken Knopfli said
Wow, the code is in a TINY font in FireFox!
jpluimers said
Now that is odd; can you post a screen shot?
I tested it with FireFox 3.0.11 on Windows XP, the screenshot is at my Flickr site.
–jeroen
Ahmet said
Doesn’t that cause the frame to lose its some behaviours like redesignablety of subcomponents in it ?
And is it possible to show additional properties of it on object inspector with that way ?
(http://stackoverflow.com/questions/289672/showing-tframe-descendants-additional-properties-on-the-object-inspector)
jpluimers said
That is indeed the whole point of making them components: they become fixed :-)
For me, redesignability freedom you see as an advantage of frames, is a big disadvantage: it allows to break your app with ease.
For instance, put an edit control on a frame, add that frame to a form, (save and) close the form, rename the edit on the frame then reload the form: boom!
Or another one: drop an edit on the frame, drop the frame on a form, move the edit on that form, (save and) close the form, move the edit on the frame, reopen the form: now the edit on the frame and the form are out of sync.
This gets worse when you are sharing a common set of frames within a project group containing multiple projects each having a truckload for forms.
How do you keep that in sync with your frames when you have so much design freedom?
Frames are great for adding new and shared functionality.
But in my experience, an average developer spends about 80% of his time in maintaining applications.
So I aim for maintainability: less degrees of freedom, which makes your 20% a bit more cumbersome and pays back in that 80% of your time.
Thanks for your link to the RegisterCustomModule call, I didn’t know that, so I’ll make sure to investigate a bit into that, and I’ll try to get back on it in a future posting.
For my reference a google search query to start investigating…
–jeroen