【问题标题】:Global variable not accessible in different sub?全局变量无法在不同的子中访问?
【发布时间】:2019-12-01 12:39:15
【问题描述】:

我在模块1的顶部全局声明了projname。它在userform中分配,并在createWB sub中成功访问。但是,当我也在模块 1 中的 addWindow 子中访问它时,它变为空(“”)。我不确定为什么会发生这种情况,因为我认为由于变量是全局声明的,我应该能够在任何子中访问它。

模块 1

Option Explicit

Public outputWorkbook As Workbook
Public globalcounter As Integer
Public projname As String
Public projnum As String

createWB()
    Dim uf2 As New UserForm2
    uf2.Show

    Set outputWorkbook = Workbooks.Add(xlWBATWorksheet)
    outputWorkbook.SaveAs Filename:=Environ("userprofile") & "\Desktop\" & 
    Replace(projname, " ", "") & ".xlsx"

    outputWorkbook.Activate

    Range("B3") = projname
    Range("B4") = projnum
End Sub

addWindow()
    Workbooks(Replace(projname, " ", "") + ".xlsx").Activate
End Sub

用户表单代码

Public Sub CommandButton1_Click()
    projname = Me.TextBox1.Text
    projnum = Me.TextBox2.Text
    Me.Hide
End Sub

单元格B3B4 被分配了正确的值,但addWindow() 行导致下标超出范围错误。当我用Debug.Print 测试它时,我看到 projname = ""。我也简单地尝试了outputWorkbook.Activate,它也不起作用。

【问题讨论】:

  • 听起来 projname 的范围是模块 1 而不是全局的——你能出示你的声明吗?
  • 我刚加了!
  • .SaveAs 方法能否重置全局变量?
  • 我认为最重要的是你如何/在哪里打电话给addWindow()。如果您在整个过程之外调用它,那么projName 将是""。例如,如果您在运行creatWB 时包含调用者,您的projName 将被存储并且您将能够访问它。
  • 是的,问题存在是因为您似乎将它们称为独立进程。如果您将Call addWindow 包含在您的createWb() 中,您将看到您不会收到该错误,因为该信息是基于createWB() 例程存储的。否则它只是将默认状态返回为“”

标签: excel vba userform


【解决方案1】:

避免全球污染

除非有充分的理由使用它们,否则请尝试avoid global variables。我们希望避免污染全局命名空间。 星球船长警告我们

相反,请尝试根据需要通过各种方法传递参数。这有助于防止错误、使您的代码更易于遵循并利用组合。


使用您的用户表单来存储和公开您的属性

尝试使用With 语句实例化您的用户表单,以便您拥有一个捕获的实例,您可以在其中访问您公开的各种属性。在你的情况下ProjectNameProjectNumber

另外,应该有一个属性来检查用户窗体是否被取消或X按钮被按下。

你的用户表单看起来像这样:

Option Explicit

Private cancelled As Boolean

Public Property Get ProjectName() As String
    ProjectName = TextBox1.Value
End Property

Public Property Get ProjectNumber() As Long
    ProjectNumber = TextBox2.Value
End Property

Public Property Get IsCancelled() As Boolean
    IsCancelled = cancelled
End Property

Private Sub CommandButton1_Click()
    Me.Hide
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        Cancel = True
        OnCancel
    End If
End Sub

Private Sub OnCancel()
    cancelled = True
    Hide
End Sub

实例化用户表单

这是现在调用您的用户表单的示例(P.S. 更改 Userform2 的名称)。请注意,我们正在使用 With 块捕获您的用户表单实例。在这个块中,我们可以访问我们公开的属性:ProjectNameProjectNumberIsCancelled

Private Sub createWB()
    With New UserForm2
        .Show
        If Not .IsCancelled Then
            ' Do neccessaray steps here...

            ' You have access to ProjectName and Project number.
            ' Pass this to your addWindow method.
            addWindow .ProjectName

        End If
    End With
End Sub

ProjectName 现在可以从您的用户窗体中访问并作为参数传递给您的addWindow 方法。

Private Sub addWindow(ByVal projName As String)
    Workbooks(Replace(projName, " ", "") + ".xlsx").Activate
End Sub

有关以这种方式使用用户表单的更多信息,请参阅有用的Rubberduck Blog Post

【讨论】:

    【解决方案2】:

    您可以尝试使用 Module1 作为前缀吗? ,就像在这段代码中一样

     Public Sub CommandButton1_Click()
            Module1.projname = Me.TextBox1.Text
            Module1.projnum = Me.TextBox2.Text
            Me.Hide
        End Sub
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-29
      • 2014-01-17
      • 2014-04-08
      • 1970-01-01
      • 2016-11-12
      • 2018-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多