如何停止运行VBA代码?

16

假设我在电子表格中嵌入了一个按钮,以启动一些VBA功能。

Private Sub CommandButton1_Click()
    SomeVBASub
End Sub

Private Sub SomeVBASub
    DoStuff
    DoAnotherStuff
    AndFinallyDothis
End Sub

我想要一个机会,有一种“取消”按钮可以在任意时刻停止SomeVBASub的执行,而且我不想在这里涉及Ctrl+Break,因为我希望静默地完成它。

我猜这应该是相当普遍的问题,有什么想法吗?

谢谢。

7个回答

22

添加一个名为"CancelButton"的按钮,该按钮设置一个标识符,然后检查该标识符。如果在"stuff"中有长循环,请在那里进行检查,并在设置的情况下退出。在长循环内使用DoEvents以确保UI正常工作。

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
我有一个想法来实现这种逻辑,但是在每个可能的过程退出点(实际上,在几乎每个字符串后面)放置“DoEvents-Check flag”链让我感到相当尴尬。 - Kirill Leontev
2
@Faheemitian所描述的方法可以避免这种情况,但它与Ctrl+Break的作用几乎相同。这取决于您对用户界面(例如按钮)有多少控制权以及您可以允许代码退出的位置。如果UI不重要且代码退出可以是任意的(例如没有依赖关系、回滚等问题),那么这将是最简单的方法。通常为取消标志添加陷阱并不会太麻烦,因为大部分执行时间都会花费在循环中,但也许在您的情况下并非如此。 - Jamie Treworgy
2
让我补充一下,如果你担心用户点击“取消”后过程没有立即停止(因此需要你添加如此多的检查),我通常会在单击程序中禁用“取消”按钮并将文本更改为“请稍候...”或类似的内容,以便用户知道应用程序实际上正在考虑他们的请求。 - Jamie Treworgy

9

关于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/zh-cn/library/aa214566(office.11).aspx的片段:


2

或者,如果你想避免使用全局变量,你可以使用用户窗体的很少使用的.Tag属性:

Private Sub CommandButton1_Click()
    Me.CommandButton1.Enabled = False 'Disabling button so user cannot push it
                                      'multiple times
    Me.CommandButton1.caption = "Wait..." 'Jamie's 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

0

这是一篇旧文章,但考虑到这个问题的标题,END选项应该更详细地描述。它可以用于停止所有过程(不仅仅是正在运行的子程序)。它也可以在函数内部使用,以停止其他子程序(我发现对于我使用的某些插件非常有用)。

正如微软所述

立即终止执行。本身不需要,但可以放置在过程中的任何位置以结束代码执行、关闭使用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

0

就像jamietre所说的,但是

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

0

我经常这样做。非常频繁。:-)

我已经习惯了更频繁地使用“DoEvents”,但仍然倾向于在没有真正双重检查确定的停止方法的情况下启动事物。

然后,今天,我又做了一次,我想,“好吧,就等待3小时的结束吧”,然后开始在功能区中四处浏览。早些时候,我注意到功能区的“查看”部分有一个“宏”下拉菜单,我想看看是否能够看到我的无尽宏运行....

现在我意识到你也可以使用Alt-F8来打开它。

然后我想,如果我“步入”不同的宏,那会救我吗?它确实救了我 :-) 如果您步入正在运行的宏(但您仍然失去了您的位置),除非您像我这样是一个非常懒惰的程序员并声明了许多“全局”变量,在这种情况下,全局数据将被保留 :-)

K


0

~ 对于使用自定义输入框的用户

Private Sub CommandButton1_Click()

DoCmd.Close acForm, Me.Name
End

End Sub

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