Câu hỏi của bạn không thực sự hữu ích, bởi vì - nói chung - không được khuyến khích để lưu trữ dữ liệu (hoặc các đối tượng trong trường hợp của bạn) trong điều khiển GUI. Xem thêm bình luận của David về cách thay đổi thiết kế của bạn.
Điều khiến câu hỏi đặt câu trả lời là sự khác biệt giữa hộp kết hợp là con của biểu mẫu trực tiếp và là con của một đứa trẻ khác trong biểu mẫu (khung của bạn trong trường hợp này). Rõ ràng, các mục combo box là bị phá hủy trước khi destructor của frame đó được gọi. Các lựa chọn thay thế rõ ràng để khám phá sau đó: ghi đè Frame.BeforeDestruction
, ghi đè Frame.DestroyWindowHandle
, ghi đè Frame.DestroyWnd
hoặc bắt WM_DESTROY
trong số bị ghi đè Frame.WndProc
, nhưng không ai trong số chúng được gọi trước khi các mục đã biến mất.
Điều tiếp theo cần thử là lặp lại điều này cho hộp tổ hợp. Nó chỉ ra rằng khi WM_DESTROY
đến tại hộp combo rằng các mục vẫn còn đó. Tuy nhiên, hãy cẩn thận khi bắt gặp thông điệp đó một cách vô cùng khi kiểm soát thực sự bị phá hủy, bởi vì VCL có thể tái tạo một hộp kết hợp thường xuyên. Thực hiện nó bằng một lớp xen cho TComboBox
, như sau:
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.
Bây giờ, để trả lời câu hỏi của bạn: "Đây có phải là một cách tốt hơn?"
Có, bởi vì nó đảm bảo sự hủy diệt của đối tượng ở cấp độ khung hình. Nói cách khác: bạn không cần phải nhớ để giải quyết vấn đề này cho mọi trường hợp một cách riêng biệt.
Và không có nó là không, bởi vì giải pháp này đòi hỏi rằng các đối tượng trong hộp kết hợp được phép được giải phóng trong bất kỳ hoàn cảnh nào hạn chế sử dụng đến một ranh giới phụ không cần thiết.
Vì vậy, câu trả lời này có hữu ích không? Vâng, nếu nó ngăn cản bạn sử dụng cách tiếp cận hiện tại của bạn, thì đúng vậy.
Bên cạnh đó, tôi cũng nhận thấy sự thay thế khác bằng cách thiết lập thuộc tính Parent
của khung để nil theo hình thức chứa OnDestroy
handler:
procedure TForm2.FormDestroy(Sender: TObject);
begin
Frame1.Parent := nil;
end;
Trong trường hợp này, bạn có thể yên tâm tiêu diệt các đối tượng được lưu trữ trong các combo trong khung hủy của khung. Nhưng giải pháp này thậm chí còn tồi tệ hơn so với hiện tại của bạn, bởi vì nó không phải là mô tả. Sau đó, Frame1.FreeComboObjects
là tốt hơn nhiều.
Lời khuyên của tôi là thay đổi thiết kế của bạn. Không có hộp combo sở hữu các đối tượng này. Hãy để khung sở hữu chúng trong bất kỳ vùng chứa nào bạn thích, ví dụ: 'TObjectList'. Sau đó, bạn có thể phá hủy thùng chứa đó trong trình phá hủy khung của bạn. –