VBA嵌套循环提前退出

3
我有一个VBA脚本,它应该将数据从一个工作表复制到另一个工作表。它通过三个嵌套的for循环实现。在调试中逐步执行代码时,看起来这些循环完全正常,但当运行VBA脚本时,它们似乎过早地停止。否则,VBA脚本可以正常工作。
我已经盯着这个问题看了几个小时,但无论如何都没有发现导致循环提前停止的原因。我希望解决方案是我忽略的某个简单问题,但我真的不知道该怎么做,这并不是自从开始以来第一次遇到这种情况。
这个工作表的组织方式如下: Sheet1:包含要复制的数据。
- 每行包含一个单独的响应,在测试数据中有55个。 - 工作表包含九个数据块,分别命名为Episode 1-9。每个剧集都包含包括开始时间、结束时间和间隔时间的整数列。 - 在测试数据中,每个剧集都相同,除了开始/结束时间不同之外。 - EndTime 的最大值是36。 - 测试数据仅覆盖前四个 Episode 块,因此 Episode4 对于每一行都包含 EndTime=36。
Sheet2:数据要去的地方
- 第一列包含要复制的每个 RespondentID,复制到 36 行。 - 第二列包含数字1-36,因此表示该受访者的时间槽。 - 其后的 11 列包含从 Sheet1 复制到该受访者/时间的区域。这些36 x 11区域在测试数据中被命名为"Response1-55"。
该VBA脚本的逻辑如下:
计数器: - n 计数器表示受访者数量。 - r 计数器表示剧集的数量。 - i 计数器表示正在复制的响应行号。
对于每个响应(从n=1开始到Respondents): - 选择第一个剧集(从r=1开始到9)。 - 对于每个剧集: - 读取开始、结束和间隔时间。 - 从i = Start 到 i = End 复制第n行的第r个剧集相关单元格。 - 将这些单元格复制到Sheet2当前响应的第i行。 - 当达到当前剧集的 EndTime 时,转到下一个剧集(下一个r)。 - 如果您刚刚完成的剧集的EndTime是36,则转到下一个响应,否则继续直到用完所有剧集为止。 - 下一个响应。
在调试中,代码似乎正是这样执行的。
但是,当我在测试表上运行VBA脚本时,它仅适用于第1和第2集。第3集和第4集的数据未复制。也没有任何错误消息。
如果有人能够提供为什么会出现这种情况的建议,我将为他们建立一座实际的教堂。答案也可以在这里添加:https://stackoverflow.com/questions/119323/nested-for-loops-in-different-languages,目前还没有针对VBA的部分。
测试表的链接在这里:http://dl.dropbox.com/u/41041934/MrExcelExample/TornHairExampleSheet.xlsm 代码的相关部分在这里。
Sub PopulateMedia()
    Application.ScreenUpdating = False

    'Count the total number of response rows in original sheet
    Dim Responses As Long, n As Integer, i As Integer, r As Integer
        Responses = (Sheets("Sheet1").UsedRange.Rows.Count - 3) ' equals 55 in test sheet

    'For each response...
    For n = 1 To Responses
        i = 1 'Reset i for new response
            Dim curr_resp As Range
                Set curr_resp = Sheets(2).Range("Response" & n) 'Define a range containing all response data

            For r = 1 To 9  'For each episode...
                Dim curr_ep As Range 'Define a range containing episode data for all responses
                    Set curr_ep = Sheets(1).Range("episode" & r)

                Dim Stime As Integer, Etime As Integer, Itime As Integer 'Variables contain start, end and inter-episode times
                    Stime = curr_ep.Cells(n, 1)
                    Etime = curr_ep.Cells(n, 17)
                    Itime = curr_ep.Cells(n, 19)

                    For i = Stime To (Etime + Itime) 'for each time-slot...
                        If i <= Etime Then
                          Dim a As Variant
                            a = curr_ep.Range(curr_ep.Cells(n - 3, 1), curr_ep.Cells(n - 3, 11))
                            curr_resp.Rows(i) = a 'Copy data from above current episode to current response for slots between Stime and Etime
                        End If
                    Next i
                If Etime = 36 Then Exit For
             Next r
     Next n

    Application.ScreenUpdating = True
End Sub

我需要说明的是,我已经从这个网站VBA copy from a union of two ranges to a row of another range得到了帮助,但是代码稍有改动,这是一个不同的问题。

再次感谢您的任何帮助。我已经盯着这个问题几个小时了,但是仍然看不出错误在哪里。非常感谢您的任何指导。


1
你可能需要重新考虑电子表格的整体设计 - 使用命名区域的方式容易出错且难以调试(正如你所注意到的!)。Excel非常适合处理表格数据 - 你可以使用一个块来代替9个单独的区域,并添加一个包含剧集编号的额外列。这个简单的改变将显著提高可读性和代码质量。 - assylias
再次感谢您的反馈。该表格实际上是由程序生成的,因此有些混乱,但我明白您的意思,即偏移选择而不是使用范围。当前的方法非常接近,但如果我无法完全使其正常工作,我将使用建议的方法。在那种情况下,我会发送消息请您将其作为答案放置,以便我可以接受它。再次感谢您对此事的关注。非常感激。 - TornHair
1个回答

5

如果可以的话,我会把这个作为评论发布,但是它太长了。所以这里是一个查询/潜在解决方案

我认为你的范围引用是问题所在。

以下代码是你代码的精简版本。

curr_ep 是一个名为 episode1 的命名范围。它具有范围地址 $Y$4:$AQ$58

当你循环遍历变量 a 时,你使用以下语法设置一个范围:
a = curr_ep.Range(curr_ep.Cells(n - 3, 1), curr_ep.Cells(n - 3, 11))
它相当于 a = curr_ep.Range("Y2:AQ2")

这意味着你实际上正在查看的是AW2:BG2而不是你可能想要的 Y2:AQ2,也就是说,你正在建立一个不需要的偏移量。

Sub PopulateMedia()
    n = 1
    r = 1
    Dim curr_ep As Range
    Dim curr_test As Range
    Set curr_ep = Sheets(1).Range("episode" & r)
    Set curr_test = curr_ep.Range(curr_ep.Cells(n - 3, 1), curr_ep.Cells(n - 3, 11))
End Sub

enter image description here


1
如果您不知道如何逐行循环代码,例如获取上面的黄色条,则应按照此处有关分析宏的建议进行操作(http://www.excel4business.com/videos/analyzing-macros-error-handling.php)。基本上,如果您在“Next n”上引入断点,那么当代码退出r循环时,您可以评估各种变量/组件。 - Ed Bolton
谢谢您的评论。我确实按照那种方式逐步执行了代码,但不知道如何检查范围变量的地址,就像上面的答案所示。我认为上面的答案已经解决了问题:循环计数器正在正确工作,正如调试所显示的那样,但是从错误的剧集中复制。感谢提供链接,我现在会查看它。 - TornHair
非常感谢,我通过创建一个范围并在调试中观察其地址来检查原始数据,偏移量正好是发生的事情。我以为你示例中设置curr_test的那一行将选择当前剧集的(从第三行向上的...)第1到第11列。现在问题已经清楚了,我会寻找是什么引入了这个偏移量。非常感谢您的帮助,@assylias提供的替代方案也很有用。 - TornHair
1
好的,我现在明白了声明范围'a'所使用的语法导致了偏移的含义。将该行更改为a = Sheets(1).Range(curr_epCells(n, 5), curr_ep.Cells(n, 16))解决了问题,宏现在按计划工作。我非常感谢您对这些问题的帮助,这让我花了整整两天的时间,如果没有提供的帮助,可能需要更长的时间。感激之情,非常多。 - TornHair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接