【问题标题】:How do you open a workbook whilst a macro is running in another workbook?当宏在另一个工作簿中运行时,如何打开工作簿?
【发布时间】:2019-02-09 03:55:47
【问题描述】:

我遇到了一个问题,我创建了一个从指定时间倒计时到零的 VBA 计时器。这个宏运行了一段时间,因此,当我尝试打开另一个工作簿时没有任何反应,就像宏阻止另一个工作簿打开一样?

我的计时器子

Private Sub Timer15_main(play As Boolean)
 Dim UserInput As String

    If play Then
      UserInput = TextBox1.Value 'this is what the user inputs and how long the timer should run
     Else
      timer_15_pause_button = False
      UserInput = "00:15:00" 'this is what the user inputs and how long the timer should run
    End If

        'validate userinput und ensure hh:mm:ss format
        Select Case Len(UserInput) - Len(Replace$(UserInput, ":", ""))
            Case 2 'input format is hh:mm:ss

            Case 1 'input format is mm:ss
                UserInput = "00:" & UserInput
            Case 0 'input format is ss
                UserInput = "00:00:" & UserInput
            Case Else
                MsgBox "invalid input"
                Exit Sub
        End Select

        'we need to convert the string UserInput into a double and
        'convert it into seconds (Timer uses seconds!)
        Dim SecondsToRun As Long
        SecondsToRun = CDbl(TimeValue(UserInput)) * 24 * 60 * 60
         TextBox4.Value = Format$((SecondsToRun / 24 / 60 / 60) + Time(), "hh:mm:ss")
        Dim TimerStart As Double
        TimerStart = Timer 'remember when timer starts

        Do

             If SecondsToRun - (Timer - TimerStart) < 10 Then
             TextBox1.BackColor = RGB(255, 0, 0)
            End If

            TextBox1.Value = Format$((SecondsToRun - (Timer - TimerStart)) / 24 / 60 / 60, "hh:mm:ss")
            'count backwards from 01:15 format as hh:mm:ss

            DoEvents
            If timer_15_pause_button = True Then
            Exit Sub
            End If


        Loop While TimerStart + SecondsToRun > Timer 'run until SecondsToRun are over
        TextBox1.BackColor = RGB(255, 255, 255)

        'TextBox4.Value = ""

        End Sub

【问题讨论】:

  • 请在您的问题中包含您的计时器的 VBA,否则我们将无法提供太多帮助。
  • 很难在没有看到任何代码的情况下判断。我猜你的计时器涉及某种循环和DoEvents?
  • edit您的帖子包含有问题的“计时器循环”。
  • 如果没有看到您的代码,我们只能说 VBA 代码正在 UI/主线程上运行,并且只要该线程忙于运行您的循环,它就不会做任何其他事情。您需要进入异步范例,以便 UI 线程不会被垄断。在循环体中有DoEvents 不是一个好的解决方案;查看Application.OnTime
  • 取决于表单的显示方式。请附上您的代码。

标签: excel vba


【解决方案1】:

假设表单是这样显示的:

UserForm1.Show
DoSomething

那么表单是modal的,这意味着DoSomething调用在表单关闭之前不会运行。在显示模式表单时,它控制消息循环,并且主机应用程序始终不可用:用户唯一可以与之交互的就是表单。

如果表单显示如下:

UserForm1.Show vbModeless
DoSomething

然后显示窗体,立即运行DoSomething调用;用户仍然可以与宿主应用程序交互,并且表单中的代码可以异步运行。

但是像这样的循环:

Do
    ' do stuff
    DoEvents
Loop While {condition}

是糟糕的设计:没有DoEvents,循环将完全劫持消息循环,模态或非模态不会产生影响,并且主机应用程序可能会“(不响应)”直到循环完成. 使用DoEvents,这是一个忙碌循环,不断地告诉Windows“嘿,你有什么要运行的吗?那就去吧!” - 你要做的是注册一个每秒调用一次的过程来更新表单上的计时器标签。

该过程需要在一个单独的标准模块中 - 理想情况下是显示表单的同一模块,并且理想情况下处理该表单的同一实例。

Option Explicit
Private theForm As UserForm1

Public Sub ShowTheForm()
    If theForm Is Nothing Then Set theForm = New UserForm1
    theForm.Show vbModeless
End Sub

Public Sub OnTimerTick()
    If theForm Is Nothing Then Exit Sub
    theForm.HandleTimerTick
End Sub

现在表单需要公开一个HandleTimerTick 过程,并安排OnTimerTick 宏。因此,您可能有一个 CommandButton 控件,单击该控件即可开始调度循环:

Dim TimerStart As Double

Private Sub CommandButton1_Click()
    ' validate inputs...
    TimerStart = Timer
    Application.OnTime Now + TimeValue("00:00:01"), "OnTimerTick"
End Sub

Public Sub HandleTimerTick()
    'timer has ticked, we're at least 1 second later.
    Dim secondsElapsed As Double
    secondsElapsed = Timer - TimerStart

    'update the textbox accordingly...
    TextBox1.Text = Format$(secondsToRun - secondsElapsed, "hh:mm:ss")

    'now determine if we need to schedule another tick:
    If Int(secondsToRun - secondsElapsed) > 0 Then
        Application.OnTime Now + TimeValue("00:00:01"), "OnTimerTick"
    End If
End Sub

请注意,不再有显式循环,没有 DoEvents:只是一个预定的宏,它告诉表单“嘿,打勾!”并且表单通过更新自身来响应,如果需要,重新安排另一个滴答。

【讨论】:

  • 您好,非常详细的回答,非常感谢您对我的耐心等待并收回反对票。我将在周三再次访问我的电脑,因此接下来将有机会玩你所说的内容,回复和/或接受答案。再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-13
  • 2018-07-27
相关资源
最近更新 更多