工作簿在打开数据提取时计算的足够延迟时间

时间:2016-05-21 19:41:59

标签: excel-vba vba excel

我遇到过这个问题:我编写了一个简单的宏来打开多个工作簿(逐个)从某些单元格中提取数据。这些工作簿的结构都相似。现在,有时似乎打开的工作簿没有足够的时间在宏提取值之前完成单元格中的计算。这意味着宏提取的内容是错误的,例如" #VALUE"或#"#NAME"。但是当手动打开时,细胞计算完美。

在宏提取值之前,有没有办法等待打开的工作簿的计算完成?有没有"等待"功能

谢谢,

2 个答案:

答案 0 :(得分:1)

有一个Wait,但它可能会冻结Excel的执行。这将确保在打开工作簿和最终MsgBox

之间等待2秒
Sub WaitABit()
    Dim d As Date

    Workbooks.Open Filename:="C:\TestFolder\beta.xlsx"

    d = Now
    Do Until Now > d + TimeSerial(0, 0, 2)
        DoEvents
    Loop
    MsgBox "X"
End Sub

DoEvents允许在VBA和Excel之间共享焦点。

答案 1 :(得分:1)

Application.AfterCalculation事件对您有用(https://msdn.microsoft.com/en-us/library/office/bb225813(v=office.12).aspx)吗?

例如,您可以创建一个计算侦听器类,在计算完成时触发事件。每次打开一本书时都可以重新设置该监听器,您可以每次只处理该事件。该类可能看起来像这样(插入一个新类并称之为适当的,我命名为我的CalcListener):

Public Event OnTargetCalculationsComplete()
Private WithEvents mApp As Application
Private mHandled As Boolean
Private mCalculationState As Integer

Public Sub FlagSheetsAsUncalculated(ParamArray targetSheets() As Variant)
    Dim ws As Worksheet
    Dim v As Variant
    Dim calculationState As Integer

    'Set the handled flag to false so event is captured.
    mHandled = False

    'Disable autocalculation.
    Application.Calculation = xlCalculationManual

    'Toggle the EnableCalculation values for each sheet.
    'Flags sheet as requiring calculation.
    For Each v In targetSheets
        Set ws = v
        ws.EnableCalculation = False
        ws.EnableCalculation = True
    Next

    'Force calculation.
    Application.Calculate

    'Restore calculation state.
    Application.Calculation = mCalculationState

End Sub

Private Sub mApp_AfterCalculate()
    'Handle the event if flag is false
    If Not mHandled Then
        'Toggle the handled flag and fire the event.
        mHandled = True
        RaiseEvent OnTargetCalculationsComplete
    End If
End Sub

Private Sub Class_Initialize()
    Set mApp = Application
    'Save the calculation state.
    mCalculationState = Application.Calculation
    'Disable autocalculation.
    Application.Calculation = xlCalculationManual
End Sub

你可以创建第二个extracter类来打开工作簿,并且只有在每个OnTargetCalculationsComplete被触发时才能发挥作用。在这个例子中,我创建了一个新类,并将其命名为ValueExtracter

Private WithEvents mCalcListener As CalcListener

Private Sub mCalcListener_OnTargetCalculationsComplete()
    'This routine will be called just once when the
    'target sheets have calculated.

    'Put your code here that should follow the calculation
    MsgBox "Calculations on target sheet(s) are complete"
    '...'

End Sub

Public Sub OpenBooks()
    Dim bk As Workbook

    'Instantiate the calculation listener
    Set mCalcListener = New CalcListener

    'Run your loop here to open the workbooks.
    'This example has just one workbook.

    Set bk = Workbooks.Open("C:\Users\User\Documents\StackOverflow\events.xlsm")

    'Set the sheets that you wish to (re-)calculate.
    With bk.Worksheets
        mCalcListener.FlagSheetsAsUncalculated .Item(1), .Item("Sheet2")
    End With

End Sub

要运行它,只需将以下代码添加到您的模块中:

Public Sub RunMe()
    Dim oValueExtracter As ValueExtracter

    Set oValueExtracter = New ValueExtracter
    oValueExtracter.OpenBooks
End Sub

这是一个模块化的例子,因为其他人可能只想要代码的监听器部分,但如果你愿意的话,你可以将它们全部归为一类。