应用程序。根据工作簿计算
我正在用超过200 000个公式(一些非常复杂的数组公式)来pipe理一个工作簿,这意味着我不能让Excel每次点击某处时自动计算所有的单元格(计算所有内容需要大约8个小时)。
而不是这样,计算设置为手动,并且在打开Calculation.xlsm时执行以下VBA代码:
With Application .CalculateBeforeSave = False .Calculation = xlCalculationManual End With
我需要时使用自定义button来计算200k单元的某些部分。
我发现Excel确实logging了每个工作簿中的设置,这意味着如果打开Calculation.xlsm,Excel会记住计算设置为手动。 如果我打开我的Values.xlsx,Excel确实记得计算设置为自动。 这是之前我试图将Calculation.xlsm 中的值复制到Values.xlsx 。
现在,因为我在Calculation.xlsm中使用VBA将值复制到Values.xlsx,Excel也将Application.Calculation
设置应用于该工作簿,这意味着如果使用Excel的新实例打开它,计算将会仍然被设置为手动。
如果我在Calculation.xlsm工作簿中closures带有VBA的Application.Calculation = xlCalculationAutomatic
之前添加Application.Calculation = xlCalculationAutomatic
,它将起作用,但Excel也将开始计算我的Calculation.xlsm工作簿中的200k个单元格,不想要。
所以我的问题是关于如何基于特定的工作簿而不是Application
对象实际设置Excel的计算。 这是基于这样一个事实,即Excel根据打开哪个工作簿来跟踪该设置(您可以只进行testing并创build两个不同的.xlsx文件,一个启用计算,另一个禁用计算,Excel将会记住这些设置)。
我知道我可以在closures它之前使用Worksheets.Range.Calculate
方法来计算我的Values.xlsx工作簿,但是如果在此之后在Excel的新实例中打开它,计算仍然会被设置为手动。
编辑3:20 pm :不知道我是否足够清楚,英语不是我的母语。 简而言之,我将Calculation.xlsm与VBA和“ Calculation
设置为手动。 我有没有VBA和计算设置为自动Values.xlsx 。 如果在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设置为手动,把我需要的剪贴板中的所有数据(我只需要值,而不是公式),closures它(将VBA仍然继续即使我closures从其执行的工作簿?),将Application.Calculation设置为自动(因为没有打开的工作簿),然后打开目标工作簿粘贴值(将Excel仍将数据保留在剪贴板中另一个工作簿已closures?),然后保存并closures该工作簿,将计算设置为手动(未打开工作簿),然后重新打开执行代码的原始工作簿?
一种方法是创build一个新的Excel实例。 虽然这可能比较慢,但在不closures函数内部的书籍/应用程序的情况下,可能更难以处理,但对于例如简单的情况,可能最容易实现:
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
属性是相对于该应用程序的实例,而不是其他实例。
或者 ,您可以使用应用程序级别的事件处理程序。 我怀疑这可能会更快,但我没有testing速度。
从这个非常相似的问题稍微修改(这也是有条件地禁用应用程序级属性)。
如果:
我只是担心,如果我closures从中启动它的工作簿,代码仍然会被执行
只需使用正常的Workbook_BeforeClose
事件处理程序来恢复所需的Application.Calculation
属性(对于整个应用程序/所有其他打开的工作簿)。
答案的其余部分:
创build一个应用程序级别的事件处理程序,创build一个名为cEventClass
的类模块,并将其中的代码:
Public WithEvents appevent As Application Dim ret Private Sub appevent_WorkbookActivate(ByVal wb As Workbook) Call ToggleCalculation(wb, ret) End Sub
在名为mod_Caclulate
的标准模块中使用以下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
这将仅在打开特定工作簿时创build事件处理程序,并且只要将视图切换到其他工作簿,处理程序就会切换“ Calculation
属性。
注意:如果“结束”运行时或在debugging时执行任何会导致状态丢失的事情,则将丢失事件处理程序。 这总是可以通过调用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