The Form's HWND
is getting destroyed when you set the Position
. That also destroys all child HWNDs. The TreeView's HWND
has not been re-created yet when you read its Count
, which is why it reports 0. Calling TreeView.HandleNeeded
after setting the Position
forces the TreeView to re-create its HWND
immediately, which will re-load any TreeNodes that had beencached internally when the TreeView's HWND
was destroyed (but only if the TreeView.CreateWndRestores
property is True, which it is by default).
A TreeView stores its child nodes inside of its HWND
. Reading the Items.Count
merely asks the HWND
how many nodes it has, so if there is no HWND
then the Count
will be 0. TTreeView
does not keep its own list of TTreeNode
objects, it merely assigns them as user-defined data in the physical nodes themselves. When nodes are removed from the tree, TTreeView
frees the associated TTreeNode
objects. In the case of HWND
recreation, TTreeView
caches the TTreeNode
data and then re-assigns it back to new nodes when the HWND
is re-created. But again, it does not keep track of the TTreeNode
objects.
What TTreeView
could have done is store the current number of nodes during HWND
destruction, and then have Items.Count
return that value if the HWND
has not been re-created yet. But alas, TTreeView
does not do that. But you could implement that manually by subclassing TTreeView
to intercept the CreateWnd()
and DestroyWnd()
methods, and then write your own function that returns the actual Items.Count
when HandleAllocated
is true and returns your cached value if it is false.
If the Form is visible to the user then its HWND
(and the HWND
of its children) will be available, since a control is not visible without an HWND
, so Items.Count
will be available if the TTreeView
is visible to the user. If its HWND
is ever destroyed while visible, the VCL will re-create the HWND
immediately so the user does not see a missing control. However, if the Form (or TreeView) is not visible to the user when the HWND
is destroyed, the HWND
will not be re-created until it is actually needed when the Form/TreeView is made visible again.
Since you are forcing the Position
to always be poDesigned
at the time of Form creation, why not just set the Position
to poDesigned
at design-time? Otherwise, you can simply set the Position
before populating the TreeView instead of afterwards, at least:
procedure TForm1.FormCreate(Sender: TObject);
var
i, j: integer;
mn: TTreeNode;
begin
Position := poDesigned; // <-- here
for i := 1 to 10 do
begin
mn := TreeView1.Items.Add(nil, 'M' + IntToStr(i)); // <-- first call to Add() forces HWND recreation if needed
for j := 1 to 10 do
begin
TreeView1.Items.AddChild(mn, 'C' + IntToStr(j));
end;
end;
Beep;
Caption := IntToStr(TreeView1.Items.Count); // <-- correct value reported
end;
This happens in all versions of Delphi. This is simply how things work in the VCL.
On a side note, you should use Free()
instead of Release()
. Release()
is meant to be used only when a Form needs to Free()
itself, such as in an event handler, by delaying the Free()
until the Form becomes idle. Since the form is already closed and idle by the time ShowModal()
exits, it is safe to Free()
the Form immediately.