vba - 工作表中多个工作表的 VBA 循环
问题描述
我有一个正常工作的 VBA 宏,可以循环遍历一列直到最后一行。我需要的是它在 excel 文件中运行多个选项卡或工作表。这是我到目前为止所拥有的:
Sub Stocks()
Dim Ticker As String
Dim Total_Stock_Volume As Double
Total_Stock_Volume = 0
Dim Summary_Table_Row As Integer
Summary_Table_Row = 2
Dim lastRow As Long
Dim ws As Worksheet
For Each ws In Worksheets
ws.Activate
Next ws
Set sht = Worksheet
lastRow = ws.Cells(sht.Rows.Count, "A").End(xlUp).Row
For i = 2 To lastRow
Total_Stock_Volume = Total_Stock_Volume + ws.Cells(i, 7).Value
If ws.Cells(i + 1, 1).Value <> ws.Cells(i, 1).Value Then
Ticker = ws.Cells(i, 1).Value
ws.Range("J" & Summary_Table_Row).Value = Ticker
ws.Range("K" & Summary_Table_Row).Value = Total_Stock_Volume
Summary_Table_Row = Summary_Table_Row + 1
Total_Stock_Volume = 0
End If
Next i
End Sub
解决方案
This following code is what I would call a useless dumpster fire.
Dim ws As Worksheet
For Each ws In Worksheets
ws.Activate
Next ws
Set sht = Worksheet
lastRow = ws.Cells(sht.Rows.Count, "A").End(xlUp).Row
The reason I call it that is because using ws.Activate
is the equivalent of clicking the worksheet tab (hence useless in this case) and your ws
variable is referencing only the last worksheet, which, if your intent is to set a reference to the last worksheet, can be done by using:
Set ws = Excel.Application.ThisWorkbook.Worksheets(YourLastWorksheetName)
Now, the following perplexes me for a few reasons:
Set sht = Worksheet
- Which worksheet?
- Which workbook are you referencing the worksheet from?
- I didn't even know one could reference anything from
Worksheet
Just to simplify things, I'm assuming that ws == sht
because I'm assuming the goal was to test if you could work with 1 worksheet before you asked about iterating through multiple worksheets, so you can simplify this by setting 1 reference to the 1 worksheet you're working with - I previously did this with ws
- instead of setting another reference to whatever worksheet sht
is referencing.
Also, sht
is not explicitly declared, so I would suggest writing Option Explicit
in the very first line of every Module or Class Module you write because, at compile time, it will show you which variables you haven't explicitly declared, which will notify you if you have mispelled any variables by accident.
This bit is what I would call the dumpster fire:
lastRow = ws.Cells(sht.Rows.Count, "A").End(xlUp).Row
Because I'm assuming your goal was to work with 1 worksheet, this line of code looks like you're working with 2 poorly-referenced worksheets, which, somewhere down the line, may not work as you intend.
Here's how I would change your code:
Edit: This code compiled in Excel so it should work, but you'll have to test it for runtime errors.
'i like this because i know when i have
'incorrectly named a variable // otherwise
'VBA will just create the incorrectly-named variable
'and set its type to Variant
Option Explicit
'i like to explicitly state whether a sub or function
'will be able to be called from outsite the module (public)
'or if i want it to only be called from within the module (private)
Public Sub Stocks()
'i prefer to keep all my 'Dim' statements in 1 block so they're
'easier to find later when i need to change something
Dim Total_Stock_Volume As Double
Dim Summary_Table_Row As Integer
Dim lastRow As Long
Dim ws As Worksheet
Dim j As Long
Dim i As Long
Dim Ticker As String
'i prefer to clump my like assignments together in a block
Summary_Table_Row = 2
Total_Stock_Volume = 0
'iterate through the collection of worksheets in your workbook
For j = 1 To Excel.Application.ThisWorkbook.Worksheets.Count
'set a reference to a worksheet // this will go through
'the different worksheets in the workbook as the loop
'progresses
Set ws = Excel.Application.ThisWorkbook.Worksheets(j)
With ws
'this is a better way to get the last column in a worksheet
lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
End With
For i = 2 To lastRow
'i prefer to explicitly cast anything i get from a cell to the type
'i intend to use because .Value returns a Variant type by default
Total_Stock_Volume = Total_Stock_Volume + CDbl(ws.Cells(i, 7).Value)
If ws.Cells(i + 1, 1).Value <> ws.Cells(i, 1).Value Then
'me explicitly casting the value of the cell to a string
Ticker = CStr(ws.Cells(i, 1).Value)
'i like with statements because it looks nicer to me.
'i'm sure there's a better reason to use these, but that's
'my reason!
With ws
.Range("J" & Summary_Table_Row).Value = Ticker
.Range("K" & Summary_Table_Row).Value = Total_Stock_Volume
End With
Summary_Table_Row = Summary_Table_Row + 1
'i'm unsure about the intention with this, so i'll leave it alone
Total_Stock_Volume = 0
End If
Next i
Next
End Sub
Hope it helps!
Edit: Added screenshots of what the output from the above code looks like when I run it. As I said in the comments, without further information about what you want this code to do, I can't really do anything else to help.
推荐阅读
- r - 如何从 autoconf 脚本 configure.ac 中检查程序的版本
- javascript - 为什么 \n 有时在 javascript 中充当空格而不是换行符?
- php - 添加一个“计数器”变量以通过 PHP 在 mail() 中发送
- python - Python变点算法
- c# - 匹配除 html 标签内容之外的所有文本
- java - 如何以编程方式在条带上创建平台帐户
- php - Laravel 找不到样式表,我也找不到
- python - 熊猫将元组中的系列附加到空数据框中
- verilog - 使用两个 4 CLA 的 Questasim 中 SystemVerilog 的 8 位进位超前加法器错误
- php - 在 Dokan 中设置每个供应商的最小订单量