Almost done. After we have added two more forms to a Delphi (SDI) project, and have displayed some of them as modal, and modeless, we are ready for some real world situations (and solutions).
Tidy Habits
Use FindComponent to determine if the form exists or not. FindComponent returns an object (if it exists) of type TControl. Since the desired type is TForm, we typecast FindComponent's result to cast the object as TForm and assign a TForm variable to grab the result. Theoretically, if FindComponent returns Nil, the form does not exist - or does it?
Try placing the two procedures above into a main form. Provide a command button named 'CmdAddNewCustomer' to create the form. Provide another command button 'CmdCloseForm' to close the form. Compile and run the project. Click the 'CmdAddNewCustomer' button to create the form and then close it using the 'CmdCloseForm' button.
Now click "cmdAddNewCustomer" twice followed by click "cmdCloseForm" twice. On the first attempt the child form is found, then closed, the second attempt fails! To get around this problem a unique name needs to be assigned to the child form. Select a meaningful name and append an integer to the end of the name i.e.
'AddCustomer_' + IntToStr(iForm) ;
The variable iForm would be a private variable of frmMain which you would initialize during the OnCreate event of frmMain. Here is the altered code for creating the subsidiary form:
procedure TfrmMain.Button1Click(Sender: TObject);
var
f:TfrmAddNewCustomer ;
begin
Inc(iForm) ;
with TfrmAddNewCustomer.Create(Self) do begin
Name := 'AddCustomer_' + IntToStr(iForm) ;
{The caption will be the name
of the form given above}
Show ;
end ;
end;
|
On the first call to this event iForm would be zero, then directly before creating the form we use Inc to increment iForm to one. This gives the next invocation of the form a name of AddCustomer_1, which can be used later to remove any instances of the form:
procedure TfrmMain.cmdCloseFormClick(Sender: TObject);
var
f:TForm;
i:Integer;
begin
for i := 1 to iForm do begin
f := TForm(FindComponent('AddCustomer_' + IntToStr(i))) ;
if f <> nil then
f.Release
else
MessageDlg('Failed to locate AddCustomer_' +
IntToStr(i),mtError,[mbOk],0) ;
end;
end;
|
Right Place, Right Time
One more benefit from creating forms dynamically is the ability to position a secondary form precisely, relative to a control on the parent form.
Suppose you need to position the Add New Customer form directly on a node in a TreeView displaying accounts. In this example the Add form is displayed when the user double clicks on the TreeView. First place a TreeView on a main form in a project, select the TreeView, press F11 for the Object Inspector, select the property "Items" and double click the left mouse button. Add several new items and sub-items (optional). Finish up by pressing the "OK" button.
Next, select the Events page of the Object Inspector while the TreeView is still selected. Double click on the event OnDblClick and enter the following code (which I shall explain in another article):
procedure TfrmMain.TreeView1DblClick(Sender: TObject);
var
A,
R,
P : TPoint;
TheSelectedNode : TTreeNode;
f:TfrmAddNewCustomer ;
begin
if TreeView1.Selected = nil then Exit;
GetCursorPos(P);
A := TreeView1.ScreenToClient(P);
TheSelectedNode := TreeView1.GetNodeAt(A.x, A.y);
if TheSelectedNode = nil then
raise Exception.Create('Please click on an Item in the TreeView!');
GetCursorPos(R) ;
P := ClientToScreen(Point(A.x,A.y));
f := TfrmAddNewCustomer.Create(Self) ;
try
f.Top := R.y ;
f.Left := R.x ;
f.Caption := 'Add customer to account: "' + TheSelectedNode.Text + '"' ;
f.ShowModal ;
finally
f.Release ;
end;
end;
|
Run the project. Select a node in the TreeView and double click the left mouse button. The secondary form should appear with its top left corner positioned on the node which was double clicked. Its caption identifies the item selected in the TreeView. If you had centered the form on the screen, the specific information concerning the item selected in the TreeView would not be accessible. Again, dynamic creation of forms can be of great service to you!
I hope this chapter has given some insight into the techniques Delphi puts at your disposal for taking control of form creation and behaviour when developing SDI forms. Next time, more on working with forms. Until then, have fun!
Some exercises for you...
What happens when you call (create) a non modal Form3 from Form2, and after that call (create) Form2 from Form3?
To the next chapter: A Beginner's Guide to Delphi Programming
This is the end of the fourteenth chapter, in the next chapter, we'll deal with retrieving user input or other data from a secondary form.
If you need any kind of help at this point, please post to the Delphi Programming Forum where all the questions are answered and beginners are treated as experts.
First page > Where it all starts > Page 1, 2, 3, 4
A Beginner's Guide to Delphi Programming: Next Chapter >>
>>
Communicating Between Forms