Ранний выход из вложенных циклов VBA

У меня есть скрипт vba, который должен копировать данные с одного листа на другой. Это делается с помощью трех вложенных циклов for. Пошаговое выполнение кода при отладке кажется, что они работают отлично, но когда запускается скрипт vba, они останавливаются слишком рано. В противном случае скрипт vba работает.

Я смотрел на это в течение нескольких часов и не могу понять, что может привести к преждевременной остановке циклов. Я надеюсь, что решение - это что-то простое, что я пропустил, но я в настоящей потере, не в первый раз с тех пор, как начал это.

Лист организован следующим образом:

Sheet1 содержит данные для копирования.

  • Каждая строка содержит отдельный ответ, которых в тестовых данных 55.
  • Лист содержит девять блоков данных, названных Episode 1-9. Каждый эпизод содержит столбец, в котором целое число представляет время начала, окончания и интервала.
  • В тестовых данных каждый эпизод идентичен, за исключением времени начала/окончания.
  • Максимальное значение EndTime – 36.
  • Тестовые данные относятся только к первым четырем блокам Episode, поэтому Episode4 содержит EndTime=36 для каждой строки.

Лист 2, куда должны быть помещены данные. - Первый столбец содержит каждый RespondentID, скопированный в 36 строк. - Второй столбец содержит числа 1–36, таким образом, представляющие этот временной интервал для этого респондента. что Респондент/Время ставится. Эти области 36x11 названы «Response1-55» в тестовых данных.

Логика скрипта vba следующая:

Счетчики: - счетчик n для количества респондентов - счетчик r для количества эпизодов - счетчик i для строк в копируемых ответах.

->Для каждого ответа (начиная с n=1 до респондентов)
--> Выберите первый эпизод (начиная с r=1 до 9)
--->Для каждого эпизода
---> Прочитайте время начала, окончания и интервала
--->Начиная с i = Начало до i=Конец, скопируйте соответствующие ячейки из n-й строки r-го эпизода
--->Скопируйте эти ячейки к i-й строке текущего ответа на листе2
--->Когда вы достигнете EndTime текущего эпизода, перейдите к следующему (следующему r)
-->Если эпизод вы только что закончили имеет 36 в качестве конечного времени, затем переходите к следующему ответу или продолжайте, пока не закончатся эпизоды.
->Следующий ответ

При отладке код делает именно это.

Однако, когда я запускаю сценарий vba на тестовом листе, он работает только для эпизодов 1 и 2. Данные из эпизодов 3 и 4 не копируются. Ничто не копируется на свое место, а копируемые данные верны во всех отношениях. Сообщений об ошибках нет ни на одном этапе.

Если бы кто-нибудь мог предположить, почему это может происходить, я бы построил для них настоящую церковь. Ответ также можно добавить сюда: https://stackoverflow.com/questions/9594693/vba-copy-from-a-union-of-two-ranges-to-a-row-of-another-range В котором еще нет раздела для 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 копирует из объединения двух диапазонов в строку другого диапазона, но с тех пор код немного изменился, и это другая проблема.

Еще раз большое спасибо за любую помощь, которая может прийти из этого. Я смотрю на это часами и не вижу, где ошибка. Любое руководство вообще очень ценится.


person TornHair    schedule 08.03.2012    source источник
comment
Возможно, на каком-то этапе вам захочется пересмотреть весь дизайн электронной таблицы — использование именованных диапазонов так, как вы это делаете, подвержено ошибкам и трудно отлаживается (как вы заметили!). Excel великолепен и прост в использовании с табличными данными — вместо 9 отдельных диапазонов вы можете иметь один блок с дополнительным столбцом, содержащим, например, номер эпизода. Это простое изменение значительно улучшит читаемость и код.   -  person assylias    schedule 08.03.2012
comment
Еще раз спасибо за отзыв. Лист на самом деле создается программой, отсюда некоторый беспорядок, но я понимаю, что вы имеете в виду о смещении выделения, а не об использовании диапазонов. Текущий метод очень близок, но если я не смогу заставить его работать полностью, я буду использовать предложенный подход. В этом случае я попрошу вас указать это как ответ, чтобы я мог его принять. Еще раз спасибо за изучение этого, снова. Очень признателен.   -  person TornHair    schedule 08.03.2012


Ответы (1)


Если бы я мог, я бы разместил это как комментарий, но это слишком длинно. Итак, вот он как запрос/потенциальное решение

Я думаю, что ваши ссылки на диапазон являются проблемой

Приведенный ниже код представляет собой урезанную версию вашего кода.

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

введите здесь описание изображения

person brettdj    schedule 08.03.2012
comment
Если вы не знаете, как циклически выполнять код построчно, например. получить желтую полосу выше, вы должны следовать приведенным здесь советам по анализу макросов (excel4business.com/videos/analyzing-macros-error-handling.php). В основном, если вы вводите точку останова, например. Затем n вы можете оценить различные переменные/компоненты, когда код выходит из цикла r. - person Ed Bolton; 08.03.2012
comment
Спасибо за комментарий. Я прошел код таким образом, но не знал, как проверить адрес переменных диапазона, как показано в приведенном выше ответе. Я думаю, что приведенный выше ответ взломал его: счетчики циклов работают правильно, как показала отладка, но копирование из неправильного эпизода. Спасибо за ссылку, сейчас посмотрю. - person TornHair; 08.03.2012
comment
Большое спасибо, я проверил оригинал, составив диапазон и посмотрев его адрес в отладке, как показано, и смещение именно то, что происходит. Я думал, что настройка строки curr_test в вашем примере будет выбирать столбцы с 1-го по 11-й из (три строки вверх от...) n-й строки текущего эпизода. Теперь, когда проблема ясна, я поищу, что вводит это смещение. Большое спасибо за помощь и @assylias за альтернативное решение. - person TornHair; 08.03.2012
comment
Хорошо, теперь я понимаю, что имелось в виду под синтаксисом, используемым для объявления диапазона «а», вызывающего смещение. Изменение этой строки на a = Sheets(1).Range(curr_epCells(n, 5), curr_ep.Cells(n, 16)) решает проблему, и макрос теперь работает, как и планировалось. Я не могу отблагодарить вас за помощь с этими проблемами, это заняло у меня два полных дня и заняло бы намного больше, если бы не оказанная помощь. Благодарность. Много всего. - person TornHair; 08.03.2012