Search code examples
delphicomponentstframe

How to improve the use of Delphi Frames


I've used frames in Delphi for years, and they are one of the most powerful features of the VCL, but standard use of them seems to have some risk such as:

  1. It's easy to accidentally move or edit the frame sub-components on a frame's host form without realising that you are 'tweaking' with the frame - I know this does not affect the original frame code, but it's generally not what you would want.

  2. When working with the frame you are still exposed to its sub-components for visual editing, even when that frame is years old and should not be touched.

So I got to thinking....

  1. Is there a way of 'grouping' components such that their positions are 'locked'? This would be useful for finished forms as well as frames. Often other developers return code to me where only the form bounds have changed and even they did not intend any change.

  2. Is there any way of turning a frame and its components into a single Delphi component? If so, the frame internals would be completely hidden and its useability would increase further.

I'm interested in any thoughts...

Brian.


Solution

  • 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;
    

    Hope this helps.

    --jeroen