TForm.Create(AOwner) ... AOwner ?!?

When creating Delphi objects dynamically, that inherit from TControl, such as a TForm (representing a form/window in Delphi applications), the constructor "Create" expects an "Owner" parameter. Should you use "nil", "self" or "Application"? Find the answer here...

Suppose you have a form TMyForm in an application, and you want to instantiate it at run-time. The TForm class has a "Create" constructor that creates and initializes a new TForm (or descendant) object:

constructor Create(AOwner: TComponent) ;

The AOwner parameter is the owner of the T(Custom)Form object. The owner of the form is responsible for freeing the form (memory allocated by the form) when needed. What's more the form created appears in the Components array of its owner. Second, the form is destroyed automatically when its owner is destroyed. For forms, the latter is usually more important.
Should you provide "nil", "self" or "Application"?

To understand the answer, you first need to know the meaning of "nil", "self" or "Application":

  • nil - specifies that no object owns the form - and therefore a developer (you) is responsible for freeing the created form (by calling myForm.Free when you no longer need the form)
  • Self - specifies the object in which the method is called. If, for example, you are creating a new instance of a TMyForm form from inside a Button's OnClick handler (where this button is placed on a MainForm) - self refers to "MainForm". Thus, when the MainForm is freed - it will also free "MyForm".
  • Application - specifies a global TApplication type variable created when you run your application. "Application" encapsulates your application as well as providing many functions that occur in the background of the program.
Examples:
  1. Modal forms. When creating a form to be displayed modally and freed when the user closes the form, you use "nil" as the owner, as in:

    ~~~~~~~~~~~~~~~~~~~~~~~~~
    var
       myForm : TMyForm;
    begin
       myForm := TMyForm.Create(nil) ;
       try
         myForm.ShowModal;
       finally
         myForm.Free;
       end;
    end;
    ~~~~~~~~~~~~~~~~~~~~~~~~~

  2. Modeless forms. You can use "Application" as the owner here:

    ~~~~~~~~~~~~~~~~~~~~~~~~~
    var
       myForm : TMyForm;
    ...
       myForm := TMyForm.Create(Application) ;
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    Now, when you terminate (exit) the application, the "Application" object will free the "myForm" instance.

    Why and when is TMyForm.Create(Application) NOT recommended? If the form is a modal form (and will be destroyed "right away", as above) you should pass "nil" for the owner.
    You could pass "Application", but the problem with this code is the time delay caused by the notification method being sent to every component and form owned or indirectly owned by the Application. If your application consists of many forms with many components (in the thousands), and the form you're creating has many controls (in the hundreds), the notification delay can be significant.
    Passing nil as the owner instead of Application will cause the form to appear sooner, and will not otherwise affect the code.

  3. When to use "Self"? If the form you need to create is not modal and is not created from the application's main form, if you use Self as the owner, closing the owner will free the created form.

    In general, when creating new form instances, you should not use "Self", use "nil" or "Application" instead (modal/modeless).
    So when to use "self"? "Self" can be used, as the owner, if you don't want the form to outlive its creator.

Warning: if you want to dynamically instantiate a Delphi component and explicitly free it sometime later, always pass nil as the owner. Failure to do so can introduce unnecessary risk, as well as performance and code maintenance problems. Read the article to learn more.

Note: in SDI applications, when a user closes the form (by clicking on the [x] button) the form still exists in the memory - it only gets hidden. In MDI applications, closing an MDI child form only minimizes it.
The OnClose event provides an Action parameter (of the TCloseAction type) you can use to specify what happens when a user attempts to close the form. Setting this parameter to "caFree" will free the form.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
公历、农历互换组件 TransDate (DELPHI 7 转换日期1900 -- 2056)TransDate组件可将公历转换成农历,公历包括星座,星期。农历数据包含节气,干支历,生肖。也可将农历转换成公历,转换过程自动完成。即输入公历日期同时得到农历日期。输入农历日期同时得到公历日期。组件拖入窗口,无需运行在属性栏就可以直接完成公历、农历的互相转换。公历、农历互换组件完成公历和农历之间的互相转换,组件的属性如下:属性:LunarDate:TLunarDate;TLunarDate类由下列属性和方法组成属性:lDay:Word; 农历年的日。属性:lMonth:Word; 农历年的月。属性:lYear: Word; 农历年的年。属性:AnimalYear:String; 生肖年,只读。属性:cDat: String; 干支历日,只读。属性:cMonth:String; 干支历月,只读。属性:cYear:String; 干支历年,只读。属性:FeastOfLunar:String; 农历节日,只读。属性:FlagLeapMonth:Boolean; 如果为 True,当月为闰月,只读。属性:MaxMonthDays:Integer; 农历年当月的最大天数,只读。属性:SolarTerm:String; 节气,只读。方法:constructor Create(AOwner: TComponent); virtual;方法: destructor Destroy; override;方法: function GetMonthDays(LY, LM: Integer): integer; 由给出的年、月,返回农历当月的最大天数。属性 BookOfChange: Boolean;属性 BookOfChange 属性为 True 时,干支历以节气为基准。中国的八字批命中的四柱中使用的干支是以节气为基准划分年、月、日,和农历年的月有一些区别。如果你查农历的目的为了得到四柱干支,可以将这个属性设置为 True。以每年的立春为农历新的一年开始,以24个节气中的12个节气为月的第一天。BookOfChange 属性为 False,干支历以农历的年、月为基准,这和国家公布的农历相同。属性: Constellation: String;Constellation 为只读属性,返回当日的星座。属性 Date: TDate;公历的年、月、日。属性Feast: String;返回当日的阳历节日,当一天有多过一个的节日时,用空格分开。注:节日多以中国节日和世界节日为准,其中感恩节有两个,一个是美国的习俗在11月,一个是加拿大的习俗在10月。属性:ISO8601: Boolean;ISO8601 属性为 True 时,Week 属性的星期排列以星期一为每周的第一天。ISO8601为False时,Week属性的排列以星期天为每周的第一天。属性LeapMonth: Boolean;LeapMonth为True时如果当月是闰月,则设置农历的闰月。如果当月不是闰月,不做任何动作。属性:MaxMonthDays:Integer;返回公历年当月的最大天数。属性:Week:Integer;返回星期对应的数值,当ISO8601=True 时,星期一返回 1,星期天返回 7。当 ISO8601=False 时,星期天返回 1,星期六返回 7。属性:property LunarDateSeparator: TLunar_DateSeparator;定义农历字符串中间的间隔符号,缺省为“年”、“月”、“日”、“闰”。TLunar_DateSeparator定义如下:TLunar_DateSeparator = record sYear: string[2]; sMonth: string[2]; sDay: string[2]; sLeapMonth: string[2]; end;方法: constructor Create(AOwner: TComponent); override;方法: destructor Destroy; override;方法: procedure DateToLunarDate(sDate: TDate; var LD: TLunarDate);将公历转换成农历。一般情况不需调用这个方法,当Date或LunarDate不管哪一个日历发生变化时,对方跟随发生变化。方法: function LunarDateToDate(iDate: TLunarDate): TDate;将农历转换成公历。一般情况不需调用这个方法,当Date或LunarDate不管哪一个日历发生变化时,对方跟随发生变化。方法:function LunarDateToStr: string;将TLunarDate格式的农历转换成字符串形式,2004年10月10日。日历中间的分隔符号如年、月、日由属性LunarDateSeparator定义。方法:procedure StrToLunarDate(DateStr: string; var LD: TLunarDate);将字符串格式的农历转换成TLunarDate格式的农历。事件:OnChange;日历发生变化时促发该事件。为了测试TransDate组件,写了一个测试程序,可以从测试程序中得知如何使用TransDate组件。测试程序也是一个实用程序,可以直接使用。日历数据从1900年至2056年,其中1935年到2056年的数据进行过校验,前面的数据就懒得校验了。使用过程中有什么问题,请发Email (gzgzlxg@hotmail.com) 与我联系。节日:公历变动节日22个,固定节日129个。农历:14个。附全部组件源码,测试程序源码,和数据单元源码,和测试程序。打开测试程序前先安装TransDate组件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值