【问题标题】:Global variables reset automatically全局变量自动重置
【发布时间】:2015-12-04 02:42:34
【问题描述】:

我想在打开文件时定义一个全局变量作为工作表,所以我使用了以下代码:

在模块 1 中:

Public mySheet As Worksheet

在本工作簿中:

Sub Workbook_Open()  
    Set mySheet = Sheet1   
End Sub

然后我想在各种过程中使用mySheet 来引用这个特定的工作表,其中一些过程引用了打开一个新文件的这个工作表。

它最初可以工作 - 当我打开文件时,设置了变量,并且涉及 mySheet.UnprotectmySheet.ProtectmySheet.Range("A1") 的宏工作。但是,当我再次尝试运行它时,我收到错误 Object variable or With block variable not set,并且调试会将我带到 mySheet.Unprotect 行,这是第一次引用工作表。

如何在全局变量中定义此工作表以使定义保持不变?

作为参考,我所指的特定宏如下,尽管我在不同的代码位上遇到了类似的问题:

Sub mySub()
    mySheet.Unprotect 
    With Application.FileDialog(msoFileDialogOpen)  
        .AllowMultiSelect = False           
        If .Show <> 0 Then
            mySheet.Range("A1") = .SelectedItems(1)
        End If           
    End With

    mySheet.Protect        
End Sub

【问题讨论】:

  • mysheet 定义为constantsheet1,这样可以吗?
  • @psychicebola VBA 不支持对象常量,它们必须在过程中初始化。
  • 使用本地窗口尝试debugging您的代码,以查看变量发生了什么。它第一次运行的事实告诉我该过程有问题 - 而不是您分配变量的方式。
  • @aprados Global 关键字只允许通过引用另一个项目中的项目来访问变量 - 就这个问题而言,PublicGlobal 将做同样的事情。
  • “其中一些引用打开了一个新文件的工作表。” - 这是否意味着您关闭了设置变量的工作簿?这将导致代码失败,因为工作表对象不再存在。

标签: vba excel global-variables


【解决方案1】:

我个人建议您创建一个返回该工作表的函数。然后您基本上可以将函数名称用作 Worksheet 变量。 (虽然如果你总是想要同一张表,你可以使用Sheet1 代号)

Function MySheet() As Excel.Worksheet
    Set MySheet = Sheet1
End Function

并使用,例如:

Sub foo()
    MsgBox MySheet.Name
End Sub

【讨论】:

    【解决方案2】:

    here for a very similar post...重申那里所说的,这种行为可能是由以下原因引起的:

    1. 使用“End”(不是“End Sub”,仅使用“End”语句)。
    2. 未处理的运行时错误(因此,如果您的任何代码抛出错误,您就会丢失全局变量)
    3. 编辑代码(包括按下停止按钮)
    4. 关闭包含 VB 项目的工作簿(您已在 cmets 部分中排除了该项目)。

    一种解决方案是使用子例程简化公共变量重新初始化。然后可以在一行中的其他子程序的开头调用此子程序,或者根据需要从错误处理中调用该子程序。不断重新初始化变量的不利之处在于它们在保存可变信息方面失去了可靠性。

    【讨论】:

    • 这应该是一条评论。你的贡献是什么?您只需传递链接,从那里复制信息并进行总结!
    • 不,它不应该是评论,因为它回答了为什么会发生这种情况的问题。您不想将答案埋在 cmets 中。我可以自己独立验证这个答案,并选择包含一个链接来证实它。这不仅仅是复制和粘贴,而是根据 OP 手头的问题添加和评估信息。我假设给定这些信息,创建一个单独的变量重新初始化子例程的解决方案是显而易见的。
    • 您最近的编辑现在更有意义了。已经推翻了投票:)
    • 嗯,1,3 和 4 绝对不会导致问题。数字 2 可能是 - 我不知道全局变量因错误而丢失。我会看看有没有什么东西可以触发这个。
    【解决方案3】:

    正如其他答案的链接中所述,您可以理解为什么会发生这种情况。

    这是我建议绕过该问题的方法。

    在模块中创建一个过程。说出它的名字,Init

    Public mySheet As Worksheet
    
    Sub Init()
       Set mySheet = Sheet1
    End Sub
    

    然后在您的Workbook_Open() 中执行此操作。

    Sub Workbook_Open()
        Init
    End Sub
    

    现在无论您在何处使用该对象,只需再添加一行

    Sub mySub()
        If mySheet is Nothing then Call Init '<== Add this
    
        mySheet.Unprotect
    
        With Application.FileDialog(msoFileDialogOpen)
            .AllowMultiSelect = False
            If .Show <> 0 Then
                mySheet.Range("A1") = .SelectedItems(1)
            End If
        End With
        mySheet.Protect
    End Sub
    

    【讨论】:

    • ++ 不错的建议 :)
    猜你喜欢
    • 1970-01-01
    • 2015-11-15
    • 2017-02-04
    • 2016-04-05
    • 2016-07-13
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多