Vba 工作表_Calculate()事件处理程序中的全局变量值始终不正确

Vba 工作表_Calculate()事件处理程序中的全局变量值始终不正确,vba,excel,Vba,Excel,我有一个全局变量的问题,它的值并不总是正确的 我是这样宣布的: Public NumRows As Long ' In any standard module Option Explicit Public NumRows As Long Public Function GetTableSize() As Long GetTableSize = Worksheets("TableSize").Range("A1").Value2 End Function 它用于保存活页1上使用的行数。

我有一个全局变量的问题,它的值并不总是正确的

我是这样宣布的:

Public NumRows As Long
' In any standard module
Option Explicit

Public NumRows As Long

Public Function GetTableSize() As Long
  GetTableSize = Worksheets("TableSize").Range("A1").Value2
End Function
它用于保存活页1上使用的行数。该变量是公共的,因为有多个宏使用它

在此处草签:

Private Sub Workbook_Open()
  NumRows = Worksheets("TableSize").Range("A1").Value
  MsgBox "NumRows = " & NumRows
End Sub
插入
MsgBox
只是为了验证代码是否正常工作。工作表
TableSize
仅在
A1
中包含信息。此时,
NumRows=32
这是正确的

这是导致问题的Sheet
TableSize
中的事件处理程序:

Private Sub Worksheet_Calculate()    

    Dim n As Long
    n = Worksheets("TableSize").Range("A1").Value 'A1 contains the formula "=ROW(INDEX(Sheet1,1,1))+ROWS(Sheet1)-1" used to count rows on Sheet 1
    MsgBox n & "NumRows=" & NumRows
    If n = NumRows Then Exit Sub
    If n > NumRows Then Call NewDatabaseEntry

    NumRows = n    

End Sub
MsgBox
n
返回
32
,但为
NumRows
返回
0
,即使
NumRows
已在
工作簿打开()处理程序中正确设置

我们希望
n
始终等于
NumRows
,除非我实际添加了一行,这样才能
NewDataEntry
(正确地)在另一张工作表上创建新的数据条目


我是否遗漏了一些重要的内容?

我假设您在模块中没有使用Option Explicit,而是将专用子工作簿\u Open()放入工作簿模块,将工作表\u Calculate放入工作表模块。由于缺少显式选项,您将不会收到错误消息,说明NumRows是未定义的变量。您不能像以前那样在类模块中定义和使用全局变量。为了修复代码,您可以将以下代码放入工作簿模块

Option Explicit

Public NumRows As Long

Private Sub Workbook_Open()
  NumRows = Worksheets("TableSize").Range("A1").Value
  MsgBox "NumRows = " & NumRows
End Sub

Private Sub Workbook_SheetCalculate(ByVal Sh As Object)

Dim n As Long

    If Sh.Name = "TableSize" Then

        n = Worksheets("TableSize").Range("A1").Value    'A1 contains the formula "=ROW(INDEX(Sheet1,1,1))+ROWS(Sheet1)-1" used to count rows on Sheet 1
        MsgBox n & "NumRows=" & NumRows
        If n = NumRows Then Exit Sub
        If n > NumRows Then
            Debug.Print "NewDatabaseEntry"
        End If

        NumRows = n
    End If

End Sub
另一个选项是使用以下代码添加标准模块

Option Explicit

Public NumRows As Long

Private Sub Auto_Open()
  NumRows = Worksheets("TableSize").Range("A1").Value
  MsgBox "NumRows = " & NumRows
End Sub
在sheet模块中,您可以这样保存代码

Option Explicit

Private Sub Worksheet_Calculate()

Dim n As Long
n = Worksheets("TableSize").Range("A1").Value    'A1 contains the formula "=ROW(INDEX(Sheet1,1,1))+ROWS(Sheet1)-1" used to count rows on Sheet 1
    MsgBox n & "NumRows=" & NumRows
    If n = NumRows Then Exit Sub
    If n > NumRows Then
        Debug.Print "NewDatabaseEntry"
    End If

    NumRows = n

End Sub

实际上,解决方案非常简单。它包括两个部分

第一部分解决了您当前的问题。您所需要做的就是将
NumRows
全局变量声明从“ThisWorkbook”模块(您现在似乎拥有它)移动到标准模块。(您在上一个问题中提到的“Module1”模块很好。)

您的
工作簿\u Open()
事件处理程序仍然能够访问该变量,就像其他模块中的代码一样,并且一切都应该像当前一样工作(如果存在其他问题,则不工作)

第二部分解决了一个更普遍的问题,即为什么您所做的不会导致错误。这也将有助于避免未来的许多其他问题。正如Storax所建议的那样,尽管我会用更有力的措辞,但您必须在每个代码模块的顶部使用
选项Explicit
语句

最好的方法是将VBIDE设置为自动执行此操作。转到
Tools>Options…>Editor
并检查
Require Variable Declaration
选项。(确保单击“确定”按钮;-))

从现在起,
选项Explicit
将自动添加到您创建的所有新模块以及您创建的新工作簿中的所有模块。但是,现有模块需要手动更新


根据DRY原理,另一个好主意是将表大小代码放在函数中。加上bug修复,您的代码如下所示:

Public NumRows As Long
' In any standard module
Option Explicit

Public NumRows As Long

Public Function GetTableSize() As Long
  GetTableSize = Worksheets("TableSize").Range("A1").Value2
End Function
“表大小”工作表模块中的“
”
选项显式
专用子工作表_Calculate()
长
n=GetTableSize()
如果n>NumRows,则新建数据库条目
'始终设置NumRows,以便即使在删除条目后(n


一个更好的主意是省去“TableSize”助手工作表及其
工作表\u Calculate()
事件处理程序,而是使用工作表1的
工作表\u Change()
处理程序直接检测添加的行。(不是您以前尝试使用的
工作表\u Calculate()
处理程序。)

您是否在模块中使用Option Explicit?如果没有,请添加它并报告您遇到的错误。如果您从问题的描述、您试图实现的目标以及提到的Excel+VBA开始,您的问题会更清楚。我建议进行一些编辑,这将有助于其他人了解如何帮助您。我遇到一个编译错误。过程声明与
工作簿\u Calculate
上具有相同名称的事件或过程的描述不匹配您尝试了哪个选项?我的代码中没有工作簿!你说得对,对不起。我使用了第一个选项,在将名称改为工作表\u SheetCalculate后,它就工作了。不幸的是,现在我的代码不起作用了。如果我添加新行,NewDatabaseEntry不会运行。我将
Debug.Print“NewDatabaseEntry”替换为
Call NewDatabaseEntry`是的,当然您必须将
Debug.Print“NewDatabaseEntry”替换为Call NewDatabaseEntry
。但是NewDatabaseEntry不运行意味着什么呢。如果在NewDatabaseEntry中使用可能不起作用的变量NumRows,尤其是工作簿模块中不包含
NewDatabaseEntry
时。我只使用vba两周,请向我解释一下。我是否需要将
NewDatabaseEntry
Workbook\u SheetCalculate
放在同一工作表中?或者只要它在工作簿中就可以了?因为它在工作簿中,就在它自己的模块中。出于好奇,
工作表\u Change()
不会检测到所有的更改,而不仅仅是计算吗?在以前版本的代码中,我确实使用了change,但当我在一行上复制多个单元格时,我的例程不断启动,破坏了可用性。@Remi是的,这就是在第1页(选项1)中使用
工作表\u change
比在第1页(选项2)中使用
工作表\u Calculate
的优点(和缺点)。选项1的优点是,如果添加行不会导致计算,您仍然可以检测到它。另一个次要的好处是,如果您在另一张工作表上工作,这会导致重新计算