作者:村医医治世界经济 | 来源:互联网 | 2023-05-27 08:14
我试图使用我在这里找到的一些代码For Each Function,循环通过特定命名的工作表来循环遍历工作簿中的指定工作表,运行少量代码并移动到下一个工作表.
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
这不是在表格中循环.我试过Dim Assets as Worksheet
但是这打破了代码.
任何帮助非常感谢,
干杯
1> Tony Dallimo..:
您在问题中显示的代码因以下原因而失败:
Assets = Array("pipe_mat_tables", "pipe_diam_tables", "pipe_length_tables")
Assets
是一种工作表,它是一种Object,您必须Set
在为Object 赋值时使用:
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
永远是一个长整数.
在运行时,编译器/解释器不必考虑I
它遇到的时间:
I = I + 5
但是假设我写道:
Dim V as Variant
V = 5
V = V + 5
V = "Test"
V = V & " 1"
这是完全有效(有效但不明智)的代码,因为Variant可以包含数字,字符串或工作表.但每次我的代码访问对时间,解释必须检查的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
为,WshtName
但我被告知名称应该至少有三个字符,以避免使用错误的一个而不注意.
该Array
函数返回包含数组的变体.For Each
语句的控制变量必须是对象或变体.这就是我定义WshtNames
和WshtNameCrnt
作为变体的原因.请注意,您的解决方案有效,因为工作表是一个对象.
我已经使用了With Worksheets(WshtNameCrnt)
这意味着匹配之前的任何代码End With
都可以通过在开头有一个句点来访问该工作表的一个组件.所以没有选择工作表.Name
而.Range("B1").Value
参考Worksheets(WshtNameCrnt)
.这比任何替代方案都更快更清晰.
我用过Debug.Print
而不是MsgBox
因为它不那么麻烦.我的代码运行时没有必须按下Return每个工作表,我在立即窗口中有一个整洁的列表,我可以在闲暇时检查.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
在这种情况下无论哪种方式都没有优势,我觉得更方便.请注意,LBound(WshtNames)
即使WshtNames的下限始终为零,我也写过.这只是我(过度?过度)精确.
希望这可以帮助.