在窗体form1的unload事件中写:set form1=noting:end ,有意义吗?

kanzm 2009-08-11 04:49:19
在窗体form1的unload事件中写:set form1=noting:end ,有意义吗?
----------------------------------
对于只有一个窗体的程序,我发现有些网友在窗体的unload事件中这样写:

Private Sub Form_Unload(Cancel As Integer)
Set Form1 = Nothing
End
End Sub

估计作者的本意是,在窗体unload后,执行 set form1=nothing,然后执行 end,但是我认为这样写有问题:
1.在unload事件中写 set form1=nothing 不会起作用,因为此时窗体没有被unload,所以 set form1=nothing也不会生效.
2.此时执行end,会造成unload事件无法正常执行完毕,即没有执行unload,就会end了,此时会造成内存泄漏

我的理解不知对不对,请大家说说,谢谢.

...全文
651 107 打赏 收藏 转发到动态 举报
写回复
用AI写文章
107 条回复
切换为时间正序
请发表友善的回复…
发表回复
jp0077777 2009-08-14
  • 打赏
  • 举报
回复
.........
倒大霉的上帝 2009-08-14
  • 打赏
  • 举报
回复
我就“ggyy”,你“kanzm”
slowgrace 2009-08-14
  • 打赏
  • 举报
回复
“唧唧歪歪”这名字不错
zdingyun 2009-08-14
  • 打赏
  • 举报
回复
[Quote=引用 103 楼 slowgrace 的回复:]
kanzm和ggyy是同一个人?
[/Quote]
依我看,2个问贴内容完全一致,应该是同一人在两个论坛的提问.我提及此事是说明CSDN的VB板块远比VBGOOD热闹!
slowgrace 2009-08-14
  • 打赏
  • 举报
回复
kanzm和ggyy是同一个人?
vbman2003 2009-08-13
  • 打赏
  • 举报
回复
看了一下,如果你是直接用窗体的Name引用窗体的,就等于使用隐含全局变量。为了释放窗体占用的内存,必须把该变量设置为 Nothing。例如:
Set Form1 = Nothing

建议:专业编程人员都应避免使用隐含全局变量,而趋向于声明自己的窗体变量,例如:
Dim dlgAbout As New frmAboutBox



zdingyun 2009-08-13
  • 打赏
  • 举报
回复
LS的MSDN的Visual Basic 窗体的存活期引用使讨论进入正轨了.
http://topic.csdn.net/u/20080629/20/56fa3143-638d-4129-a2fc-c281b95b576d.html
参阅下去年我在CSDN的问贴"声明为窗体的局部变量,当该窗体被Unload,再加载该窗体,变量值维持Unload前值,如何解决?"的讨论,LS各位我想会有新想法.
vbman2003 2009-08-13
  • 打赏
  • 举报
回复
忙中偷闭查了一下MSDN,找到一点资料,比较忙,没时间细看,不过至少可以肯定,set form1=nothing并不是不可以用....某些时候或许很有必要,具体细节以后有时间再好好想想...
-------------------------------------------
Visual Basic 窗体的存活期

由于窗体和控件是可见的,所以它们与其它对象的存活期不同。例如,即使释放了对窗体的所有引用,也不会关闭该窗体。Visual Basic 维护整个工程所有窗体的全局集合,只有当窗体卸载时才能从集合中删除该窗体。

同样的,Visual Basic 为每个窗体维护一个控件集合。可以从控件数组中加载或卸载控件,但简单地释放对控件的所有引用并不能撤消它。

详细信息 有关窗体和控件集合的内容已在本章的“Visual Basic 中的集合”中以作了讨论。

Visual Basic 窗体经历的状态
通常地,Visual Basic 窗体在整个存活期中有四种状态:

创建,但不加载。


加载,但不显示。


显示。


内存和资源完全收回。
在一定环境下,窗体可有第五种状态:当其中有一个控件仍被引用时,窗体处于卸载和未引用状态。

本主题将描述这些状态及状态之间的转换。

创建,但不加载
Initialize 事件是该状态开始的标志。因而,放在 Form_Initialize 事件过程中的代码,就是窗体创建时最先执行的代码。

处于这种状态时,窗体是作为一个对象而存在,但还没有窗口。而且它的控件也不存在。虽然该状态可能很短暂,但任何窗体都要经过该状态。

例如,如果执行 Form1.Show,则窗体被创建,Form_Initialize 开始执行;一旦 Form_Initialize 执行完毕,该窗体被加载,这是下一个状态。

在指定窗体为启动对象时会发生同样的过程。在“工程”菜单中,选取“工程属性”对话框,然后选定“通用”选项卡,就可以指定一个窗体为启动对象。一旦窗体被指定为启动对象,该窗体在工程启动时就被创建,并立即加载和显示。

注意 正如下面描述的,通过调用窗体的 Show,或使用内置的属性和方法,都可以从 Form_Initialize 中加载窗体。

保持创建,但不加载的状态
相反的,以下的代码创建 Form1 的实例,但不让其进入加载状态:

Dim frm As Form1
Set frm = New Form1

一旦 Form_Initialize 结束,在不强制加载窗体的情况下,所能执行的过程只有能添加到该窗体代码窗口的 Sub、Function 和 Property 过程。例如,可以给 Form1 添加以下的方法:

Public Sub ANewMethod()
Debug.Print "Executing ANewMethod"
End Sub

使用变量 frm(也就是 frm.ANewMethod),可以在窗体不强制进入下一状态的情况下调用该方法。同样的,可以调用 ANewMethod 创建窗体:

Dim frm As New Form1
frm.ANewMethod

由于 frm 声明为 As New,所以直到代码中首次使用该变量之前,上述情况是调用 ANewMethod,该窗体不能创建。上面的代码执行后,该窗体保持在已创建状态,但没有加载。

注意 只要运行 Form1.ANewMethod,无需声明窗体变量,也可以达到上述示例的效果。正如“定制窗体类”中所解释的,Visual Basic 为每一个窗体类创建一个隐含的全局变量。该变量名和类名相同,这可想象为 Visual Basic 进行了 Public Form1 As New Form1 声明。

可以在不加载窗体的情况下,任意运行定制的属性和方法。然而,一旦访问了窗体内置的任一属性或控件,该窗体就进入下一状态。

注意 把一个窗体分为两部分是非常有用的,一部分是代码部分,另一部分是可视部分。窗体加载前,只有代码部分在内存中。这样,可以不加载窗体的可视部分,而在代码中任意调用过程。

所有窗体都需经过的唯一状态
创建完毕但未加载,是所有窗体都需经过的唯一状态。如果上述示例中变量 frm 被设置为 Nothing,则该窗体在进入下一状态前就撤消了:

Dim frm As New Form1
frm.ANewMethod
Set frm = Nothing '窗体被撤消。

这样使用的窗体不会比类模块好,所以绝大部分窗体进入下一状态。

加载但不显示
Load 事件标志着此状态的开始。一旦窗体进入加载状态,Form_Load 事件过程中的代码就开始执行。

Form_Load 事件过程开始后,窗体上的所有控件都被创建和加载,而且该窗体有了一个窗口─ 是通过窗口句柄 (hWnd) 和设备描述体 (hDC) 完成的,尽管该窗口还未被显示。

任何窗体只有加载后才能可见。

很多窗体自动从创建但不加载状态进入加载但不显示状态。窗体如果满足以下的条件就会自动加载:

该窗体在“工程属性”对话框的“通用”选项卡中被指定为启动对象。


窗体中首先被调用的属性或方法是 Show 方法,正如示例 Form1.Show。


首先被调用的窗体属性或方法是窗体内置的成员,如上述例子中是 Move 方法。
注意 因为每个控件定义了窗体的一个属性,所以这种情况包括了窗体的所有控件;也就是说,为了访问 Command1 的 Caption 属性,就必须经过窗体的 Command1 属性:Command1.Caption。

正如早些时候所述的,可以用 Load 语句加载窗体,而无需首先使用 New 或 As New 创建该窗体。
从不显示的窗体
上述的前两种情况,一旦 Form_Load 执行完毕,窗体就直接可见。而后面的两种情况,窗体将保持加载状态,但不显示。

在 Visual Basic 中编程时,常常加载了某一窗体但从未予显示。这样做有以下的原因:

用时钟控件产生计时事件。


用功能控件,而不是用户界面控件。例如,串行通信或访问系统文件。


执行 DDE 事务。
注意 对于 VBP 和 VBE,可以创建 ActiveX 部件(以前称为OLE服务端),这比控件更有利于提供纯代码功能。请参阅《部件工具指南》中的“创建 ActiveX 部件”。

总是返回的根状态
任何时候,只要隐藏了窗体,它就总是从可见状态回到加载状态。回到加载状态并不重新执行 Load 事件。Form_Load 在窗体的存活期中只运行一次。

显示状态
一旦窗体可见,用户就能和它交互作用。当然,窗体在卸载前可以任意隐藏及显示。

其它事项:卸载前的准备
窗体在卸载时可以是隐藏的,也可以是可见的。若没隐藏,则它将保持可见直到卸载完毕。

窗体卸载前最后发生 Unload 事件。该事件发生前,有另一个重要的事件发生,即 QueryUnload。QueryUnload 提供了停止窗体卸载的机会。如果某些数据希望保存,则此时将提示保存或忽略所做的更改。

重点 把 QueryUnload 的参数 Cancel 设置为 True,就会忽略 Unload 语句,从而不卸载窗体。

QueryUnload 事件的一个重要功能是还要了解窗体的卸载是什么原因造成的:是单击“关闭”按钮,或是程序中执行 Unload 语句,或在应用程序中关闭,或者是在 Windows 中的关闭。所以 QueryUnload 提供了取消关闭窗体的机会,同时也允许在需要时从代码中关闭窗体。

重点 在一些情况下,窗体不会接收到 QueryUnload 事件。例如,使用了 End 语句来结束程序,或在开发环境中单击“结束”按钮(或从“运行”菜单中,选取“结束”按钮)。

详细信息 请参阅《语言参考》的“QueryUnload 事件”。

返回到创建但不加载状态
窗体卸载后,Visual Basic 把它从 Forms 集合中删除掉。除非使用变量保持对窗体的引用,否则该窗体将被撤消,其所占内存和资源会被 Visual Basic 收回。

如果使用变量保持了对窗体的引用,例如“定制窗体类”中描述的隐含全局变量,窗体就会回到创建但不加载状态。窗体的窗口、控件不再存在。

对象将继续占有资源和内存。所有窗体代码部分模块级变量中的数据继续存在(但是,事件过程中的 Static 变量将消失)。

可以使用已有的引用调用窗体中所添加的方法和属性。但如果调用了内置的成员,或访问其控件,该控件将再次加载,并执行 Form_Load。

完全释放内存和资源
释放内存和资源的唯一办法就是卸载窗体,并把所有引用设置为 Nothing。这种做法常常会漏掉那些隐含的全程变量引用。如果使用了类名(正如“属性”窗口中的 Name 属性所示)来引用窗体,就等于使用隐含全局变量。为了释放窗体占用的内存,必须把该变量设置为 Nothing。例如:

Set Form1 = Nothing

该窗体在撤消前会接收到 Terminate 事件。

提示 很多专业编程人员都避免使用隐含全局变量,而趋向于声明自己的窗体变量(例如,Dim dlgAbout As New frmAboutBox)。

注意 执行 End 语句将卸载窗体并把所有的对象变量设置为 Nothing。然而,这种中断程序的方法非常唐突。所有的窗体都不会发生 QueryUnload、Unload 或 Terminate 事件,所创建的对象也不会发生 Terminate 事件。

卸载未被引用,但有控件仍被引用
为了进入这一状态,就必须在卸载和释放窗体时保持对其中某一控件的引用:

Dim frm As New Form1
Dim obj As Object
frm.Show vbModal
'模态窗口解体,保存对其上一个控件的引用。
Set obj = frm.Command1
Unload frm
Set frm = Nothing

尽管窗体已卸载,则对它的所有引用就释放。但只要还引用了其中的一个控件,其代码部分将仍然保存在内存中。一旦调用该控件的任一属性或方法,该窗体将被再次加载:

obj.Caption = "Back to life"

模块级变量将保留它们的值,但所有控件的属性被设置为缺省值,好象该窗体是首次加载一样。Form_Load 将被执行。

注意 在 Visual Basic 以前的有些版本中,窗体不能完整地重新初始化,Form_Load 也不会再次执行。

注意 并不是所有的窗体都象 Visual Basic 窗体。例如,Microsoft Office 中提供的 Microsoft Forms,就没有 Load 和 Unload 事件;一旦这些窗体接收到初始化事件,则它们所有的控件就开始存在,并可以使用。

详细信息 有关窗体的内容,在“窗体、控件和菜单”中的“设计窗体”及“创建用户界面”中的“再论窗体”中都作了讨论。
捧剑者 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 aisac 的回复:]
引用 66 楼 vbman2003 的回复:
Nothing 的作用是将对象变量从实际对象中分离开来。目的是释放与被引用的对象有关联的内存资源及系统资源。

根据对象变量声明的方法,对象变量nothing的结果会二有类:
1.
dim obj as object
set obj=new object
set obj=nothing
这个nothing的结果,obj从实际引用的对象中分离出来,同时释放了资源

2.
dim obj as new object
set obj=nothing
这个nothing的结果,obj不能从实际引用的对象中分离,但它释放了资源,从而重新初始化了obj

Form1是一个隐含的全局的用new声明的对象变量,所以我觉得,在一个窗体Unload事件中,用Set Form1 = Nothing或许是个不错的方法....


set obj = nothing 只是做引用计数-1,而析构过程并不是它调用的。所以下面这段代码并没有重新初始化的过程。

VB codedim newfrmasnew form1set newfrm=nothing

一直隐隐感觉在form_unload 下写set form1 = nothing 与下面的代码如出一辙,所以不是什么好的方式。
VB codeprivatesub form_load()
form1.btnTest.caption="&Test"end sub
[/Quote]同意。
捧剑者 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 69 楼 tiger_zhao 的回复:]
引用 48 楼 slowgrace 的回复:引用 42 楼 tiger_zhao 的回复:
我其实要表达的意思是:在 Form2 内强制限定自己的实例肯定持有在全局变量 Form2 中,这对多实例的使用留下了隐患。

这话没看懂啊
按照13楼的方式写了下面的代码。
VB code'Form1OptionExplicitPrivateSub Command1_Click()Dim f1As Form'一个新的 Form2 实例作为对话框调用一下' Debug.Print"Command1_Click()","Step 1"Set f1=New Form2
f1.Show vbModalSet f1=Nothing'将全局 Form2 显示到前端' Debug.Print"Command1_Click()","Step 2"
Form2.ZOrderEnd SubPrivateSub Form_Load()
Debug.Print"Form1_Load()"
Form2.Show'全局 Form2 和 Form1 一起打开'End Sub
VB code'Form2OptionExplicitPrivate m_hWndAsLongPrivateSub Form_Load()
m_hWnd= Me.hWnd'为了在 Unload 之后使用' Me.Caption= Hex(m_hWnd)
Debug.Print"Form2_Load() :"& Hex(m_hWnd)End SubPrivateSub Form_Terminate()
Debug.Print"Form2_Terminate() :"& Hex(m_hWnd)End SubPrivateSub Form_Unload(CancelAsInteger)
Debug.Print"Form2_Unload() :"& Hex(m_hWnd)Set Form2=NothingEnd Sub
1)运行程序,显示两个窗体。
2)点击 Form1 上的 Command1,弹出模态的 Form2
3)关闭模态的 Form2,非模态的 Form2 没有显示到前端
“立即”窗口输出如下:
VB codeForm1_Load()
Form2_Load() : 250A86
Command1_Click() Step1
Form2_Load() : 120A48
Form2_Unload() : 120A48'这里调用了 Set Form2 = Nothing'Form2_Terminate() : 120A48
Command1_Click() Step2
Form2_Load() : 130A48'Form2.ZOrder 就重新创建了一个实例'
这就是隐患的一种表现。你还可以在各种情况下遇到各种预期的错误。
[/Quote]说的很对。
捧剑者 2009-08-13
  • 打赏
  • 举报
回复
75 楼 vbman2003 的回复:
是的AC,nothing是释放资源,我意思因此相当于重新初始化了Fom1,(确切的讲,就是置form1=空指针)并不是重新构析....对set Form1=nothing以后,forms集合中依然存在这个Form1.....(直到form1 unload)
神马都能聊 2009-08-13
  • 打赏
  • 举报
回复


现在有点儿忙,随后再解释自己的话
slowgrace 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 82 楼 vbman2003 的回复:]
引用 78 楼 slowgrace 的回复:
引用 66 楼 vbman2003 的回复:
Form1是一个隐含的全局的用new声明的对象变量,所以我觉得,在一个窗体Unload事件中,用Set Form1 = Nothing或许是个不错的方法....


不赞同。在单实例的情况下,Set Form1 = Nothing是多余的;在多实例的情况下,它会带来隐患。

关于隐患,你看69楼的例子,以及13楼+21楼+57楼(这3楼构成一个完整的例子)+62楼(是对这个例子的解释)。


我好几天没来了,没弄错的话,这个贴子的主题应该是关闭一个应用程序吧?不然怎么会讨论end?
对于结束应用程序,大家都明白,通过释放对所有对象的引用来释放部件是个良好的编程习惯,那么Set Form1 = Nothing为什么多余?
[/Quote]

恩,如果是想非正常终止程序,这一句也许有点用。

单窗体正常终止程序的话,它就多余。不管怎样,我都觉得这句话有点危险。我说的那两个例子你试试就知道了。
捧剑者 2009-08-13
  • 打赏
  • 举报
回复
引用 66 楼 vbman2003 的回复
Nothing 的作用是将对象变量从实际对象中分离开来。目的是释放与被引用的对象有关联的内存资源及系统资源。

根据对象变量声明的方法,对象变量nothing的结果会二有类:
1.
dim obj as object
set obj=new object
set obj=nothing
这个nothing的结果,obj从实际引用的对象中分离出来,等到引用计数为0时释放了资源

2.
dim obj as new object
set obj=nothing
这个nothing的结果,与上面效果完全一样

Form1是一个隐含的全局的用new声明的对象变量,所以我觉得,在一个窗体Unload事件中,用Set Form1 = Nothing肯定是个不好的方法....
vbman2003 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 81 楼 slowgrace 的回复:]
另外,我还想称呼你vbman。
[/Quote]

呵呵,称呼随便你啦....不就是代号吗?什么003 007 008随便只要我一看就知道是点我名就行......
vbman2003 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 78 楼 slowgrace 的回复:]
引用 66 楼 vbman2003 的回复:
Form1是一个隐含的全局的用new声明的对象变量,所以我觉得,在一个窗体Unload事件中,用Set Form1 = Nothing或许是个不错的方法....


不赞同。在单实例的情况下,Set Form1 = Nothing是多余的;在多实例的情况下,它会带来隐患。

关于隐患,你看69楼的例子,以及13楼+21楼+57楼(这3楼构成一个完整的例子)+62楼(是对这个例子的解释)。
[/Quote]

我好几天没来了,没弄错的话,这个贴子的主题应该是关闭一个应用程序吧?不然怎么会讨论end?
对于结束应用程序,大家都明白,通过释放对所有对象的引用来释放部件是个良好的编程习惯,那么Set Form1 = Nothing为什么多余?
slowgrace 2009-08-13
  • 打赏
  • 举报
回复
另外,我还想称呼你vbman。
slowgrace 2009-08-13
  • 打赏
  • 举报
回复
V3,其实,我觉得这一切症结在于,我们要深深地记住Form1它是一个变量,一个名为Form1的窗体类型的对象变量!

想想在类模块里对一个全局对象变量设置nothing有多不合理,你就知道你刚才觉得不错的想法有多不合理。因为这个语句会被这个类的每个实例调用!
vbman2003 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 77 楼 slowgrace 的回复:]
心虚地问V3,难道你看懂AC最后一段代码在说啥么?我怎么觉得他的文字和代码不匹配啊?
[/Quote]
呵呵,我也没看懂...
slowgrace 2009-08-13
  • 打赏
  • 举报
回复
[Quote=引用 66 楼 vbman2003 的回复:]
Form1是一个隐含的全局的用new声明的对象变量,所以我觉得,在一个窗体Unload事件中,用Set Form1 = Nothing或许是个不错的方法....
[/Quote]

不赞同。在单实例的情况下,Set Form1 = Nothing是多余的;在多实例的情况下,它会带来隐患。

关于隐患,你看69楼的例子,以及13楼+21楼+57楼(这3楼构成一个完整的例子)+62楼(是对这个例子的解释)。
加载更多回复(87)

7,764

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧