1. Tech

Your suggestion is on its way!

An email with a link to:

http://delphi.about.com/od/beginners/l/aa070203c.htm

was emailed to:

Thanks for sharing About.com with others!

Making Forms Work - a Primer
Page 3: Showing Non-modal forms - making them visible and bringing to the front of other forms on the screen.
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• Page 1: the Form, the Life
• Page 2: Modal forms
• Page 4: Tidy Habits!
 Join the Discussion
"Post your views and comments to this chapter of the free Delphi Programming Course"
Discuss!
 Related Resources
• A Beginner's Guide to Delphi Programming.TOC

• Delphi Project file (dpr)
• Working with forms
• Delphi forms - Life Cycle
• Owner vs. Parent

Ok, now we know how to add more forms to a Delphi (SDI) project, and even how to call a modal form, let's see how to call some of those forms in a non-modal fasion...

A Non-Modal Form
If the secondary form needs to be non-modal, use Show instead of ShowModal. We can't use exactly similar code because the form would show briefly, then disappear, because Release is called right after showing the form. To correct this problem use the code shown below:

procedure TfrmMain.cmdAddNewCustomerClick(Sender: TObject); 
var 
  f:TfrmAddNewCustomer ; 
begin 
  f := TfrmAddNewCustomer.Create(Self); 
  f.Show ; 
end; 

Then in the FormClose event for the Add New Customer form add the following (Action caFree frees up all resources for the form and destroys it):

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

Whoops, there is a slight problem with the code! Can you see the problem? Since the secondary form is non-modal the user can go back to the main form and press the Add button again. The program tries to create another Add New Customer form with unfortunate results if you have not planned for it! To prevent this from happening first check to see if the form object already exists. If so, simply show it; if not, create the form and then show it.

There are various ways to test for an object's existence, for example:

procedure TfrmMain.cmdAddNewCustomerClick(Sender: TObject); 
var 
  f:TfrmAddNewCustomer ; 
  iFound, 
  i:Integer ; 
begin 
  iFound := -1; 
  for i := 0 to Screen.FormCount -1 do 
  if Screen.Forms[i] is TfrmAddNewCustomer then 
    iFound := i; 
  if iFound >= 0 then 
  begin 
    ShowMessage('Add Customer form already created, will now show it') ; 
    Screen.Forms[iFound].Show ; 
  end
  else
  begin 
    ShowMessage('Add New Customer form not found, creating...') ; 
    f := TfrmAddNewCustomer.Create(Self) ; 
    f.Show ; 
  end; 
end; 

These methods give your program much better control of resources than auto-created forms, with very little hand-coding. There is a slight performance trade-off with dynamically created forms, but a delay is unlikely to be perceptible unless the called forms are very complex and/or your user has an unreasonably slow machine.

Caution: When defining forms for dynamic invocation you should be aware of the need to avoid any named reference to the properties of the object whose variable is declared in the interface section. That variable will never be assigned because the calling form uses its own local variable to invoke it. For example:

procedure TfrmAddNewCustomer.FormCreate(Sender: TObject); 
begin 
  frmAddNewCustomer.Top := Top + 12 ; 
end; 

Using our example, the reference to the variable frmAddNewCustomer would cause an access violation. The code below demonstrates how you need to work with properties of the secondary form

procedure TfrmAddNewCustomer.FormCreate(Sender: TObject); 
begin 
  Top := Top + 12 ; 
end; 

If for some reason you need an explicit reference to the form object, use the identifier Self in front of the property or method.

procedure TfrmAddNewCustomer.FormCreate(Sender: TObject); 
begin 
  Self.Top := Self.Top + 12 ; 
end; 

The variable in the interface section of can be safely removed if the form is intended only for dynamic invocation. It is scarcely worth doing, though, since it will be optimized out when the project is compiled.

For completeness, here is a method for showing a modeless form.

procedure TfrmMain.cmdAddNewCustomerClick(Sender: TObject); 
var 
  f:TfrmAddNewCustomer ; 
begin 
  with TfrmAddNewCustomer.Create(Self) do
  begin 
    Show; 
  end; 
end; 

Once you are finished using the form it can be destroyed by using the following code:

procedure TfrmMain.cmdCloseFormClick(Sender: TObject); 
var 
  f:TForm; 
begin
  f := TForm(FindComponent('frmAddNewCustomer')) ; 
  if f <> nil then 
    f.Release 
  else 
    ShowMessage('Failed to find it') ; 
end; 

All set. Ready to code ... read on and learn about some more from_the_battle_field situations...

Next page > Tidy Habits; Right Place, Right Time > Page 1, 2, 3, 4

A Beginner's Guide to Delphi Programming: Next Chapter >>
>> Communicating Between Forms

©2014 About.com. All rights reserved.