您在问题中显示的代码失败的原因是:
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
Assets
是一个工作表,它是一种对象类型,您必须使用Set
给对象赋值时:
Set Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
这会失败,因为Array("…")
不是工作表。
您暗示您的代码的早期版本将运行但不会循环遍历工作表。原因是:
MsgBox ActiveSheet.Name
这将显示活动工作表的名称,但此循环中不会更改活动工作表。
我对你的解决方案并不满意,尽管它没有任何明显的错误。我见过太多的程序失败,因为程序员在一条语句中做了太多事情。首先,语句越复杂,一开始就需要花费越长的时间来理解,并且在后续维护过程中理解的时间也就越长。有时,最初的程序员的说法略有错误;有时维护程序员在尝试更新时会出错。在每种情况下,程序员花费的额外时间并不能证明运行时间上的任何节省都是合理的。
Alex K 通过重新定义修复了您的代码Assets
and Asset
作为变体,按照 VBA 的要求,并添加Sheets(Asset).Select
更改哪个工作表处于活动状态。我不能同意这一点,因为Select
是一个缓慢的陈述。特别是,如果您不包括Application.ScreenUpdating = False
,当屏幕从每个Select
.
在解释我的解决方案之前,先介绍一下变体的一些背景知识。
如果我写:
Dim I as Long
I
始终是一个长整数。
在运行时,编译器/解释器不必考虑什么I
就是当它遇到:
I = I + 5
但假设我写:
Dim V as Variant
V = 5
V = V + 5
V = "Test"
V = V & " 1"
这是完全有效(有效但不合理)的代码,因为 Variant 可以包含数字、字符串或工作表。但是每次我的代码访问 V 时,解释器都必须检查 V 当前内容的类型并决定它是否适合当前情况。这很耗时。
我不想阻止您在适当的时候使用变体,因为它们非常有用,但您需要了解它们的开销。
接下来我想提倡使用有意义的、系统的名称。我根据我使用多年的系统命名变量。我可以查看我的任何程序/宏并知道变量是什么。当我需要更新 12 或 15 个月前编写的程序/宏时,这确实可以节省时间。
我不喜欢:
Dim Assets As Variant
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
因为“pipe_mat_tables”等不是资产;它们是工作表的名称。我会写:
Dim WshtNames As Variant
WshtNames = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
我的第一个提议是:
Option Explicit
Sub Test1()
Dim WshtNames As Variant
Dim WshtNameCrnt As Variant
WshtNames = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
For Each WshtNameCrnt In WshtNames
With Worksheets(WshtNameCrnt)
Debug.Print "Cell B1 of worksheet " & .Name & " contains " & .Range("B1").Value
End With
Next WshtNameCrnt
End Sub
我本可以命名WshtNameCrnt
as WshtName
但我被告知,名称应该至少相差三个字符,以避免使用错误而不引起注意。
The Array
函数返回一个包含数组的变体。控制变量aFor Each
语句必须是对象或变体。这就是为什么我定义了WshtNames
and WshtNameCrnt
作为变体。请注意,您的解决方案之所以有效,是因为工作表是一个对象。
我用过With Worksheets(WshtNameCrnt)
这意味着匹配之前的任何代码End With
可以通过在开头加上句点来访问此工作表的某个组成部分。所以.Name
and .Range("B1").Value
参考Worksheets(WshtNameCrnt)
无需选择工作表。这比任何替代方案都更快、更清晰。
I have used Debug.Print
rather than MsgBox
because it is less bother. My code runs without my having to press Return for every worksheet and I have a tidy list in the Immediate Window which I can examine at my leisure. I often have many Debug.Print
statements within my code during development which why I have output a sentence rather than just a worksheet name or cell value.
我的第二个提议是:
Sub Test2()
Dim InxW As Long
Dim WshtNames As Variant
WshtNames = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
For InxW = LBound(WshtNames) To UBound(WshtNames)
With Worksheets(WshtNames(InxW))
Debug.Print "Cell B1 of worksheet " & .Name & " contains " & .Range("B1").Value
End With
Next InxW
End Sub
该宏与第一个宏具有相同的效果。我有时会发现For
比方便For Each
尽管在这种情况下我看不出任何优势。请注意我已经写了LBound(WshtNames)
即使 WshtNames 的下限始终为零。这只是我的(过度?过度?)精确。
希望这可以帮助。