简体   繁体   English

Excel VBA:打开工作簿并复制单元格

[英]Excel VBA: Opening Workbooks and Copying Cells

The macro below opens a series of workbooks from a list, then copies some data from them. 下面的宏从列表中打开一系列工作簿,然后从中复制一些数据。 It works fine for the first workbook, then crashes on the second. 它在第一个工作簿上正常工作,然后在第二个工作簿上崩溃。 I've tried changing the order, and it's always the second workbook that causes it to crash. 我尝试过更改顺序,它始终是导致其崩溃的第二个工作簿。

Sub ImportData()
    Dim lastRow As Long
    Dim lastSumRow As Long
    Dim j As Long
    Dim k As Long
    With ActiveSheet
        lastRow = ActiveSheet.Cells(1048576, 1).End(xlUp).Row
    End With
    For k = 2 To lastRow
        k = 2
        lastUsedRow = ThisWorkbook.Sheets("Summary").Cells(1048576, 1).End(xlUp).Row
        If ActiveSheet.Cells(k, 2).Value <> "Imported" Then
            Workbooks.Open Filename:=ThisWorkbook.Path & "\Analysis\" & Cells(k, 1), UpdateLinks:=False
            ActiveWorkbook.Sheets("Summary").Activate
            For j = 3 To 100
                If j Mod 3 = 0 Then
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 1).Value = ActiveWorkbook.Sheets("Summary").Cells(j, 1).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 2).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 2).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 3).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 3).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 4).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 4).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 5).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 2, 2).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 6).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 2, 3).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 7).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 2, 4).Value
                    ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 8).Value = ActiveWorkbook.Sheets("Summary").Cells(j + 1, 5).Value
                End If
            Next j
            ActiveWorkbook.Close
        End If
        ThisWorkbook.Sheets("Setup").Cells(k, 2).Value = "Imported"
    Next k
End Sub

I'm guessing your error is here: 我猜你的错误在这里:

 Workbooks.Open Filename:=ThisWorkbook.Path & "\\Analysis\\" & Cells(k, 1), UpdateLinks:=False 'Ooops ^^^^^ 

The .Activate and .Select calls are convoluted enough that I'm not really going to expend the effort figuring out what should be the active worksheet at that particular point in your code on the second run through the loop. .Activate.Select呼叫进行卷积足够,我不是真的要花费精力搞清楚什么应该是在你的代码通过循环第二次运行特定点活动工作表。 Whatever it is, it's different than it was when you started and an unqualified call to Cells implicitly refers to whatever worksheet is the ActiveSheet at the time. 不管它是什么,它都与您开始时不同,并且对Cells的无条件调用隐式地引用了当时是ActiveSheet任何工作表。 This builds a bad file name (or fails completely) and then the wheels come off. 这将生成错误的文件名(或完全失败),然后滚轮脱落。

The best thing to do is not use the Active* objects at all. 最好的办法是根本不使用Active*对象。 Get references to the objects that you're using, and well, use them. 获取对您正在使用的对象的引用,然后使用它们。 That way there is no chance that you'll get wires crossed. 这样,您就不会有电线交叉的可能性。 While you're at it, you can give them names that make it obvious what you're working with at a glance. 在查看时,您可以给他们命名,使您一眼就能清楚地看到正在使用的内容。

Couple other things before we get to the code that doesn't use Activate and Select . 在获得不使用ActivateSelect的代码之前,请结合其他因素。


lastSumRow is never used and lastUsedRow is never declared. lastSumRow是从来没有使用过lastUsedRow从未声明。 I'm assuming they were supposed to be the same thing. 我假设他们应该是同一回事。 You should put Option Explicit at the top of your modules to avoid this type of error (and worse ones). 您应该将Option Explicit放在模块的顶部,以避免此类错误(甚至更糟)。


These 2 lines of code make very little sense together: 这两行代码在一起几乎没有什么意义:

  For j = 3 To 100 If j Mod 3 = 0 Then 

If you only want to copy every 3rd row, skip all the division and just increment your loop counter with a Step of 3: 如果您只想复制每第3行,请跳过所有除法,仅以3 Step递增循环计数器:

        For j = 3 To 99 Step 3

Note that you can stop at 99, because 100 Mod 3 is never going to be 0 . 请注意,您可以在99处停止,因为100 Mod 3永远不会为0


Your With block here isn't using the captured reference... 您的With块此处未使用捕获的参考...

 With ActiveSheet lastRow = ActiveSheet.Cells(1048576, 1).End(xlUp).Row End With 

...but you continually use this pattern that would be useful in a With block: ...但是您一直使用在With块中有用的这种模式:

 ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 1).Value = ... ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 2).Value = ... ThisWorkbook.Sheets("Summary").Cells((j / 3) + lastUsedRow, 3).Value = ... 

Hard-coding Cells(1048576, 1) will fail on older versions of Excel. 硬编码Cells(1048576, 1)在旧版本的Excel上将失败。 You should use Rows.Count instead. 您应该改用Rows.Count。


As mentioned in the comments, k = 2 creates an infinite loop. 如评论中所述, k = 2创建一个无限循环。


You don't need to repeatedly find the last row of the sheet you're copying to with this code: 您无需使用以下代码重复查找要复制到的工作表的最后一行:

 lastUsedRow = ThisWorkbook.Sheets("Summary").Cells(1048576, 1).End(xlUp).Row 

Each time you go through your " j " loop, the last row increases by one. 每次您执行“ j ”循环时,最后一行将增加一。 Just add 1 to lastUsedRow instead of doing all the row counting gymnastics. 只需将1加到lastUsedRow而不是对所有的体操进行计数。


If you're working with Worksheets , use the Worksheets collection instead of the Sheets collection: 如果您正在使用Worksheets ,请使用Worksheets集合而不是Sheets集合:

 ThisWorkbook.Sheets("Summary") '<--I could return a Chart! 

Put all of that together, and you come up with something like the code below. 将所有这些放在一起,您将得到类似于以下代码的内容。 Note that I have no clue what the ActiveSheet is supposed to be when you start this macro, so I just named the variable it's stored in active . 请注意,当您启动此宏时,我不知道ActiveSheet应该是什么,因此我只是将其命名为存储在active的变量。 It's quite possible that it's one of the other worksheets it grabs a reference too (I have no clue) - if so, you should consolidate them into one reference: 它很可能也是它也获得参考的其他工作表之一(我不知道)-如果是这样,您应该将它们合并为一个参考:

Public Sub ImportData()
    Dim lastRow As Long
    Dim lastUsedRow As Long
    Dim dataRow As Long
    Dim fileNameRow As Long

    Dim active As Worksheet
    Set active = ActiveSheet
    With active
        lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
    End With

    Dim setupSheet As Worksheet
    Set setupSheet = ThisWorkbook.Worksheets("Setup")
    With ThisWorkbook.Worksheets("Summary")
        lastUsedRow = .Cells(.Rows.Count, 1).End(xlUp).Row
        For fileNameRow = 2 To lastRow
            If active.Cells(fileNameRow, 2).Value <> "Imported" Then
                Dim source As Workbook
                Set source = Workbooks.Open(ThisWorkbook.Path & "\Analysis\" & _
                                            active.Cells(fileNameRow, 1), False)
                Dim dataSheet As Worksheet
                Set dataSheet = source.Worksheets("Summary")
                For dataRow = 3 To 99 Step 3
                    .Cells(lastUsedRow, 1).Value = dataSheet.Cells(dataRow, 1).Value
                    .Cells(lastUsedRow, 2).Value = dataSheet.Cells(dataRow + 1, 2).Value
                    .Cells(lastUsedRow, 3).Value = dataSheet.Cells(dataRow + 1, 3).Value
                    .Cells(lastUsedRow, 4).Value = dataSheet.Cells(dataRow + 1, 4).Value
                    .Cells(lastUsedRow, 5).Value = dataSheet.Cells(dataRow + 2, 2).Value
                    .Cells(lastUsedRow, 6).Value = dataSheet.Cells(dataRow + 2, 3).Value
                    .Cells(lastUsedRow, 7).Value = dataSheet.Cells(dataRow + 2, 4).Value
                    .Cells(lastUsedRow, 8).Value = dataSheet.Cells(dataRow + 1, 5).Value
                    lastUsedRow = lastUsedRow + 1
                Next
                source.Close
            End If
            setupSheet.Cells(fileNameRow, 2).Value = "Imported"
        Next
    End With
End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM