vba - 遍历VBA中的指定工作表

标签 vba loops excel

我正在尝试使用在For Each Function, to loop through specifically named worksheets中找到的一些代码来遍历工作簿中的指定工作表,运行少量代码并移至下一个工作表。

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,但是这破坏了代码。

任何帮助表示赞赏,

干杯

最佳答案

您在问题中显示的代码由于以下原因而失败:

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

这将显示 Activity 工作表的名称,但是此循环中的任何内容都不会更改 Activity 工作表。

我对您的解决方案不满意,尽管没有任何明显的错误。我已经看到太多程序失败,因为程序员在单个语句中做了太多事情。首先,语句越复杂,首先需要花费较长的时间,而在随后的维护过程中需要花费的时间也就越长。有时,原始程序员会使该语句略有错误;有时,维护程序员在尝试更新时会出错。在每种情况下,程序员节省的额外时间都不能证明节省运行时间是合理的。

Alex K通过根据VBA的要求将AssetsAsset重新定义为Variants并添加Sheets(Asset).Select来更改 Activity 的工作表,从而修复了您的代码。我不赞成这样做,因为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的当前内容的类型,并确定它是否适合当前情况。这很费时间。

我不想阻止您在适当的时候使用Variants,因为它们可能非常有用,但是您需要了解其开销。

接下来,我希望提倡使用有意义的系统名称。我根据多年使用的系统来命名变量。我可以查看任何程序/宏,并知道变量是什么。当我需要更新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语句的控制变量必须是对象或变量。这就是为什么我将WshtNamesWshtNameCrnt定义为Variants的原因。请注意,您的解决方案之所以有效,是因为工作表是一个对象。

我使用了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

此宏与第一个宏具有相同的效果。有时我发现ForFor Each更方便,尽管在这种情况下我都看不到任何优势。请注意,即使WshtNames的下限始终为零,我也写了LBound(WshtNames)。这只是我(过于?过度)精确。

希望这可以帮助。

关于vba - 遍历VBA中的指定工作表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27922453/

相关文章:

excel - 当文档另存为 PDF 时,VBA 超链接不起作用

复制并粘贴到特定空白列的 Excel 宏

vba - 使用 VBA 将控件添加到 Excel 用户窗体中的框架

R 有效地填充向量

r - 迭代地分层循环行,直到满足条件

vba - 引用另一个工作表VBA重命名Excel中的工作表

excel - 有公式可以删除最后一个字符右侧的所有字符(可能有多个)vba问题

java - 如何将数据从多个Arraylist移动​​到多个Array(Java中)

excel - 尝试使用 Selenium + Excel VBA 从 Chrome 浏览器中的网站抓取代码

java - VBA获取带有空格字符(例如换行符和回车符)的字符串长度