Application.Calculation取决于工作簿

时间:2014-08-28 19:10:05

标签: excel vba excel-vba excel-2010

我正在管理一个包含超过20万个公式的工作簿(一些非常复杂的数组公式),这意味着每次点击某个地方时我都不能让Excel自动计算所有单元格(计算所有内容大约需要8个小时) )。

而不是那样,计算设置为手动,当 Calculation.xlsm 打开时,我执行了以下VBA代码:

With Application
    .CalculateBeforeSave = False
    .Calculation = xlCalculationManual
End With

我使用自定义按钮在需要时仅计算200k单元格的某些部分。

我注意到Excel会跟踪每个工作簿中的设置,这意味着如果我打开我的Calculation.xlsm,Excel会记住计算设置为手动。如果我打开我的Values.xlsx,Excel会记住计算设置为自动。这是在我尝试将值从 Calculation.xlsm 复制到 Values.xlsx 之前。

现在,因为我在Calculation.xlsm中使用VBA将值复制到Values.xlsx,Excel也会将Application.Calculation设置应用于该工作簿,这意味着如果我使用新的实例打开它Excel,计算仍将设置为手动。

如果我在 Calculation.xlsm 工作簿中使用VBA关闭 Values.xlsx 之前添加Application.Calculation = xlCalculationAutomatic,它将起作用,但Excel也会启动计算我的 Calculation.xlsm 工作簿中的200k单元格,这显然是我不想要的。

所以我的问题是如何基于特定工作簿而不是Application对象实际设置Excel的计算。这是基于以下事实:Excel会根据打开的工作簿来跟踪该设置(您可以只进行测试并创建2个不同的 .xlsx 文件,其中一个启用计算,另一个启用禁用计算后,Excel将记住这些设置。)

我知道我可以在关闭它之前使用Worksheets.Range.Calculate方法计算我的Values.xlsx工作簿,但是如果我在之后的Excel新实例中打开它,计算仍将设置为手动。


编辑下午3:20 :不确定我是否足够清楚,英语不是我的母语。简而言之,我将 Calculation.xlsm 与VBA和Calculation设置为手动。我有 Values.xlsx ,没有VBA,计算设置为自动。如果我在 Calculation.xlsm 中使用以下VBA代码打开 Values.xlsx ,Excel将自动将我的 Values.xlsx 工作簿转换为手动计算。

Calculation.xlsm 代码:

Private Sub Workbook_Open()
    With Application
        .CalculateBeforeSave = False
        .Calculation = xlCalculationManual
    End With
End Sub

Sub someFunction()
    Set WB = Application.Workbooks.Open("Values.xlsx")
    Set WBws = WB.Sheets("mySheet")
    DoEvents
    wb.Save
    WB.Close
End Sub

执行someFunction()后, Values.xlsx 计算设置为手动。那就是问题所在。我希望它保持自动(我不能将VBA添加到该文件,它必须全部来自 Calculation.xlsm ,如上所述)。


编辑下午3:40 :我可以把我的大工作簿与Application.Calculation设置为手动,将我需要的所有数据放在剪贴板中(我只需要值,而不是公式) ,关闭它(即使我关闭执行它的工作簿,VBA仍会继续执行吗?),将Application.Calculation设置为Auto(因为没有打开的工作簿),然后打开目标工作簿以粘贴值( Excel是否仍将数据保留在剪贴板中,因为其他工作簿已关闭?),然后保存并关闭该工作簿,将计算设置为手动(未打开工作簿)并重新打开执行代码的原始工作簿?

1 个答案:

答案 0 :(得分:4)

执行此操作的一种方法是创建Excel的新实例。虽然这可能比较慢,但在您不在函数中关闭书籍/应用程序的情况下可能更难处理,但对于像您的示例这样的简单案例,它可能最容易实现:

Sub someFunction()
Dim newExcel as Excel.Application
Set newExcel = CreateObject("Excel.Application")

    Set WB = newExcel.Workbooks.Open("Values.xlsx")
    Set WBws = WB.Sheets("mySheet")
    DoEvents
    wb.Save
    WB.Close
    newExcel.Quit
    Set newExcel = Nothing
End Sub

Application.Calculation属性是相对于应用程序的实例,而不是其他实例。

或者,您可以使用应用程序级事件处理程序。我怀疑这可能会更快,但我没有测试它的速度。

this very similar question略微修改(也询问有条件地禁用APplication级属性)。

如果:

  

我只是担心如果关闭启动它的工作簿,代码是否仍会被执行

这只是使用普通的Workbook_BeforeClose事件处理程序来恢复所需的Application.Calculation属性(对于整个应用程序/所有其他打开的工作簿)。

答案的其余部分:

创建一个应用程序级事件处理程序,创建一个名为cEventClass的类模块并将此代码放入其中:

Public WithEvents appevent As Application
Dim ret
Private Sub appevent_WorkbookActivate(ByVal wb As Workbook)

    Call ToggleCalculation(wb, ret)

End Sub

在名为mod_Caclulate的标准模块中使用以下内容:

Option Explicit
Public XLEvents As New cEventClass
Sub SetEventHandler()

If XLEvents.appevent Is Nothing Then
    Set XLEvents.appevent = Application
End If

End Sub

Sub ToggleCalculation(wb As Workbook, Optional ret)
    If wb.Name = ThisWorkbook.Name Then
        ret = xlCalculationManual
    Else
        ret = xlCalculationAutomatic
    End If
    Application.Calculation = ret
End Sub

将此信息放在工作簿的Workbook_Open事件处理程序中,您始终希望手动计算:

Option Explicit
Private Sub Workbook_Open()
    'Create the event handler when the workbook opens
    Call mod_Caclulate.SetEventHandler
    Call mod_Caclulate.ToggleCalculation(Me)

End Sub

这将仅在打开特定工作簿时创建事件处理程序,并且只要将视图切换到其他工作簿,处理程序就会切换Calculation属性。

注意:如果你"结束"运行时或在调试时做任何会导致状态丢失的事情,你将失去事件处理程序。这可以通过调用Workbook_Open过程来恢复,因此另外一个安全措施可能是在ThisWorkbook代码模块中添加它:

Private Sub Workbook_SheetActivate(ByVal Sh As Object)
' Additional safeguard in case state loss has killed the event handler:
' use some workbook-level events to re-instantiate the event handler

    Call Workbook_Open
End Sub
相关问题