dnL*_*nLL 2 excel vba excel-2010
我正在管理一个包含超过 200 000 个公式(一些非常复杂的数组公式)的工作簿,这意味着我不能让 Excel 每次单击某个地方时自动计算所有单元格(计算所有内容大约需要 8 小时)。
取而代之的是,计算设置为手动,并且在打开Calculation.xlsm时执行了以下 VBA 代码:
With Application
.CalculateBeforeSave = False
.Calculation = xlCalculationManual
End With
Run Code Online (Sandbox Code Playgroud)
我使用自定义按钮在需要时仅计算 200k 单元格的某些部分。
我注意到 Excel 会跟踪每个工作簿中的设置,这意味着如果我打开我的 Calculation.xlsm,Excel 会记住计算设置为手动。如果我打开 Values.xlsx,Excel 会记住计算设置为自动。这是在我尝试将值从Calculation.xlsm复制到Values.xlsx 之前。
现在,因为我在 Calculation.xlsm 中使用 VBA 将值复制到 Values.xlsx,ExcelApplication.Calculation也会将该设置应用于该工作簿,这意味着如果我使用新的 Excel 实例打开它,计算仍将被设置手动。
如果我在我的Calculation.xlsm工作簿中使用 VBAApplication.Calculation = xlCalculationAutomatic关闭Values.xlsx之前添加一个,它将起作用,但 Excel 也将开始计算我的Calculation.xlsm工作簿中的 200k 单元格,这显然是我不想要的。
所以我的问题是关于如何根据特定的工作簿而不是Application对象来实际设置 Excel 的计算。这是基于这样一个事实,即 Excel 会根据打开的工作簿跟踪该设置(您只需进行测试并创建 2 个不同的.xlsx文件,一个启用计算,另一个禁用计算,Excel 将记住这些设置)。
我知道我可以Worksheets.Range.Calculate在关闭它之前使用该方法计算我的 Values.xlsx 工作簿,但如果我之后在 Excel 的新实例中打开它,计算仍将设置为手动。
编辑下午 3:20:不确定我是否足够清楚,英语不是我的母语。简而言之,我有带有 VBA 的Calculation.xlsm并Calculation设置为手动。我有Values.xlsx没有 VBA 和计算设置为自动。如果我在Calculation.xlsm中使用以下 VBA 代码打开Values.xlsx,Excel 将自动将我的Values.xlsx工作簿转换为手动计算。
计算.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
Run Code Online (Sandbox Code Playgroud)
someFunction()的执行之后,Values.xlsx计算被设置为手动。那就是问题所在。我希望它保持自动状态(并且我无法将 VBA 添加到该文件中,必须像上面一样从Calculation.xlsm 中完成)。
编辑下午 3 点 40 分:我是否可以将 Application.Calculation 的大工作簿设置为手动,将我需要的所有数据放在剪贴板中(我只需要值,而不是公式),关闭它(VBA 是否仍会继续即使我关闭执行它的工作簿也执行?),将 Application.Calculation 设置为 Auto(因为没有打开的工作簿),然后打开目标工作簿以粘贴值(Excel 仍将数据保留在剪贴板中,因为另一个工作簿已关闭?),然后保存并关闭该工作簿,将计算设置回手动(未打开工作簿)并重新打开执行代码的原始工作簿?
一种方法是创建一个新的 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
Run Code Online (Sandbox Code Playgroud)
该Application.Calculation属性与应用程序的该实例相关,而不是其他实例。
或者,您可以使用应用程序级事件处理程序。我怀疑这可能会更快,但我还没有测试它的速度。
从这个非常相似的问题(它还询问有条件地禁用应用程序级属性)稍微修改了一下。
如果:
我只是担心如果我关闭启动它的工作簿,代码是否仍然会被执行
然后只需使用普通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
Run Code Online (Sandbox Code Playgroud)
在名为 的标准模块中使用以下内容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
Run Code Online (Sandbox Code Playgroud)
将其放在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
Run Code Online (Sandbox Code Playgroud)
这将仅在打开特定工作簿时创建事件处理程序,并且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
Run Code Online (Sandbox Code Playgroud)