公共变量在表单中的VBA中并非真正公开

时间:2013-04-11 21:17:37

标签: vba scope

下面是一个我将自己回答的问题,但是它给我带来了极大的挫败感,我在网上搜索它时遇到了很多麻烦,所以我在这里发帖是为了节省一些时间和时间。为别人付出的努力,如果我将来忘记这一点,也许对我自己:

对于VBA(在我的情况下,MS Excel), Public声明应该使变量(或函数)可由该模块中的其他函数或子例程以及任何其他模块全局访问。

事实证明这不是真的,在Forms
的情况下,我怀疑也在Sheets,但我没有验证后者。

简而言之,跟随在Form中创建时不会创建公共的可访问变量,因此会崩溃,说明在mModule1中未定义bYesNo和dRate变量:

(inside fMyForm)
Public bYesNo As Boolean`
Public dRate As Double

Private Sub SetVals()
    bYesNo = Me.cbShouldIHaveADrink.value
    dRate = CDec(Me.tbHowManyPerHour.value)
End Sub
(Presume the textbox & checkbox are defined in the form)

(inside mModule1)
Private Sub PrintVals()
    Debug.Print CStr(bYesNo)
    Debug.Print CStr(dRate)
End Sub


但是,如果您进行下面的轻微更改,则一切正常:

(inside fMyForm)

Private Sub SetVals()
    bYesNo = Me.cbShouldIHaveADrink.value
    dRate = CDec(Me.tbHowManyPerHour.value)
End Sub
(Presume the textbox & checkbox are defined in the form)

(inside mModule1)
Public bYesNo As Boolean`
Public dRate As Double
Private Sub PrintVals()
    Debug.Print CStr(bYesNo)
    Debug.Print CStr(dRate)
End Sub


mModule1将完全正常工作,并且假设fMyForm始终首先被调用,那么在PrintVals例程运行时,表单中的文本框和复选框中的值将正确抓获。

老实说,我无法理解MS正在考虑这种变化,但缺乏一致性是对效率的巨大挫折,学习像这样的特质,这些记录很差,以至于谷歌在2013年搜索了一些可能存在的东西。十年或更长时间的搜索是如此具有挑战性。

2 个答案:

答案 0 :(得分:4)

第一条评论:

Userform和Sheet模块是对象模块:它们的行为与常规模块的行为不同。但是,您可以使用与引用类属性的方式类似的方式引用userform中的变量。在您的示例中,引用fMyForm.bYesNo可以正常工作。如果您没有将bYesNo声明为Public,那么表单外部的代码将不可见,因此当您将其设为Public时,它实际上与非Public不同。 - 蒂姆威廉姆斯2013年4月11日21:39

实际上是一个正确答案......

答案 1 :(得分:1)

作为社区答案的快速附加答案,仅供单挑:

实例化表单时,可以使用表单对象本身,也可以使用New创建表单对象的新实例并将其放入变量中。后一种方法是更清洁的IMO,因为这使得使用量更少单身。

但是,当您在userform中调用Unload(Me)时,所有公共成员将被清除干净。所以,如果你的代码是这样的:

  Dim oForm as frmWhatever
  Set oForm = New frmWhatever
  Call oForm.Show(vbModal)
  If Not oForm.bCancelled Then  ' <- poof - bCancelled is wiped clean at this point

我用来防止这种情况的解决方案,它也是OP的一个不错的替代解决方案,是将所有带有表单的IO(即所有公共成员)捕获到一个单独的类中,并使用该类的实例与表格沟通。所以,例如。

  Dim oFormResult As CWhateverResult
  Set oFormResult = New CWhateverResult
  Dim oForm as frmWhatever
  Set oForm = New frmWhatever
  Call oForm.Initialize(oFormResult)
  Call oForm.Show(vbModal)
  If Not oFormResult.bCancelled Then  ' <- safe