Up to now I have ignored the issue of form creation. You know that when the form is created, you receive the OnCreate event and can change or test some of the initial form's properties or fields. The statement responsible for creating the form is in the project's source file:
begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.
To skip the automatic form creation, you can either modify this code or use the Forms page of the Project Options dialog box (see Figure 7.10). In this dialog box, you can decide whether the form should be automatically created. If you disable automatic creation, the project's initialization code becomes the following:
begin Applications.Initialize; Application.Run; end.
If you now run this program, nothing happens. It terminates immediately because no main window is created. The call to the application's CreateForm method creates a new instance of the form class passed as the first parameter and assigns it to the variable passed as the second parameter.
Something else happens behind the scenes. When CreateForm is called, if there is currently no main form, the current form is assigned to the application's MainForm property. For this reason, the form indicated as Main Form in the dialog box shown in Figure 7.10 corresponds to the first call to the application's CreateForm method (that is, when several forms are created at startup).
The same holds for closing the application. Closing the main form terminates the application, regardless of the other forms. If you want to perform this operation from the program's code, call the Close method of the main form, as you've done several times in past examples.
Regardless of the manual or automatic creation of forms, when a form is created, you can intercept many events. Form-creation events are fired in the following order:
OnCreate indicates that the form is being created.
OnShow indicates that the form is being displayed. Besides main forms, this event happens after you set the Visible property of the form to True or call the Show or ShowModal method. This event is fired again if the form is hidden and then displayed again.
OnActivate indicates that the form becomes the active form within the application. This event is fired every time you move from another form of the application to the current one.
Other events, including OnResize and OnPaint, indicate operations always done at startup but then repeated many times.
In Qt, the OnResize event won't fire as it does in Windows when the form is created. To make the code more portable from Delphi to Kylix, CLX simulates this event, although it would make more sense to tweak the VCL to avoid this odd behavior (a comment in the CLX source code describes this situation).
As you can see in the previous list, every event has a specific role apart from form initialization, except OnCreate, which is guaranteed to be called only once as the form is created.
However, there is an alternative approach to adding initialization code to a form: overriding the constructor. This is usually done as follows:
constructor TForm1.Create(AOwner: TComponent); begin inherited Create (AOwner); // extra initialization code end;
Before the call to the Create method of the base class, the properties of the form are still not loaded and the internal components are not available. For this reason the standard approach is to call the base class constructor first and then do the custom operations.
Up to version 3, Delphi used a different creation order, which has led to the OldCreateOrder compatibility property of the VCL. When this property is set to the default value of False, all the code in a form constructor is executed before the code in the OnCreate event handler (which is fired by the special AfterConstruction method). If you enable the old creation order, instead, the constructor's inherited call leads to the call of the OnCreate event handler. You can examine the behavior of the CreateOrd example using the two values of the OldCreateOrder property.
When you close the form using the Close method or by the usual means (Alt+F4, the system menu, or the Close button), the OnCloseQuery event is called. In this event, you can ask the user to confirm the action, particularly if there is unsaved data in the form. Here is an example of the code you can write:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if MessageDlg ('Are you sure you want to exit?', mtConfirmation, [mbYes, mbNo], 0) = mrNo then CanClose := False; end;
If OnCloseQuery indicates that the form should still be closed, the OnClose event is called. The third step is to call the OnDestroy event, which is the opposite of the OnCreate event and is generally used to de-allocate objects related to the form and free the corresponding memory.
To be more precise, the BeforeDestruction method generates an OnDestroy event before the Destroy destructor is called. That is, unless you have set the OldCreateOrder property to True, in which case Delphi uses a different closing sequence.
So, what is the use of the intermediate OnClose event? In this method, you have another chance to avoid closing the application, or you can specify alternative "close actions." The method has an Action parameter passed by reference. You can assign the following values to this parameter:
caNone The form is not allowed to close. This corresponds to setting the CanClose parameter of the OnCloseQuery method to False.
caHide The form is not closed, just hidden. This makes sense if there are other forms in the application; otherwise, the program terminates. This is the default for secondary forms, and it's the reason I had to handle the OnClose event in the previous example to close the secondary forms.
caFree The form is closed, freeing its memory, and the application eventually terminates if this was the main form. This is the default action for the main form and the action you should use when you create multiple forms dynamically (if you want to remove the windows and destroy the corresponding Delphi object as the form closes).
caMinimize The form is not closed but only minimized. This is the default action for MDI child forms.
When a user shuts down Windows, the OnCloseQuery event is activated, and a program can use it to stop the shutdown process. In this case, the OnClose event is not called even if OnCloseQuery sets the CanClose parameter to True.