Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


Tip of the Day
Language: Pascal
Expertise: Beginner
Mar 19, 1997

Avoiding MDI: Making a form a child of another form

Question:
How do I make a form a child of another form without having to resort to the overhead of MDI?

Answer:

MDI provides an easy and well-established way for developers to create applications in which one form can contain several forms in a Parent-Child relationship. But because MDI is so well-defined, it takes up a lot of resources. Especially in the case where you want to create a child form for the express purpose of being a tool bar of sorts, carrying the MDI along for just this purpose can be a bit of a waste of resources. But there is a work-around for it.

All Delphi forms inherit a very useful method from TWinControl called CreateParams. You can override this method to achieve various behaviors in the way a form diplays when it's created. Without going into a lot of esoteric Windows API lingo, CreateParams initializes a TCreateParams structure that contains generic base values defining a window's appearance. The record structure is listed below:

type  
  TCreateParams = record
    Caption: PChar;
    Style: Longint;
    ExStyle: Longint;
    X, Y: Integer;
    Width, Height: Integer;
    WndParent: HWND;
    Param: Pointer
    WindowClass: TWndClass;
    WinClassName: array[0..63] of Char;
  end;

We won't go into any detail about this structure because it's beyond the scope of this discussion. I'll leave it up to you to peruse the online help for a detailed discussion of the topic. However, note that there are several things you can change in the structure itself. With respect to our current discussion, to achieve our desired result of having a form be the child of another form, we'll manipulate this structure within our CreateParams method.

It's actually a fairly trivial thing to make a form act as a child form. All we have to do is the following:

  1. Create the form with a Child window style
  2. Notify Windows that the form has a new parent
  3. Notify Delphi that the form has a new parent

It couldn't get easier than this. Here's the code for the method that accomplishes the steps above:

unit child;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TChildForm = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
  private
    procedure CreateParams(var Params : TCreateParams); override;
  public
    { Public declarations }
  end;

var
  ChildForm: TChildForm;

implementation

{$R *.DFM}

procedure TChildForm.CreateParams(var Params : TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do begin
    {Set the Child's style to WS_CHILD}
    Style := (Style OR WS_CHILD) AND NOT WS_POPUP;
    X := 50;
    Y := 50;
    Width := 200;
    Height := 150;
    {Let Windows know about the relationship}
    WndParent := Application.MainForm.Handle;
  end;
  {Let Delphi know about the relationship}
  Parent := Application.MainForm;
end;

procedure TChildForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TChildForm.Button1Click(Sender: TObject);
begin
  ShowMessage('Hello world!!!');
end;

end.

Nothing really complex about that, right? All I did with the TCreateParams structure was to set the window style to WS_CHILD so the window is created a child, then set the parent-child relationship with a couple of assignment lines. With this sample, I simply embedded a TButton on the form to display the obligatory test message Hello world!!! But you can make the form do practically anything you want. Also, note the FormClose method: I've set it so that the form is destroyed when it is closed. However, you can substitute the Action := caFree; with Action := caMinimize to mimic the behavior of an MDIChild form.

Since this is a fairly simple tip, I didn't include a sample application. However, if you want to create a test application to test this concept out, do the following:

  1. Create a new application in Delphi.
  2. Name the main form something like ParentForm to differentiate it from other forms.
  3. Using either the tool bar or File|New Form, create a new form.
  4. Insert the code above in the Child form as above.
  5. Insert a uses statement in the implementation of your MainForm and declare your child form's unit name.

Create a child form like this as you would normally create any other form. Here's some sample code from the main form of my test application:

procedure TForm1.Button1Click(Sender: TObject);
var
  ChildFrm : TChildForm;
begin
  ChildFrm := TChildForm.Create(Application);
  ChildFrm.Show;
end;

This is plain vanilla form creation, so there's nothing here that you don't already know how to do. In fact, if you look at all the code above, there's really nothing so complex that you couldn't have figured it out sooner or later by yourself.

You might be asking Of what use is this methodology? Well, besides toolbars, I use this technique for creating wizard-like programs. I also use it instead of using notebooks because sometimes my pages can get fairly complex. So to reduce resource utilization, I instead create a bunch of child forms that don't have any caption bars or borders and are maximized in the client area of the main form. As the user goes from page to page, the components embedded on the pages are created and destroyed on the fly. This may be a bit slower in comparison to having a notebook, but this technique is far less resource-intensive than using a notebook, which would load up all the components at run time.

DevX Pro
 
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date