二、由程序员用new的方法创建的窗体事件驱动链
在程序中无数次地见到过以下代码:
TfrmConstant *pForm=new TfrmConstant(this); //创建一个窗体
pForm->Show();
……
delete pForm;
我们经常需要动态创建一个Form,再显示它,然后在合适的地方销毁它。
请注意上面代码中的this参数,它被传送给TfrmConstant窗体的构造函数,这一构造函数有一个唯一的形参——Owner。这个参数决定了由谁负责销毁它。
在BCB的帮助文件中对Owner参数的描述如下:
Owner描述了谁负责销毁这个组件。
使用Owner参数来存取component所有者的接口。当一个组件拥有另一个组件时,当父组件内存被释放时,子组件所占的内存资源也被释放。这就是说,当一个窗体被销毁时,窗体上的所有组件也会被删除。
缺省情况下,一个窗体拥有放在其上的所有组件,同样地,Application对象则拥有所有的Form对象。这样,当程序结束时,Application对象会释放所有Form占用的资源。
下面是我对Owner参数的实验记录
实验一:主窗体(Form1)new一个普通窗体(Form2),Owner=this
Form1中的代码示例:
p2=new TForm2(this);
p2->Show();
创建:
先创建完主窗体后,只调用普通窗体Form2的构造函数,不管显不显示,事件驱动链与以前的实验一样。
关闭:
主窗体:OnCloseQueryàOnCloseàOnHide()àOnDestory()à主窗体析构函数àForm2析构函数
关闭次序是先主窗体再普通窗体,如果创建了多个普通窗体,根据创建的先后顺序按后创建先销毁的原则逐个销毁窗体:
普通窗体是显示还是隐藏对事件驱动链无影响
实验二:主窗体(Form1) new一个普通窗体Form2,Owner=Application
创建:
同实验一
关闭:
首先是Form1:OnCloseQuery()àOnClose()àForm2析构函数(如果有多个,按照后进先出的次序调用) àForm1:OnHide()àOnDestory()àForm1析构函数.
实验三:主窗体(Form1) new一个继承窗体(Form2继承自Form1),Owner=this
创建:
创建主窗体Form1,事件链同单窗体的创建;
接着在代码中开始new Form2:
Form2 OnCreate()àForm1的构造函数àForm2 的构造函数à创建结束
我们看到要先调用父类的构造函数
关闭:
1.Form2未显示:
Form1: OnCloseQuery()àOnClose()àOnHid()eàOnDestory()àForm1的析构函数
àForm2的析构函数à Form1的析构函数à Form2 OnDestory()
注意:并无Form1的OnDestory,同样地:Form1的析构函数被执行了两次
2.Form2显示情况下::
Form1: OnCloseQuery()àOnClose()àOnHide()àOnDestory()àForm1的析构函数
Form2 OnHide()à Form2的析构函数à Form1的析构函数à Form2 OnDestory
仅多了一个Form2 OnHide()过程
实验四:主窗体new一个继承窗体(Form2继承自Form1),Owner=Application:
创建(Form2不显示情况):
Form2 OnCreate()àForm1的构造函数à Form2的构造函数
关闭(Form2不显示情况)
Form1 OnCloseQuery()àOnClose()àForm2的析构函数à Form1的析构函数à Form2 OnDestory()àMainForm HideàMainForm的析构函数à MainForm 的析构函数
创建(Form2显示情况):
Form2 OnCreate()àForm1的构造函数à Form2的构造函数à Form2 OnShow()à ……à Form2:OnResize()
多了一个显示的事件
关闭(Form2显示情况)
Form1: OnCloseQuery()àOnClose()à Form2 :OnHide()àForm2的析构函数à Form1的析构函数à Form2 OnDestory()
àForm1 OnHide()àForm1 OnDestoryà MainForm1析构函数
三、MDI型应用程序事件发生次序
主窗体为MainForm,子窗体为MDIChild
创建
MainForm构造函数àOnCreate()à……à OnResize()
新建一个MDI子窗体时,Owner=Application或MainForm
MDIChild 构造函数àOnCreateàshowàActivate
关闭
Owner=Application时:
MDIChild OnCloseQuery()(有几个子窗体就执行几次)àMainForm OnCloseQuery()àMainForm OnClose()à MDIChild OnDestory()à MDIChild 析构函数àMainForm OnDestory()àMainForm析构函数
Owner=MainForm时:
MDIChild CloseQuery()(有几个子窗体就执行几次)àMainForm OnCloseQuery()àMainForm OnClose()àMainForm OnDestory()à MainForm析构函数à MDIChild OnDestory()à MDIChild 析构函数
显然,Owner参数决定了主窗体与MDIChild的析构次序。
有用的结论
从实验中我们可以得出一些有用的结论:
关于OnCreate和OnDestory事件:
1. Form的OnCreate事件是不可靠的,并不像名字所说的当窗体一创建时就执行,而是当窗体是工程的主窗体或是一个继承其它窗体的子窗体时才执行.所以,在OnCreate()中初始化变量和创建对象是不合适的;
2. 在有继承情况下,OnCreate事件先于构造函数发生,对应地OnDestroy事件后于析构函数发生。
关于窗体的构造函数和析构函数
1. 对于任何窗体,构造函数和析构函数是可靠的,因为它每一次创建和销毁窗体时都会执行。所以我们应在构造函数中进行程序的初始化操作,在析构函数中清理资源;而不要在OnCreate和OnDestory事件中进行处理;
2. 在继承情况下BCB子窗体对象的构造过程是先构造父窗体,再构造子窗体,这点与C++完全一样,销毁过程则反之;
3. 在有继承的情况下,父类窗体的构造函数和析构函数则会被执行多次,所以,在这两个地方不要new和delete对象,而应将这类代码放到具体的子窗体类中。如果不这样做,可能会由于多次删除同一对象而引发错误,除非将父类窗体的对象指针声明为static的,保证所有子类共享此new的唯一对象!
4.析构函数总是最后调用的,而构造函数总是第一个调用。
关于Owner参数:
当Owner=Application时,先销毁new出来的窗体,再销毁主窗体;
而当Owner=this(指主窗体)时,先销毁主窗体,再销毁子窗体;
这个原则对于在窗体内部动态地生成VCL控件时也适用。特别地,当程序中用到了数据模块,或需要动态地生成DataSet等对象时更要注意。因为一个DataSet可能会向多个窗体提供数据(应该避免这样做,合适的方法是new TDataSet时Owner参数不设为Application)。
其它:
1. 一个Visible=true的窗体一定要先Hide,才能被销毁。
2. 程序事件链的源头为工程中的主窗体的构造函数
3. 在有继承情况下,子类窗体实例一定要先Hide才可以被销毁。
4. 多窗体的管理BCB采用了栈的方法,按创建的次序,先创建的后销毁,千万要避免先创建的窗体含有对后创建的窗体(或其上的控件)的指针。
5. 关闭时一定会发生OnCloseQuery事件,如果是MDI,此事件还会在MDIChild窗体中传播,所以,在这个地方提示用户改变是合适的。
6. 有些事件一发生,则定然会跟着一系列的事件,这些事件发生的次序是不变的,比如,只要OnShow事件发生,则一定会接着发生以下事件:
àOnActivate()àOnCanResize()àOnConstrainedResize()àOnResize()
OnCloseQuery之后一定是OnClose()
相关推荐
BCB 阻止打开重复窗体
超星格式的。
DLL中的窗体和主程序进行交互显示信息
BCB 编写 如何控制 BCB 窗口 控件 透明部分 希望对大家有所帮助 C++BUILDER 编辑通过
c++ builder 6.0一个简单的窗体设计实例 可供初学者参考
BCB 窗体与控件 组件应用基础 常用事件 事件驱动编程(Event -Driven Programming)就是指通过对事件做出反应来进行编程 常用控件:单选钮和检查框 群组框和单选按钮组 列表框和组合框 等控件的属性方法及实例
bcb6做的特效窗体及图片切换示例 基于SmartEffects控件
BCB源代码:系统与窗体
c++ builder6 自定义形状窗体 图像图片窗体
C++Builder MDI 程序调用 DLL窗体实例。基于 BCB2010
参予过较大型项目的朋友应该有这样的体会:一个项目动辄上千个文件,各种窗体多达成百上千个,刚开始接触时常常得费老大的劲才能弄清某些窗体间的继承关系。为了更快地理清窗体之间的关系,我编了这个小东东。 为...
创建不规则窗体 // 设置窗口大小为图片大小 this->Width = Image1->Width; this->Height = Image1->Height; POINT *a; if((a=(POINT*)malloc(800*4*(sizeof(POINT))))==NULL) { ShowMessage("分配内存失败...
提取Delphi(BCB)编译的exe中窗体的例子
There are pointer to the digital image and prune BCB program.
bcb串口mscomm控件错误编译运行错误修复工具集合c++builder
There are two BCB program.One is Otsu + thinning the other is Otsu + sobel.
There are five BCB program include dialation, erosion,highboost,RGB image convert to YCbCr and lowpass LoG.
It is a BCB program for digital image by thinning method.
源代码……包含sql查询、更新、插入 删除等功能。 愿与大家分享!!
OPC bcb 程序代码(opc协议 opc-server)