【问题标题】:VBA : Disabling Listbox while macro is runningVBA:在宏运行时禁用列表框
【发布时间】:2017-04-17 21:26:57
【问题描述】:

问题

我有一个宏(我称之为launch_macro),它通过双击用户窗体列表框(ListBox1_DblClick)来启动。

我的问题是,如果用户在宏仍在运行时再次双击,则宏将在第一次执行完成后再次启动,而不管我在宏运行时禁用 ListBox 的事实正在运行。

代码和测试

Private sub ListBox1_DblClick(Byval Cancel as MSForms.ReturnBoolean)

   (....Logging...)

    If Not Cancel Then
        Me.ListBox1.Enabled = False
        (...DisplayStatusBar / ScreenUpdating / ListBox1.BackColor...)
        launch_macro
        (...DisplayStatusBar / ScreenUpdating / ListBox1.BackColor...)
        Me.ListBox1.Enabled = True

    End If

End sub

似乎 Excel 记录/排队 ListBox1_DblClick 事件(以供将来执行),而关联的 ListBox 已禁用。为什么 ?我怎样才能防止这种情况发生?

我也试过了,没有成功:

  • 锁定Me.ListBox1.Locked = True
  • Doevents : 在Me.ListBox1.Enabled = False 之后添加DoEvents
  • 启用事件 :Application.EnableEvents = False
  • ma​​croLaunched 变量:使用变量来检查宏是否已经启动(macroLaunched = TrueListBox1_DblClick 事件的开头和macroLaunched = False 在结尾)。这不起作用,因为第二次执行是在第一个事件结束后启动的(因此变量被设置回False)。 (并且在 Dbl_Click 事件范围之外将变量设置回 False 是不可接受的,因为用户需要能够再次立即启动宏(但不是在第一次执行仍在运行时)。
  • 添加延迟(仅用于测试目的):我在启动宏之后立即添加了 10 秒延迟 (Application.Wait)。然后我在 1 秒内双击了两次。第二次执行仍然启动。我通过记录进行了检查:第二个 ListBox1.Dbl_Click 事件在第一个事件之后被 Excel 12 秒“记录”。

注意:我使用的是 Office Standard 2013

当前的“解决方案”

这个技巧改编自 A.S.H 答案(以减少延迟):

Private sub ListBox1_DblClick(Byval Cancel as MSForms.ReturnBoolean)
   Static nextTime As Single

   If Timer < nextTime then
        Log_macro "Event canceled because Timer < nextTime : " & Timer
        Exit Sub
   End if

   (....Logging...)

    If Not Cancel Then
        (...DisplayStatusBar / ScreenUpdating / ListBox1.BackColor...)
        launch_macro
        (...DisplayStatusBar / ScreenUpdating / ListBox1.BackColor...)

    End If

    nextTime = Timer + 0.5
    Log_macro "nextTime = " & nextTime

End sub

它“成功了”,但我仍然不喜欢 ListBox1 仍处于启用状态且 Excel 仍在排队事件,因此我需要估计用户可能 Dbl_Click 的时间(取决于宏需要多长时间)估计我需要多少延迟(目前需要 0.5 秒才能处理(和记录)至少 10 个取消的事件)。此外,Excel 似乎不太喜欢(就性能而言)在宏运行时排队事件。

【问题讨论】:

  • @YowE3K。刚刚测试过EnableEvents;那也行不通。 :-(
  • 是的 - 我意识到这是在一个实际的表格上,所以决定可能 不是 会是正确的答案,所以删除了评论。
  • 我刚试过这个并在宏运行时再次双击列表框没有再次触发代码,除非我包含DoEvents(因为用户活动被锁定),并且在代码中使用DoEvents,第二次执行与第一次执行同时运行 - 即它没有等待第一次执行完成。
  • 在launch_macro之前,检查macroLaunched是否为真。如果是,请不要启动宏。如果不是,请在launch_macro 之前将其设置为true。当可以再次启动宏时,在 doubleClick 事件之外设置 macroLaunched。
  • @Tibo 也许我的想法不够清楚。请尝试下面我的答案中的方法。

标签: vba excel listbox ms-office


【解决方案1】:

好吧,我会发布我的建议,希望您尝试一下,因为可能是被误解了。这个想法是,一旦宏完成,我们在再次处理双击事件之前设置 n 秒(比如 2 秒)的延迟。这样一来,在宏执行期间排队的 dbl-click 在这两秒内将被无效处理。

Private Sub ListBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    Static NextTime As Variant ' Will set a barrier for launching again the macro 
    If Not IsEmpty(NextTime) Then If Now < NextTime Then Exit Sub

    ListBox1.Enabled = False
    ' Any event code
    launch_macro
    ' ...
    ListBox1.Enabled = True

    NextTime = Now + TimeSerial(0, 0, 2) ' dbl-click events will have no effects during next 2 seconds
End Sub

【讨论】:

  • 如果你将NextTime定义为Date,你就不需要检查IsEmpty,它会被初始化为第0天,所以Now不会小于它的初始值价值。
  • @YowE3K 好地方。由 OP 来更改它,我个人更喜欢这样保留它,因为我清楚地看到它,但这只是个人选择:)
  • @A.S.H 谢谢。使用静态变量方法可能会成功,但是使用 Static NextTime As Single 和使用 Timer 而不是 Now 甚至应该让我使用 0.1 秒的延迟,这使得 ListBox1.Enabled 语句无用。我明天会测试一下,因为现在快凌晨 2 点了(即Const myNeededSleepTime As Single = 6*3600nextTime = Timer + myNeededSleepTime...)
  • @Tibo Dim 也一样好。梦想 :)
  • 您的建议(结合nextTime As SingleTimer)“成功了”(有合理的延迟);谢谢。但是我仍然不喜欢 ListBox1 仍然启用并且 Excel 仍在排队事件,因此我需要估计用户可能 Dbl_Click 多少时间(取决于宏需要多长时间)来估计我需要多少延迟(目前0.5 秒能够处理(和记录)至少 10 个被取消的事件)。此外,似乎 Excel 并不真正喜欢(就性能而言)在宏运行时排队事件。
【解决方案2】:

您可以使用变量将代码的关键部分锁定一段时间。 下面的例子在 Excel 工作簿的 Sheet2 中锁定了 Test() 函数的关键部分。

Option Explicit
Private booIsRunning As Boolean
Private Sub Test()

    If Not booIsRunning Then
        booIsRunning = True
        Debug.Print "Hello."
        Application.OnTime Now + TimeValue("00:00:02"), "Sheet2.UnlockTest"
    End If
End Sub

Public Sub UnlockTest()
    booIsRunning = False
End Sub

【讨论】:

  • 谢谢。这可能会奏效,但我不太愿意使用 Application.OnTime 和多个 subs 来解决这样一个简单的问题)。至于技巧,我更喜欢 A.S.H 的回答(我目前的解决方案)
  • 感谢您的反馈。如果这是一个用户表单,那么可能会找到更好的方法here
  • 我刚刚看了看。它确实是userform,但我很确定它不会起作用,因为它不是引发不同事件的“更改属性”,而是引发不同事件的同一事件(ListBox1_DblClick)(ListBox1_DblClick)已经在执行。正如我所说的关于“变​​量”方法(称为macroLaunched或blockEvents):“这不起作用,因为第二次执行是在第一个事件结束后启动的(因此变量被设置回到False)。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 2013-12-10
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多