【问题标题】:Using Global Variables in VBA在 VBA 中使用全局变量
【发布时间】:2018-03-04 07:23:25
【问题描述】:

在过去一周内刚开始使用 VBA,并且正在玩工作表与模块并定义变量。这是我目前拥有的代码:

表 1:

Dim writtenvoe As Boolean
Dim verbalvoe As Boolean
Dim voerequired As Boolean
Dim CA14 As Boolean
Dim CA15 As Boolean
Dim W2s As Boolean
Dim tranapp As Boolean

模块1:

Public Sub ImpDocs()

'Is written voe on file?
If Sheet1.CheckBox6.Value = True Or Sheet1.CheckBox8.Value = True Or Sheet1.CheckBox9.Value = True Or Sheet1.CheckBox10.Value = True Then writtenvoe = True Else writtenvoe = False
If Sheet1.CheckBox6.Value = True Then Sheet1.[O40] = "hello" Else Sheet1.[O40] = ""
If writtenvoe = True Then Sheet1.[O39] = "writtenvoe = true" Else Sheet1.[O39] = "writtenvoe=false"

'Is verbal voe on file?
If Sheet1.CheckBox11.Value = True Then verbalvoe = True

'Is a written VOE required?
If Sheet1.CheckBox16.Value = True Or Sheet1.CheckBox18.Value = True Or Not IsEmpty(Sheet1.[H33]) Then voerequired = True
If voerequired = True Then Sheet1.[J35] = "hello" Else Sheet1.[J35] = ""

'Are tax docs CA14 or CA15?
If Sheet1.CheckBox31.Value = True Or Sheet1.CheckBox7.Value = True Or Sheet1.CheckBox32.Value = True Or Sheet1.[H29].Value > 25 Then CA15 = True Else CA15 = False
If CA15 = False Then CA14 = True Else CA14 = False

'Are W-2's on file?
If Sheet1.CheckBox12.Value = True And Sheet1.CheckBox13.Value = True Then W2s = True

'Are 4506-T's on file?
If Sheet1.CheckBox60.Value = True And Sheet1.CheckBox61.Value = True Then tranapp = True

    'Order Wage transcripts if W-2s and 4506-T not on file
    If W2s = False And tranapp = False And CA14 = True Then Sheet4.fullCA14

End Sub

还有模块 1(第二个子程序):

Public Sub test()

If writtenvoe = True Then Sheet1.[N37] = "Yes" Else Sheet1.[N37] = "No"

End Sub

我注意到在这种当前格式下,Sub ImpDocs 运行良好,并且变量被正确确定,但 Sub test 总是返回 false。但是,如果我将所有代码放入模块 1,那么一切都会按预期工作。似乎只有 Sub 测试会受到在 Sheet1 和 Module1 中声明变量的影响。真的吗?如果是这样,为什么?

谢谢。

【问题讨论】:

  • 也许尝试将 Option Explicit 放在模块的顶部以确保正确找到所有变量声明(尽管它不应该有所作为,因为 bool 的默认值为 false)?无论如何,最好使用此行,因为它会提醒您是否未定义变量。
  • 这可能是一件显而易见的事情,但是,您已经在 if 语句中的所有复选框都设置为 false 的情况下对此进行了测试,我认为对吗?
  • @TiannaProcon 好建议,选项显式添加确实告诉我我的变量没有在测试中定义。你知道为什么 ImpDocs 能够提取变量,但 test 不能吗?我确实测试了两个程序中的变量,并且 ImpDocs 准确返回。

标签: excel vba


【解决方案1】:

Sheet1 是一个Worksheet 对象,是一个实例。因此,即使您在Sheet1 上声明了所有Public,您也将无法在不先访问实例 的情况下访问它们。

Dim 用于声明本地变量。它在模块级别也是合法的,但它相当于使用Private 来声明它们:使用Dim 关键字声明的任何变量都不会公开访问——我的建议是对本地人使用Dim,并且对模块变量使用Private/Public

当您在标准模块(而不是类模块)中声明Public 变量时,您实际上是在声明全局变量 - 可以从项目中的任何位置读取和写入。如果这听起来是个好主意,请花时间研究“全局变量的优缺点”——不管是什么语言,它们通常都是灾难的根源。您希望变量仅由特定代码编写,并且希望变量的作用域尽可能受到限制。

了解如何将参数传递给您的过程。

您正在发现标准模块和类之间的区别:您周围的几乎所有东西(ApplicationRangeSheet1 等)都是一个对象。对象是某个Excel.ApplicationExcel.RangeExcel.Worksheet等)的实例,每个实例封装其自己的状态。

标准模块非常适合宏入口点,但不太适合封装 - 封装是面向对象编程 (OOP) 的基本支柱之一。

【讨论】:

  • @MatsMug 感谢您花时间写出该上下文;当我发展我的概念理解时,这对我很有帮助。我会更多地研究全局变量。
  • @khelm 您可能有兴趣查看Rubberduck - 我管理的一个开源 VBIDE 插件项目。我相信它可以帮助您避免大量初学者陷阱!
  • @khelm 传播这个信息,如果你愿意,请在 GitHub 上给我们一颗星!
【解决方案2】:

这是关于 VBA 如何处理其命名空间的一个怪癖 (https://en.wikipedia.org/wiki/Namespace)。回到 Sheet1,您需要将 writtenvoe 设为 Sheet1 的 Public 成员:

Public writtenvoe As Boolean

然后,回到Module1,每次想要Sheet1writtenvoe,都必须指定Sheet1.writtenvoe,例如:

'Is written voe on file?
If Sheet1.CheckBox6.Value = True Or Sheet1.CheckBox8.Value = True Or Sheet1.CheckBox9.Value = True Or Sheet1.CheckBox10.Value = True Then Sheet1.writtenvoe = True Else Sheet1.writtenvoe = False

当您将writtenvoe 移出Sheet1 并移入Module1 时,您实际上删除了Sheet1.writtenvoe 并创建了Module1.writtenvoe,从而使Module1 可以轻松访问某些内容。模块的命名空间非常宽松,因此在模块内声明的任何 Public 几乎都可以在任何地方使用——另一个模块、任何工作表、任何类模块等。

【讨论】:

  • 哦,是的,使用Option Explicit 也可以消除很多潜在的混乱!
  • 这不是“VBA 怪癖”,它是基本的 OOP 101 - Sheet1Worksheet 类的一个实例。
  • VBA 中没有关于命名空间的怪癖,因为一开始就没有命名空间。 Sheet1Worksheet 类型的对象,Module1 是模块。既没有也不是命名空间。你说的叫scope
  • 是的,我明白你的意思。在我的辩护中,根据维基百科:“命名空间与范围:命名空间标识符可以为名称提供上下文(计算机科学中的范围),并且这些术语有时可以互换使用。但是,名称的上下文也可能由其他因素提供,例如它出现的位置或名称的语法。”
  • @rskar 效果很好,谢谢!我也在其他模块中测试了其他变体,只是为了确保我理解/正确地拉动它们。这真的很有帮助。
猜你喜欢
  • 2016-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-05
相关资源
最近更新 更多