停止上一个循环,仅运行最后一个

时间:2020-03-23 11:33:55

标签: excel vba loops

我有以下宏。作为简短描述,每次选择一个新单元格时,它会将参考文本作为滚动文本放在状态栏中。我做到了,因此不会通过将“ Do ... While循环”与“ Do events”一起使用来干扰用户输入,将共享以下代码。 问题是如果我快速单击多个单元格,它会记住以前的循环并全部运行。如何设置宏以停止运行除最后一个循环以外的所有循环?

Option Explicit

Public STATUSTEXT As String
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  STATUSTEXT = "Some text valid only for current selection"
  'FILL THE TEXT AND GOTO EXIT SUB TO SKIP RELEASING STATUSBAR
  charTotal = Len(STATUSTEXT)
  charI = 1

  Do
    charI = charI + 1
    Application.statusBar = Right(STATUSTEXT, charI)
    DoEvents    '@ IMPORTANT
  Loop Until charI >= charTotal

  Application.statusBar = STATUSTEXT

End Sub

1 个答案:

答案 0 :(得分:1)

好吧,我会尝试更好地解释实际情况。

您的向下箭头会触发事件Worksheet_SelectionChange。然后,该宏运行并进入DoEvents循环。此DoEvents允许您再次移动光标并执行其他事件。这意味着您的第一个SelectionChange实际上在DoEvents时停止了,而第二个SelectionChange则触发了。在第二个事件完成后,您将返回到第一个DoEvents事件的SelectionChange,并一直持续到结束。

因此,由于VBA无法进行多线程处理,因此您的事件会堆积很多。它只是在DoEvents处暂停第一个宏,从而触发下一个事件,并在执行以下操作后继续第一个事件:

1. SelectionChange
   2. SelectionChange
      3. SelectionChange
         …
      3. SelectionChange Ends
   2. SelectionChange Ends
1. SelectionChange Ends

所以看起来第一个SelectionChange事件最后运行是因为它在其他事件之间运行。请注意,这不是多线程处理,代码已暂停。

实际问题出在您的DoEvents(如果删除)。 Excel会阻塞用户界面,直到第一个SelectionChange事件结束为止,并且直到第一个事件结束之前才允许运行其他事件。而且,您会看到它在光标停止处结束。但这很慢,因为它等待事件直到执行向下的下一个箭头。

因此,实际上,您只需要取消第一个事件,以防另一个事件运行。请尝试以下操作:

Option Explicit

Public GlobalStatusText As String

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim PrivateStatusText As String
    PrivateStatusText = "Some text valid only for current selection " & Target.Address
    GlobalStatusText = PrivateStatusText

    Dim charTotal As Long, charI As Long
    charTotal = Len(GlobalStatusText)
    charI = 1

    Do
        charI = charI + 1
        Application.StatusBar = Right(GlobalStatusText, charI)
        DoEvents    '@ IMPORTANT
        If GlobalStatusText <> PrivateStatusText Then Exit Sub 'cancel because another event run inbetween
    Loop Until charI >= charTotal

    Application.StatusBar = GlobalStatusText
End Sub

如果另一个事件在其间更改了状态文本,则将取消先前的事件。