<< Click to Display Table of Contents >> Navigation: Technology Overview > Forms and Modules > Other Forms > Application Form |
This is the auto-generated code for an Application Form (already renamed):
unit _AppForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, uniGUITypes, uniGUIAbstractClasses,
uniGUIClasses, uniGUIForm;
type
TAppForm = class(TUniForm)
private
{ Private declarations }
public
{ Public declarations }
end;
function AppForm: TAppForm;
implementation
{$R *.dfm}
uses
MainModule, uniGUIApplication;
function AppForm: TAppForm;
begin
Result := TAppForm(UniMainModule.GetFormInstance(TAppForm));
end;
end.
Instead of a variable like:
var
AppForm : TAppForm;
which is the standard code generated for a VCL form, the Wizard generated a function with the same name and type.
The original variable was global in scope, useless in a multi-user environment.
The new function request the instance from the session UniMainModule, automatically making the form local to each session.
But the function keeps the original intent of the VCL variable, each session will always access only one instance of that form (it is a singleton per session).
The function is also smart enough to manage the lifetime of the form:
•It will create the form if it doesn't exist
•If the form is closed, it will be freed and will get unregistered from the managed form list. (Property FreeOnClose = True)
•It will be returned immediately if it already exist.
uniGUI forms are dynamic objects and framework automatically allocates and disposes them. As described above each uniGUI application form is associated with a function which will create/return an instance of that form. Main purpose of providing this function was to provide syntax compatibility between VCL and uniGUI. In the VCL all of your forms are automatically created and all form global variables are initiated when your application is started. In VCL you can easily use your form by simply writing this simple syntax:
Form1.Show;
Likewise in uniGUI we have provided a handy syntax similar to above to allow you access your forms:
UniForm1.Show;
It must be reminded that in above code UniForm1 is a function not a variable. It returns the correct instance of Form for current session or it will create a new instance if an instance is not already created.
Let me restate that this function is provided to perform certain tasks only and it should not be treated as a global variable because it is not a variable in the first place.
This global function should must be used only when you want to instantiate and display a uniGUI form:
UniForm1.Caption := 'New Caption'; // A new form instance is created and Caption is assigned a new value
UniForm1.Show; // Show function is called for form instance created a previous line
Another important detail is that uniGUI forms must be shown as soon as they are created. It is not possible to create a form in one event and show it in another. If you attempt doing this uniGUI will automatically show the form if you do not call Show or ShowModal explicitly.
Incorrect usage:
procedure TMainForm.UniButton4Click(Sender: TObject);
begin
UniForm1.Caption := 'New Caption';
end;
Correct usage:
procedure TMainForm.UniButton4Click(Sender: TObject);
begin
UniForm1.Caption := 'New Caption';
UniForm1.Show; // Show must be called
end;
It must be avoided to to use a form instance inside a datamodule unless it is used to create and show that form as demonstrated above.
You must avoid accessing form's public variables from a datamodule or another form. All of these are against good OOP design rules anyway.
Forms must not be used to store application global variables or data components such as connections which will be used by other forms and datamodules. Each form must be considered as an atomic element of your application which will hold its own private variables for its own internal usage. If you want to define public variables for a session then you must MainModule or other datamodules for this purpose.
For instance in below code a label in a form is used to display a field data. As we stated above such usage of form must be avoided.
procedure TDataModule2.DataSource1DataChange(Sender: TObject; Field: TField);
begin
UniForm1.UniLabel1.Caption := Field.DisplayText; // incorrect usage, form function should not be directly used inside an event handler of a component which belongs to another form/module
end;
Instead you can resolve this by simply using a data aware control such as TUniDBText and connecting it to a data source.
Another solution to above problem is to place a TDataSource component directly on form and use its event to update form's visual elements.
Here rule of thumb is to avoid updating a form's visual elements from event handlers of other components which does not belong to that form.
The only exception to above rule is that when you are completely in control of a specific form's lifetime. i.e. you explicitly create and destroy it in your own code.