The full title should be: What is the purpose of the OldCreateOrder property in a form and how does it affect my todays coding?, but it turned out to be too long for a catchy headline.
Probably you may already have wondered about that OldCreateOrder. It appears not only in forms, but also in some other classes, f.i. in a TDataModule. It was introduced in either Delphi 4 or Delphi 5 – (I can only say it was absent in Delphi 3, but present in Delphi 5).
Basically OldCreateOrder controls when the OnCreate and OnDestroy events are called. In case of a TCustomForm descendant, with OldCreateOrder = True the OnCreate is called inside TCustomForm.Create after the DFM is loaded, while with False the OnCreate is called after all inherited constructors are finished (i.e. in TCustomForm.AfterConstruction).
This has consequences for the way you code. Let me show you the difference with a simple example of a VCL form with a memo and a button. The memo contains some text entered at design time, which is saved in a TStringList instance during FormCreate. The TStringList is create in the constructor and destroyed in the destructor.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
type TMainForm = class(TForm) edtText: TMemo; btnReset: TButton; procedure FormDestroy(Sender: TObject); procedure btnResetClick(Sender: TObject); procedure FormCreate(Sender: TObject); private FDesignText: TStrings; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; |
A click on the button restores the text to the saved content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
constructor TMainForm.Create(AOwner: TComponent); begin inherited; FDesignText := TStringList.Create; end; procedure TMainForm.FormCreate(Sender: TObject); begin FDesignText.Assign(edtText.Lines); end; destructor TMainForm.Destroy; begin FDesignText.Free; FDesignText := nil; inherited Destroy; end; procedure TMainForm.FormDestroy(Sender: TObject); begin FDesignText.Clear; end; procedure TMainForm.btnResetClick(Sender: TObject); begin edtText.Lines := FDesignText; end; |
When you run this project with OldCreateOrder = False (the default), everything is working as expected (unless you are doing this with a really, really old Delphi version).
Let’s switch OldCreateOrder to True and try again: It will crash with a nil pointer reference in FormCreate.
If we recall what I have written above
with OldCreateOrder = True the OnCreate is called inside TCustomForm.Create
this was to be expected.
1 2 3 4 5 |
constructor TMainForm.Create(AOwner: TComponent); begin inherited; // <== here we call FormCreate FDesignText := TStringList.Create; end; |
The typical workaround in these old days, when OldCreateOrder was the only and standard behavior, was to move the TStringList creation before the inherited call. Luckily this approach works even when OldCreateOrder is False.
Of course, we could as well move the creation on the FormCreate event, but personally I dislike this approach – be it because it just doesn’t look clean to me.
Looking at the other side – Destroy and FormDestroy – things are quite similar, albeit the other way round. With OldCreateOrder = True, the FormDestroy is called inside the inherited call of Destroy, while with OldCreateOrder = False it is called before any destructor is executed.
So, whenever you see a pattern in creating instances before calling a constructors inherited and freeing after that in a destructor, you now know where this habit originates.
I think there is a copy/paste issue “Let’s switch OldCreateOrder to False and try again: It will crash with a nil pointer reference in FormCreate.” appears right below the paragraph where you say it works….I think it was supposed to be = True
Indeed! Fixed now. Thanks!