2016-05-21 6 views
0

Ich habe dieses Problem festgestellt: Ich schrieb ein einfaches Makro, um mehrere Arbeitsmappen (eins nach dem anderen) zu öffnen, um Daten aus bestimmten Zellen zu extrahieren. Diese Arbeitsmappen sind alle in der Struktur ähnlich. Nun scheint es manchmal so zu sein, dass die geöffnete Arbeitsmappe nicht genügend Zeit hat, um die Berechnung in den Zellen abzuschließen, bevor das Makro die Werte extrahiert. Es bedeutet, dass die Makroextrakte fehlerhaft sind, wie "#VALUE" oder "#NAME". Beim manuellen Öffnen werden die Zellen jedoch perfekt berechnet.Ausreichende Verzögerungszeit für Arbeitsmappen zu berechnen, wenn für Datenextraktion geöffnet

Gibt es eine Möglichkeit zu warten, bis die Berechnung der geöffneten Arbeitsmappe abgeschlossen ist, bevor das Makro die Werte extrahiert? Gibt es eine "Warte" -Funktion?

Danke,

Antwort

1

Es gibt eine Wait, aber es wird wahrscheinlich Excel Hinrichtung einfrieren. Dies wird eine 2 Sekunden Wartezeit zwischen einer Arbeitsmappe zu öffnen und die endgültigen MsgBox versichern:

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 

Die DoEvents ermöglicht Fokus zwischen VBA und Excel gemeinsam genutzt werden.

+0

Verwendung von CTRL/ALT/F9, kann es auf irgendeine Weise helfen – skkakkar

+0

@skkakkar Sie sind richtig! ................... aber das Plakat wollte es im * VBA * –

+0

Danke, Gary's Student. Es stoppt tatsächlich das Excel und friert einfach wie Sie sagten. Außerdem besteht meine Aufgabe darin, Hunderte von Dateien oder sogar Tausende für diesen Zweck auf einem Netzlaufwerk zu extrahieren. Dies scheint zu lange zu dauern, wenn jede Datei eine Wartezeit von einer Sekunde benötigt. Aber ich lerne hier etwas Neues! – user5700405

1

Wäre das Ereignis Application.AfterCalculation für Sie nützlich (https://msdn.microsoft.com/en-us/library/office/bb225813(v=office.12).aspx)?

Sie können beispielsweise eine Berechnungslistenerklasse erstellen, die ein Ereignis auslöst, sobald Ihre Berechnungen abgeschlossen sind. Dieser Listener kann jedes Mal neu gesetzt werden, wenn ein Buch geöffnet wird, und Sie können das Ereignis jedes Mal einfach handhaben. Die Klasse könnte wie folgt aussehen (fügen Sie eine neue Klasse und nennen es etwas angemessen, nannte ich mein 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 

Sie könnten eine zweite extracter Klasse erstellen, die die Arbeitsmappe geöffnet und hat seine Magie nur, wenn jeder OnTargetCalculationsComplete wurde gefeuert. In diesem Beispiel habe ich eine neue Klasse und nannte es 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 

es ausführen zu können, fügen Sie einfach den folgenden Code in das Modul:

Public Sub RunMe() 
    Dim oValueExtracter As ValueExtracter 

    Set oValueExtracter = New ValueExtracter 
    oValueExtracter.OpenBooks 
End Sub 

Es ist ein bisschen wie ein modularisierten Beispiel, weil andere Vielleicht möchten Sie nur den Hörer Teil des Codes, aber Sie könnten alles in eine Klasse einteilen, wenn Sie es wollten.

+0

Danke, Ambie. Ich werde es versuchen und Sie wissen lassen. Ich schätze deinen Rat sehr! – user5700405

Verwandte Themen