Your question is not very useful, because - generally speaking - it is not recommended to store data (or objects in your case) in a graphical user interface control. See also David's comment on how to change the design.
Which makes the question respond to queries, although the difference between the combo box is a child of the form and is a descendant of another child of the form (in this case, your frame). Apparently, the elements with the list are destroyed before calling the destructor of this frame. Obvious search alternatives are: overriding Frame.BeforeDestruction , overriding Frame.DestroyWindowHandle , overriding Frame.DestroyWnd or intercepting WM_DESTROY in an overridden Frame.WndProc , but none of them are called before the elements have already disappeared.
The next thing to try is to repeat this for the combo box. It turns out when WM_DESTROY comes into the combo box that the items are still there. However, be careful to catch this message when the control is actually destroyed, because the VCL can often recreate the combo box. Implement it using the intermediate class for TComboBox as follows:
unit Unit2; interface uses Windows, Messages, Classes, Controls, Forms, StdCtrls; type TComboBox = class(StdCtrls.TComboBox) protected procedure WndProc(var Message: TMessage); override; end; TFrame1 = class(TFrame) ComboBox1: TComboBox; end; implementation {$R *.dfm} { TComboBox } procedure TComboBox.WndProc(var Message: TMessage); var I: Integer; begin if (Message.Msg = WM_DESTROY) and (csDestroying in ComponentState) then for I := 0 to Items.Count - 1 do Items.Objects[I].Free; inherited WndProc(Message); end; end.
Now, to answer your question: "Is this the best way?"
Yes, this is because it provides confidence in the destruction of an object at the frame level. In other words: you do not have to remember this for each case separately.
And no, this is not so, because this solution requires the objects in the combo box to be freed in any circumstances that limit the use of an unnecessary additional border.
So is this answer helpful? Well, if that is stopping you from using your current approach, then it is.
In addition, I also found another alternative by setting the frame Parent property to nil in the OnDestroy handler:
procedure TForm2.FormDestroy(Sender: TObject); begin Frame1.Parent := nil; end;
In this case, you can safely destroy the objects stored in the combo box inside the frame destructor. But this solution is even worse than your current one, because it is not descriptive. Then Frame1.FreeComboObjects much better.