Как остановить код VBA?

Скажем, у меня есть кнопка, встроенная в мою электронную таблицу, которая запускает некоторую функцию VBA.

Private Sub CommandButton1_Click()
    SomeVBASub
End Sub

Private Sub SomeVBASub
    DoStuff
    DoAnotherStuff
    AndFinallyDothis
End Sub

Мне бы хотелось иметь какую-то кнопку "отменить", которая остановит выполнение SomeVBASub в любой момент, и я не буду включать Ctrl+Break здесь, потому что я бы как сделать это тихо.

Я предполагаю, что это должна быть довольно распространенная проблема, любые идеи?

Спасибо.

Ответы

Ответ 1

Добавьте еще одну кнопку под названием "CancelButton", которая устанавливает флаг, а затем проверяет этот флаг.

Если у вас есть длинные петли в "stuff", тогда проверьте его там и выйдите, если он установлен. Используйте DoEvents внутри длинных циклов, чтобы убедиться, что пользовательский интерфейс работает.

Bool Cancel
Private Sub CancelButton_OnClick()
    Cancel=True
End Sub
...
Private Sub SomeVBASub
    Cancel=False
    DoStuff
    If Cancel Then Exit Sub
    DoAnotherStuff
    If Cancel Then Exit Sub
    AndFinallyDothis
End Sub

Ответ 2

Как насчет Application.EnableCancelKey - используйте кнопку Esc

On Error GoTo handleCancel
Application.EnableCancelKey = xlErrorHandler
MsgBox "This may take a long time: press ESC to cancel"
For x = 1 To 1000000    ' Do something 1,000,000 times (long!)
    ' do something here
Next x

handleCancel:
If Err = 18 Then
    MsgBox "You cancelled"
End If

Фрагмент из http://msdn.microsoft.com/en-us/library/aa214566(office.11).aspx

Ответ 3

Или, если вы хотите избежать использования глобальной переменной , вы можете использовать редко используемое свойство .Tag пользовательской формы:

Private Sub CommandButton1_Click()
    Me.CommandButton1.Enabled = False 'Disabling button so user cannot push it
                                      'multiple times
    Me.CommandButton1.caption = "Wait..." 'Jamie suggestion
    Me.Tag = "Cancel"
End Sub

Private Sub SomeVBASub
    If LCase(UserForm1.Tag) = "cancel" Then
        GoTo StopProcess
    Else
        'DoStuff
    End If

Exit Sub
StopProcess:
    'Here you can do some steps to be able to cancel process adequately
    'i.e. setting collections to "Nothing" deleting some files...
End Sub

Ответ 4

что сказал jamietre, но

Private Sub SomeVBASub
    Cancel=False
    DoStuff
    If not Cancel Then DoAnotherStuff
    If not Cancel Then AndFinallyDothis
End Sub

Ответ 5

Я делаю это много. Много.: -)

Я привык чаще использовать "DoEvents", но все же имею в виду, что все работает, не проверяя при этом верный метод остановки.

Затем, сегодня, повторив это, я подумал: "Ну, просто дождись до конца через 3 часа" и начал кататься на ленте. Раньше я заметил в разделе "Вид" ленты теги "Макросы", и я подумал, что посмотрю, могу ли я увидеть, как мой бесконечный макрос работает....

Теперь я понимаю, что вы также можете использовать это с помощью Alt-F8.

Тогда я подумал: "Что, если я" сделаю шаг "в другом Макро, это спасет меня? Он сделал:-) Он также работает, если вы входите в свой бегущий макрос (но вы все равно теряете то, что у вас есть), если вы не ленивый программист вроде меня и не объявляете множество "глобальных" переменных, и в этом случае сохраняются глобальные данные: )

К

Ответ 6

~ Для тех, кто использует настраиваемое поле ввода

Private Sub CommandButton1_Click()

DoCmd.Close acForm, Me.Name
End

End Sub

Ответ 7

Это старая запись, но, учитывая название вопроса, опция END должна быть описана более подробно. Это может быть использовано для остановки ВСЕХ ПРОЦЕДУР (не только запуска подпрограммы). Он также может быть использован внутри функции для остановки других подпрограмм (что я считаю полезным для некоторых надстроек, с которыми я работаю).

Как заявляет Microsoft:

Прекращает выполнение немедленно. Сам по себе никогда не требуется, но может быть помещен в любое место процедуры, чтобы завершить выполнение кода, закрыть файлы, открытые с помощью оператора Open, и очистить переменные *. Я заметил, что метод END не описан в деталях. Это может быть использовано для остановки ВСЕХ ПРОЦЕДУР (не только запуска подпрограммы).

Вот иллюстративный пример:

Sub RunSomeMacros()

    Call FirstPart
    Call SecondPart

    'the below code will not be executed if user clicks yes during SecondPart.
    Call ThirdPart
    MsgBox "All of the macros have been run."

End Sub

Private Sub FirstPart()
    MsgBox "This is the first macro"

End Sub

Private Sub SecondPart()
    Dim answer As Long
    answer = MsgBox("Do you want to stop the macros?", vbYesNo)

    If answer = vbYes Then
        'Stops All macros!
        End
    End If

    MsgBox "You clicked ""NO"" so the macros are still rolling..."
End Sub

Private Sub ThirdPart()
    MsgBox "Final Macro was run."
End Sub