如何计算整个工作簿,而不是所有打开的工作簿?

16

有没有一种方法可以在VBA中计算整个工作簿而不是所有打开的工作簿?

我了解

worksheet.Calculate

但它只能做一张纸。我也知道

Application.CalculateFull

但我认为这会同时重新计算所有打开的工作簿。

是否可能只对一个工作簿进行操作?

编辑: 我明白了方法:

For Each wks In ActiveWorkbook.Worksheets
    wks.Calculate
Next

如果工作表之间有链接,那么这样做非常危险,计算的顺序很重要。我知道我可以找到确切的顺序并应用它,但问题在于在非常大的工作簿上,这可能会变得有些棘手。

8个回答

10
经过一些调查和测试,首先选择所有的工作表,然后进行计算,这种方法是有效的。
Application.Calculation = xlManual
ThisWorkbook.Sheets.Select
ActiveSheet.Calculate 

这将同时计算所有选定的工作表,并创建正确的计算顺序。

不起作用。我得到了“对象‘Sheets’的方法‘Select’失败”的错误信息。 - Denis
如果工作表不是自包含的,那么该方法可能是错误的。 - ingwarus

3
史蒂文·G的答案实际上并不起作用,只是看起来像它起作用了。(我不能回复那篇帖子,因为我没有50+声望,这很烦人)。它仍然按照单向顺序计算表格。我通过创建5个工作表,并在每个工作表中以不同的方向将它们全部+1到另一个单元格中进行测试。使用选择工作表然后计算的方法会得出错误的结果。由于它要求工作表可见,下面是我构建的函数来替换使用该方法的计算函数。(需要字典引用库)。不过不要使用。
    EXAMPLE, METHOD DOES NOT WORK
Function Calculate_Workbook(Optional Wb As Workbook)

'Application.calculate will calculate all open books, which can be very slow.
'Looping through all sheets in workbook to calculate can be risky due to formula referencing a cell thats not yet calculated, calculation order may be important.
Dim DicShtVisible As New Dictionary
DicShtVisible.CompareMode = TextCompare
Dim Asht As Worksheet, AWkbk As Workbook    'Previously selected books
Dim Sht As Worksheet

Set Asht = ActiveSheet
Set AWkbk = ActiveWorkbook

If Wb Is Nothing Then Set Wb = ThisWorkbook

Wb.Activate
'Unhide all sheets as can't select very hidden stuff
For Each Sht In Wb.Sheets
    DicShtVisible.Add Sht.Name, Sht.Visible
    Sht.Visible = xlSheetVisible
Next Sht

'Select all sheets and calculate the lot
Wb.Sheets.Select
ActiveSheet.Calculate

'Reapply visibility settings
Dim Key As Variant
For Each Key In DicShtVisible.Keys
    Wb.Sheets(Key).Visible = DicShtVisible.Item(Key)
Next Key

'Reset selections
AWkbk.Activate
Asht.Select

End Function

据我所见,没有解决方案,唯一的答案是要么知道工作簿的计算顺序并手动按照这个顺序计算工作表,要么接受使用Calculate并且它会计算所有打开的工作簿。
然而,我很愿意被证明是错误的。这是一个非常恼人和愚蠢的问题。

1
找到了一个解决方案:循环所有工作表并将EnableCalculation = false,除了相关的工作簿,然后调用Application.Calculate,最后恢复EnableCalculation。http://www.verycomputer.com/204_265ae465613d9bd1_1.htm - AlexO

3

据我所知,Steven,没有这样的东西。

实际上,执行 Application.Worksheets(1).Calculate 会浪费时间。

我进行了一个计时测试:在同一Excel实例中打开3个工作簿。

一个工作簿有8200个易失性函数,其中8000个在一个工作表中,分布在4个不连续的范围内,200个在其他工作表中。

另外两个工作簿共有100个函数。结果如下:

  • Application.Calculate - 4.41毫秒
  • ThisWorkbook.Worksheets(1).Calculate - 每个工作表52.05毫秒
  • ThisWorkbook.Worksheets(1).Range("R1").Calculate (重复4次) - 84.64毫秒

这是违反直觉的,但确实如此。

声明 Dim wks as Worksheet 也会浪费时间,除非你使用 For ... Each 将其引用为 ThisWorkbook.Worksheets(1) - 这样更快。

还要注意,当您的代码运行时,参考 ActiveWorkbook 时可能并不是主要的工作簿。 ThisWorkbook (带有代码的工作簿)更安全。


1
另一种选择是创建一个新的Excel实例,打开该实例中的工作簿,然后计算它。这将使原始实例中的任何工作簿未计算,如果另一个工作簿计算非常缓慢(例如100k+公式),则可能节省您的时间。
Dim xlApp As Excel.Application
Dim wbTest As Workbook

Set xlApp = New Excel.Application
Set wbTest = xlApp.Workbooks.Open("c:\temp\test.xlsx")

' do a bunch of stuff in wbTest

xlApp.Calculate

这取决于您的具体情况。打开第二个Excel实例需要额外的时间和更多内存(虽然我没有测试过,而且可能不是很显著)。

您可能需要更改更多的代码来考虑此工作簿位于不同实例中的事实,并且某些函数可能会出现问题(例如,如果您通过在原始Excel实例中依次遍历所有工作簿来检查工作簿是否已经打开)。


1

我们可以使用

Application.CalculateBeforeSave = True 

然后保存工作簿?可能更加精细的方法是捕获当前值,如果不为真则设置,保存,如果之前不为真则重置。


1
这个工作簿将仅使用代码所在的工作簿。
For Each wks In ThisWorkbook.Worksheets
    wks.Calculate
Next wks

-1

试试这个:

Sub CalcBook()
    Dim wks As Worksheet
    Application.Calculation = xlManual
    For Each wks In ActiveWorkbook.Worksheets
        wks.Calculate
    Next
    Set wks = Nothing
End Sub

Application.Calculate 将计算所有已打开的工作簿。 - Steven G
2
所以如果我理解正确的话,您同时打开了多个工作簿(Excel文件)。您想更新其中一个工作簿(文件),而不是其他的吗?如果是这样,请尝试上面的脚本。 - William C.
这非常危险,因为所有的工作表之间都有链接,所以你可能会计算工作表1,但你需要先计算工作表2。我点赞了这个答案,因为它确实计算了整个工作簿,但很可能不会生成Application.CalculateFull预期的结果。 - Steven G
那为什么不设定一个更新表格的顺序呢?指定 Worksheets("Sheet2").Calculate,然后 Worksheets("Sheet1").Calculate。 - William C.
很难确定在大型工作簿上执行正确的顺序。我正在寻找像Application.CalculateFull这样的调用,但我想它并不存在。如果没有更简单的解决方案可用,只需添加“没有内置函数可以这样做,但是假设您的工作表之间没有链接,这里有一个解决方法”,我将接受答案。 - Steven G

-1

只需使用Calculate

例如:

Sub Cal_()
    Calculate
End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接