From my point of view, one thing that is really missing for Delphi/Lazarus is a better application’s form management. Two problems: an independent public variable is used to control an instance, and the ‘please place everything within the form’ approach. The first one requires the programmer to either create the form at the start of the application and not destroy it anymore, or it requires the programmer to create the forms and keep track of object destruction insuring that no variable points to a destroyed object. The second, among other problems, requires that the first one works perfectly so that the communication between forms can work.
When using the second approach there is not much work to be done. You either have to live with this limitation or write a new framework to go around it. Now, in order to maintain an up-to-date public variable, the programmer can benefit from the small tricks I will be describing here.
My suggestion to maintain an up-to-date public variable is to give it to a class method. This method takes care to create the form when this is necessary, and to update the variable when the form is destroyed. For this, implement the following method in the forms base class, in other words, the one from which all the forms will inherit:
TBaseForm = class(TForm) public class procedure Execute(var AForm; AModal: Boolean = False); end;
And implement the methods like this:
class procedure TBaseForm.Execute(var AForm; AModal: Boolean); var VIndex: Integer; begin if not Assigned(_Forms) then begin _Forms := TStringList.Create; _Forms.Sorted := True; end; if not _Forms.Find(ClassName, VIndex) then VIndex := _Forms.Add(ClassName); if TForm(AForm) = nil then Application.CreateForm(Self, AForm); _Forms.Objects[VIndex] := TObject(@AForm); if AModal then TForm(AForm).ShowModal else TForm(AForm).Show; end;
and make the public variable references nil the moment the form is destroyed:
destructor TBaseForm.Destroy; type PForm = ^TForm; var VIndex: Integer; begin if Assigned(_Forms) and _Forms.Find(ClassName, VIndex) and (_Forms.Objects[VIndex] <> nil) then begin PForm(_Forms.Objects[VIndex])^ := nil; _Forms.Objects[VIndex] := nil; end; inherited; end;
Finally, the StringList needs to be declared, and destroyed when the application is closed:
implementation var _Forms: TStringList = nil; ... initialization finalization _Forms.Free; end.
Done. The only thing needed is to create new forms that descend from this one and call TYourForm.Execute(YourForm). When the form is destroyed, the public variable will be assigned to nil.