我的全局变量存在问题,其值并不总是正确的。
我已经宣布这样:
Public NumRows As Long
它用于保存Sheet 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
会为32
返回n
,但0
会为NumRows
,即使NumRows
已在Workbook_Open()
中正确设置{1}}处理程序!
希望n
总是等于NumRows
,除非我实际添加一行,这样才会NewDataEntry
(正确地)在另一张纸上创建新数据条目。< / p>
我错过了一些关键的东西吗?
答案 0 :(得分:1)
我假设您不在模块中使用Option Explicit,并将Private Sub Workbook_Open()放入Workbook模块,将Worksheet_Calculate放入工作表模块。由于缺少Option Explicit,您将不会收到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
在工作表模块中,您可以保留代码
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
答案 1 :(得分:1)
实际上,解决方案非常简单。它涉及两个部分。
第一部分解决了您的直接问题。您需要做的就是将NumRows
全局变量声明从“ThisWorkbook”模块(现在看起来像你现在的位置)移动到标准模块。 (您在上一个问题中提到的“Module1”模块很好。)
您的Workbook_Open()
事件处理程序仍然可以访问该变量,并且每个其他模块中的代码都是如此,并且所有内容仍然可以正常工作(或者如果有其他问题,则仍然可以正常工作)。
第二部分解决了为什么你所做的不会导致错误的更普遍的问题。它还有助于避免将来出现许多其他问题。正如Storax建议的那样,虽然我会说它更强一些,但必须使用每个代码模块顶部的Option Explicit
语句。
执行此操作的最佳方法是设置VBIDE以自动执行此操作。转到Tools > Options… > Editor
并查看Require Variable Declaration
选项。 (确保单击确定按钮;-))
从现在开始,Option Explicit
将自动添加到您创建的所有新模块以及您创建的新工作簿中的所有模块。但是,现有的模块需要手动更新。
根据DRY原则,另一个好主意是将表大小代码放在函数中。与错误修复一起,您的代码将如下所示:
' In any standard module
Option Explicit
Public NumRows As Long
Public Function GetTableSize() As Long
GetTableSize = Worksheets("TableSize").Range("A1").Value2
End Function
' In the "ThisWorkbook" module
Option Explicit
Private Sub Workbook_Open()
NumRows = GetTableSize()
End Sub
' In the "TableSize" sheet module
Option Explicit
Private Sub Worksheet_Calculate()
Dim n As Long
n = GetTableSize()
If n > NumRows Then NewDatabaseEntry
' Always set NumRows so that even after entries are deleted (n < NumRows),
' adding new entries will work correctly.
NumRows = n
End Sub
更好的想法是省去“TableSize”助手工作表及其Worksheet_Calculate()
事件处理程序,而是使用Sheet 1的Worksheet_Change()
处理程序直接检测添加的行。 (不是您之前尝试使用的Worksheet_Calculate()
处理程序。)