声明为窗体的局部变量,当该窗体被Unload,再加载该窗体,变量值维持Unload前值,如何解决?
FORM1窗体代码:
Private Sub Command1_Click()
    Form2.Show
End Sub
FORM2窗体代码:
Option Explicit
    Dim a As IntegerPrivate Sub Command1_Click()
    a = a + 1
    Text1 = a
End SubPrivate Sub Form_Load()
    Text1 = a
End SubPrivate Sub Form_Unload(Cancel As Integer)
    Unload Form2
End Sub

解决方案 »

  1.   

    虽然不知道楼主想干什么要让局部变量完成全局变量的功能,我觉得可不可以把a的值传到外部文件中保存?load时再把a的值传进来。
      

  2.   

    哈哈哈,新建一个模块,声明一个全局变量Ga,然后在UnLoad前将局部变量的值赋值给Ga。然后加载时,再把Ga的值赋给a。是想要这种答案么?我想不是。呵呵
      

  3.   

    To:superleo_007
    我就是需在工程的某个窗体使用模块级局部变量,但该窗体在运行中需不断地被Unload,且不断地再次load,但观察发现该变
    量保留Unload前的值.只有工程初次运行时变量的原值为0.
    一个变量我可在该窗体加载的初始化中处理,但变量较多,处理就麻烦了.
    这也与MSDN的解释不符合:
    Load 事件
    此事件是在一个窗体被装载时发生。当使用 Load 语句启动应用程序,或引用未装载的窗体属性或控件时,此事件发生。
    语法
    Private Sub Form_Load( )说明
    通常,Load 事件过程用来包含一个窗体的启动代码—例如,指定控件缺省设置值,指明将要装入 ComboBox 或 ListBox 控件等的内容,以及初始窗体级变量等。
      

  4.   

    我自己的解决方法:
    Option Explicit
        Dim a As IntegerPrivate Sub Command1_Click()
        a = a + 1
        Text1 = a
    End SubPrivate Sub Form_Load()
        a = 0
        Text1 = a
    End SubPrivate Sub Form_Unload(Cancel As Integer)
        Unload Form2
    End Sub
      

  5.   

    楼上各为,我贴出的代码,你们运行过吗?
    既然是窗体级局部变量,那么Unload该变量所在窗体,内存中已没有该窗体及其变量的痕迹,似乎再次load该变量所在窗体,内存中仍保留原来的痕迹.
      

  6.   

    Private Sub Form_Unload(Cancel As Integer)
        'Unload Form2
        Set Form2 = Nothing
    End Sub
      

  7.   

    如果你不想保留原来值,在form_load时重新初始变量,如果想保留,就像你现在这样.
    vb工程中窗体在工程加载的时候就已经被分配到内存,unload仅使其不能被操作,不代表其已经在内存中被移除,只有在工程运行结束后,窗体才被移除,窗体级变量也同窗体一样道理.用9楼的办法也可以达到楼主的要求,但再次show该窗体时,该窗体中的控件都被清掉,因为窗体中的控件就相当于窗体变量.
    举个简单例子说明:
    创建2个窗体,form1,form2,form1中有个command1控件
    Private Sub Command1_Click()
        form2.visible=true
        form2.show 0
    End Sub
    form2也有一个command1
    Private Sub Command1_Click()
        form2.unload
    End Sub
    一开始运行form1,点command1,form2就显示了,点form2中的command1关闭form2,再点form1中command1,form2又出现...
    从头到尾都没有用load form2,但form2一直能正确加载,为何?因为form2从工程运行一开始就被加载到内存,只是没有被触发任何事件而已.
      

  8.   

    楼上说:但再次show该窗体时,该窗体中的控件都被清掉,因为窗体中的控件就相当于窗体变量. 
    ==============================
    不对,其实只要form被unload了,控件一定被释放了,但是窗体和窗体级变量仍在。
      

  9.   

    摘自msdn:
    如果使用变量保持了对窗体的引用,例如“定制窗体类”中描述的隐含全局变量,窗体就会回到创建但不加载状态。窗体的窗口、控件不再存在。
    对象将继续占有资源和内存。所有窗体代码部分模块级变量中的数据继续存在(但是,事件过程中的 Static 变量将消失)。
      

  10.   

    更详细的: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 事件;一旦这些窗体接收到初始化事件,则它们所有的控件就开始存在,并可以使用。详细信息 有关窗体的内容,在“窗体、控件和菜单”中的“设计窗体”及“创建用户界面”中的“再论窗体”中都作了讨论。
      

  11.   

    分析:
    Private Sub Command1_Click()
        Form2.Show
    End Sub
    楼主有没有想过 Form2 明明是个类名,为什么可以象对象一样进行 Show 调用?
    因为 VB 默认为窗体创建了一个同名实例,你可以看成在某个不可见的Module中,VB自动做了如下定义
    Public Form2 As New Form2那么为什么变量 a 的值会保留的原因也找到了:Unload 只是释放的 Windows 相关的句柄,全局对象 Form2 依旧保留着,那么对象内部的变量 a 的值也保留下很正常。解决方案1:释放全局变量
    'Form2 中
    Private Sub Form_Unload(Cancel As Integer)
        'Unload Form2 <- 窗体已经开始 Unload,所以——多次一举
        Set Form2 = Nothing
    End Sub解决方案2:不适用全局变量(推荐)
    'Form1 中
    Private Sub Command1_Click()
        Dim frm As Form2
        Set frm = New Form2
        frm.Show
    End Sub'Form2 中不需要 Form_Unload
      

  12.   

    看了上面的回答,我明白楼主的意思了,楼主真细心能发现这个问题,按照楼长高手的回答那VB做的程序不就有有一个问题了吗?就是说窗体的卸载仍有局部变量存在那会不会留下安全隐患呢?
    恕我愚钝,o(∩_∩)o...