При повторении макроса возникает ошибка после нескольких прогонов - PullRequest
1 голос
/ 28 мая 2020

Образец книги У меня есть повторяющиеся макросы, которые зависают с ошибкой после выполнения от 500 до 600 раз. Количество запусков, которое мне нужно запускать, будет каждый раз меняться, но в основном будет около 2000 раз. Уведомление об ошибке

Строка кода, на которой он останавливается MaE.png

Ниже приведен весь код, несколько макросов запускаются друг за другом и вызывают другие до завершения отчета. Он работает нормально, если выполняется менее 500 раз.

    Sub Start_New_Report()
'
' Start_New_Report Macro
' Clear Old data and prepare for new lines.
'
    Application.ScreenUpdating = False
    Sheets("Filtered Report").Select
    Range("A2:I1048576").Select
    Selection.ClearContents
    Range("A2").Select
    ActiveCell.FormulaR1C1 = "1"

    Call Filter_Data

End Sub

Sub Filter_Data()
' Filter raw Syteline data to usable lines

    Worksheets("Filtered Report").Range("B2").Value = _
        Worksheets("PurchaseOrderStatus").Range("A5:E5").Value
    Worksheets("Filtered Report").Range("C2").Value = _
        Worksheets("PurchaseOrderStatus").Range("A6:C6").Value
    Worksheets("Filtered Report").Range("D2").Value = _
        Worksheets("PurchaseOrderStatus").Range("A7:F7").Value
    Worksheets("Filtered Report").Range("E2").Value = _
        Worksheets("PurchaseOrderStatus").Range("J5").Value
    Worksheets("Filtered Report").Range("F2").Value = _
        Worksheets("PurchaseOrderStatus").Range("O7").Value
    Worksheets("Filtered Report").Range("G2").Value = _
        Worksheets("PurchaseOrderStatus").Range("P6:R6").Value
    Worksheets("Filtered Report").Range("H2").Value = _
        Worksheets("PurchaseOrderStatus").Range("P7:T7").Value
    Worksheets("Filtered Report").Range("I2").Value = _
        Worksheets("PurchaseOrderStatus").Range("V7").Value

    Call Clear_Raw_Data

End Sub

 Sub Clear_Raw_Data()
' Clear Raw Data Lines

    Sheets("PurchaseOrderStatus").Select
    Rows("5:7").Delete

    Call Blank_Cells

End Sub

Sub Blank_Cells()
' Check if blank cells exist in current line

    Sheets("Filtered Report").Select
    Range("B2").Select
If IsEmpty(Range("B2").Value) Then
    Call Copy_Up
Else
    Call Blank_Cells_Raw_Data
End If

End Sub

Sub Copy_Up()
'
' Copy Data Up from line below if cells are empty.
'
    Range("B3:D3").Copy Range("B2:D2")

    Call Blank_Cells_Raw_Data

End Sub

Sub Blank_Cells_Raw_Data()

    Sheets("PurchaseOrderStatus").Select
    Range("V5").Select
If IsEmpty(ActiveCell.Value) Then
    Call Finalize_Report
Else
    Call Clear_for_Next_Line
End If

End Sub

Sub Clear_for_Next_Line()
'
' Clear_for_Next_Line Macro
'
' Insert_line Macro
    Sheets("Filtered Report").Select
    Range("2:2").Insert CopyOrigin:=xlFormatFromRightOrBelow

' Create next index number

    Worksheets("Filtered Report").Range("A2").Value = _
        Worksheets("Filtered Report").Range("A3").Value + 1

    Call Filter_Data

End Sub

Sub Finalize_Report()
'
' Finalize_Report Macro
' Finish report and sort the order.
'
    Sheets("Filtered Report").Select
    Range("A1") = "Index"
    Columns("A:I").Sort key1:=Range("A2"), _
      order1:=xlAscending, Header:=xlYes

End Sub

1 Ответ

1 голос
/ 30 мая 2020

По сути, я отказался от всей модели, в которой отдельные подпрограммы вызывали друг друга последовательно, и заменил ее одной подпрограммой, которая выполняет все функции.

  • Я решил переписать пример кода, удалив использование .Select (см. ссылка ) и определив переменные рабочего листа, когда это возможно.

  • Еще одна вещь, которую я заметил, была в Blank_Cells и Blank_Cells_Raw_Data, я не думаю, что вы хотели использовать здесь IsEmpty (который проверяет, инициализирована ли переменная; см. ссылка ), а скорее определяет, пуста ли сама ячейка. Я изменил это на If Application.WorksheetFunction.CountA(Range) = 0 в обоих случаях.

  • В Filter_Data я заметил, что вы устанавливаете значение одной ячейки (например, B2) на значение нескольких ячейки (например, A5:E5). При тестировании просто установите для первой ячейки первое значение в заданном диапазоне (например, ячейка A5). Предполагая, что вы не хотели делать что-то вроде Application.WorksheetFunction.Sum(ws2.Range("A5:E5")) (суммировать значения в этих ячейках), я просто изменил их, чтобы получить первую ячейку.

  • Я изменил Filter_Data и несколько других пятна, чтобы использовать ссылки на ячейки / столбцы вместо диапазонов, когда это возможно.
  • В Copy_Up я заменил функцию .Copy фактической установкой значений ячеек (Копирование иногда может показаться странным, поэтому я стараюсь не использовать его, когда это возможно).
  • Кроме того, поскольку .Delete и .Insert значительно замедляют выполнение макроса, я использовал метод, который избегает этого, просто проверяя одну группу из трех строк на «PurchaseOrderStatus» за раз, затем переходя к следующей и записывая в первую свободную в строке "Отфильтрованный отчет" вместо того, чтобы вставлять новые строки вверху. Это значительно ускорило макрос (от ~ 35 секунд до менее секунды).

Option Explicit

Sub Start_New_Report()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng As Range
Dim newRow As Long, lastRow As Long, x As Long

Set ws1 = ThisWorkbook.Sheets("Filtered Report")
Set ws2 = ThisWorkbook.Sheets("PurchaseOrderStatus")

' Turn screen updating / calculation off for speed
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

' Clear Old data and prepare for new lines.
ws1.Range(ws1.Cells(2, 1), ws1.Cells(10000, 9)).ClearContents
ws1.Cells(2, 1) = 1

' Define last row
lastRow = ws2.Cells(ws2.Rows.Count, 1).End(xlUp).Row - 2

' Iterate through all groups of 3 rows on PurchaseOrderStatus sheet
For x = 5 To lastRow Step 3

    ' Determine new row to write to
    newRow = ws1.Cells(ws1.Rows.Count, 1).End(xlUp).Row

    ' Filter raw Syteline data to usable lines
    ws1.Cells(newRow, 2) = ws2.Cells(x, 1)
    ws1.Cells(newRow, 3) = ws2.Cells(x + 1, 1)
    ws1.Cells(newRow, 4) = ws2.Cells(x + 2, 1)
    ws1.Cells(newRow, 5) = ws2.Cells(x, 10)
    ws1.Cells(newRow, 6) = ws2.Cells(x + 2, 15)
    ws1.Cells(newRow, 7) = ws2.Cells(x + 1, 16)
    ws1.Cells(newRow, 8) = ws2.Cells(x + 2, 16)
    ws1.Cells(newRow, 9) = ws2.Cells(x + 2, 22)

    ' Copy Data Up from line below if cells are empty.
    If Application.WorksheetFunction.CountA(ws1.Cells(newRow, 2)) = 0 Then
        ws1.Cells(newRow, 2) = ws1.Cells(newRow - 1, 2)
        ws1.Cells(newRow, 3) = ws1.Cells(newRow - 1, 3)
        ws1.Cells(newRow, 4) = ws1.Cells(newRow - 1, 4)
    End If

    ' Create next index number if not the last row
    If x <> lastRow Then
        ws1.Cells(newRow + 1, 1) = ws1.Cells(newRow, 1).Value + 1
    End If

Next x

' Finish report and sort the order.
ws1.Range(ws1.Columns(1), ws1.Columns(9)).Sort _
    Key1:=ws1.Cells(2, 1), _
    Order1:=xlAscending, _
    Header:=xlYes

' Turn screen updating / calculation back on
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic

End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...