循环遍历 VBA 中的指定工作表
loop through specified sheets in VBA
我正在尝试使用我在此处找到的一些代码 For Each Function, to loop through specifically named worksheets 循环遍历工作簿中指定的 sheets,运行 少量代码并移至下一个sheet.
Sub LoopThroughSheets()
Dim Assets As Worksheet
Dim Asset As Worksheet
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
For Each Asset In Assets
'my code here
MsgBox ActiveSheet.Name 'test loop
Next Asset
End Sub
这不是在 sheet 中循环。我试过 Dim Assets as Worksheet
但这破坏了密码。
非常感谢任何帮助,
干杯
使用变体而不是工作表。
Array
returns 字符串的 Variant 数组,因此不能转换为 Worksheet
,Each
变量必须是 Variant
.
Dim Assets As Variant
Dim Asset As Variant
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
For Each Asset In Assets
'my code here
Sheets(Asset).Select
MsgBox ActiveSheet.Name 'test loop
Next Asset
解决了,但总是很高兴听到其他方法
Sub loopsheets()
Dim Sh As Worksheet
For Each Sh In Sheets(Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables"))
MsgBox Sh.Range("b1")
Next
End Sub
干杯
您在问题中显示的代码失败,因为:
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
Assets
是一个 Worksheet,它是一种 Object,在给 Object 赋值时必须使用 Set
:
Set Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
这会失败,因为 Array("…")
不是工作表。
您暗示您的代码的早期版本会 运行 但不会遍历工作表。原因是:
MsgBox ActiveSheet.Name
这会显示活动工作表的名称,但此循环中不会更改活动工作表。
我对你的解决方案不满意,尽管它没有明显的错误。我见过太多的程序失败是因为程序员在一条语句中做了太多的事情。首先,语句越复杂,一开始就正确的时间越长,后续维护时理解的时间也越长。有时,最初的程序员会把语句弄错;有时维护程序员在尝试更新时弄错了。在每种情况下,运行 时间的任何节省都不能用程序员花费的额外时间来证明。
Alex K 已根据 VBA 的要求将 Assets
和 Asset
重新定义为变体,并添加 Sheets(Asset).Select
以更改激活的工作表,从而修复了您的代码。我不能赞成这个,因为 Select
是一个缓慢的声明。特别是,如果您不包括 Application.ScreenUpdating = False
,您的例程的持续时间可以通过屋顶从每个 Select
.
重新绘制屏幕。
在解释我的解决方案之前,先了解一下变体的背景知识。
如果我写:
Dim I as Long
I
将始终是一个长整数。
在运行的时候,compiler/interpreter不用考虑遇到I
是什么:
I = I + 5
但是假设我写:
Dim V as Variant
V = 5
V = V + 5
V = "Test"
V = V & " 1"
这是完全有效(有效但不合理)的代码,因为 Variant 可以包含数字、字符串或工作表。但是每次我的代码访问 V 时,解释器都必须检查 V 当前内容的类型,并决定它在当前情况下是否合适。这很费时间。
我不想阻止您在适当的时候使用变体,因为它们非常有用,但您需要了解它们的开销。
接下来我提倡使用有意义的、系统的名字。我根据我使用多年的系统命名我的变量。我可以查看我的任何 programs/macros 并知道变量是什么。当我需要更新我 12 或 15 个月前写的 program/macro 时,这是一个真正的节省时间。
我不喜欢:
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
命名为 WshtName
,但我被告知名称应至少相差三个字符,以避免使用错误的字符而引起注意。
Array
函数 returns 包含数组的变体。 For Each
语句的控制变量必须是对象或变体。这就是我将 WshtNames
和 WshtNameCrnt
定义为变体的原因。请注意,您的解决方案之所以有效,是因为工作表是一个对象。
我使用了 With Worksheets(WshtNameCrnt)
,这意味着匹配 End With
之前的任何代码都可以通过在开头加上句点来访问此工作表的组件。因此 .Name
和 .Range("B1").Value
引用 Worksheets(WshtNameCrnt)
而不选择工作表。这比任何替代方法都更快、更清晰。
我用的是Debug.Print
而不是MsgBox
,因为这样更省事。我的代码 运行s 无需为每个工作表按 Return 并且我在即时 Window 中有一个整洁的列表,我可以在我的闲暇在开发过程中,我的代码中经常有许多 Debug.Print
语句,这就是为什么我输出一个句子而不仅仅是工作表名称或单元格值的原因。
我的第二个产品是:
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
更方便,尽管在这种情况下我看不出任何一种方式有任何优势。请注意,即使 WshtNames 的下限始终为零,我也写了 LBound(WshtNames)
。这只是我(过度?过度?)精确。
希望对您有所帮助。
我正在尝试使用我在此处找到的一些代码 For Each Function, to loop through specifically named worksheets 循环遍历工作簿中指定的 sheets,运行 少量代码并移至下一个sheet.
Sub LoopThroughSheets()
Dim Assets As Worksheet
Dim Asset As Worksheet
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
For Each Asset In Assets
'my code here
MsgBox ActiveSheet.Name 'test loop
Next Asset
End Sub
这不是在 sheet 中循环。我试过 Dim Assets as Worksheet
但这破坏了密码。
非常感谢任何帮助,
干杯
使用变体而不是工作表。
Array
returns 字符串的 Variant 数组,因此不能转换为 Worksheet
,Each
变量必须是 Variant
.
Dim Assets As Variant
Dim Asset As Variant
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
For Each Asset In Assets
'my code here
Sheets(Asset).Select
MsgBox ActiveSheet.Name 'test loop
Next Asset
解决了,但总是很高兴听到其他方法
Sub loopsheets()
Dim Sh As Worksheet
For Each Sh In Sheets(Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables"))
MsgBox Sh.Range("b1")
Next
End Sub
干杯
您在问题中显示的代码失败,因为:
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
Assets
是一个 Worksheet,它是一种 Object,在给 Object 赋值时必须使用 Set
:
Set Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
这会失败,因为 Array("…")
不是工作表。
您暗示您的代码的早期版本会 运行 但不会遍历工作表。原因是:
MsgBox ActiveSheet.Name
这会显示活动工作表的名称,但此循环中不会更改活动工作表。
我对你的解决方案不满意,尽管它没有明显的错误。我见过太多的程序失败是因为程序员在一条语句中做了太多的事情。首先,语句越复杂,一开始就正确的时间越长,后续维护时理解的时间也越长。有时,最初的程序员会把语句弄错;有时维护程序员在尝试更新时弄错了。在每种情况下,运行 时间的任何节省都不能用程序员花费的额外时间来证明。
Alex K 已根据 VBA 的要求将 Assets
和 Asset
重新定义为变体,并添加 Sheets(Asset).Select
以更改激活的工作表,从而修复了您的代码。我不能赞成这个,因为 Select
是一个缓慢的声明。特别是,如果您不包括 Application.ScreenUpdating = False
,您的例程的持续时间可以通过屋顶从每个 Select
.
在解释我的解决方案之前,先了解一下变体的背景知识。
如果我写:
Dim I as Long
I
将始终是一个长整数。
在运行的时候,compiler/interpreter不用考虑遇到I
是什么:
I = I + 5
但是假设我写:
Dim V as Variant
V = 5
V = V + 5
V = "Test"
V = V & " 1"
这是完全有效(有效但不合理)的代码,因为 Variant 可以包含数字、字符串或工作表。但是每次我的代码访问 V 时,解释器都必须检查 V 当前内容的类型,并决定它在当前情况下是否合适。这很费时间。
我不想阻止您在适当的时候使用变体,因为它们非常有用,但您需要了解它们的开销。
接下来我提倡使用有意义的、系统的名字。我根据我使用多年的系统命名我的变量。我可以查看我的任何 programs/macros 并知道变量是什么。当我需要更新我 12 或 15 个月前写的 program/macro 时,这是一个真正的节省时间。
我不喜欢:
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
命名为 WshtName
,但我被告知名称应至少相差三个字符,以避免使用错误的字符而引起注意。
Array
函数 returns 包含数组的变体。 For Each
语句的控制变量必须是对象或变体。这就是我将 WshtNames
和 WshtNameCrnt
定义为变体的原因。请注意,您的解决方案之所以有效,是因为工作表是一个对象。
我使用了 With Worksheets(WshtNameCrnt)
,这意味着匹配 End With
之前的任何代码都可以通过在开头加上句点来访问此工作表的组件。因此 .Name
和 .Range("B1").Value
引用 Worksheets(WshtNameCrnt)
而不选择工作表。这比任何替代方法都更快、更清晰。
我用的是Debug.Print
而不是MsgBox
,因为这样更省事。我的代码 运行s 无需为每个工作表按 Return 并且我在即时 Window 中有一个整洁的列表,我可以在我的闲暇在开发过程中,我的代码中经常有许多 Debug.Print
语句,这就是为什么我输出一个句子而不仅仅是工作表名称或单元格值的原因。
我的第二个产品是:
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
更方便,尽管在这种情况下我看不出任何一种方式有任何优势。请注意,即使 WshtNames 的下限始终为零,我也写了 LBound(WshtNames)
。这只是我(过度?过度?)精确。
希望对您有所帮助。