【问题标题】:How can I calculate an entire workbook, but not all open workbooks?如何计算整个工作簿,而不是所有打开的工作簿?
【发布时间】:2017-05-05 13:45:15
【问题描述】:

有没有办法在 VBA 中计算整个工作簿而不是所有打开的工作簿?

我知道

worksheet.Calculate

但它只会做 1 张。我也知道

Application.CalculateFull

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

是否可以只做 1 个工作簿?

编辑: 我明白了:

For Each wks In ActiveWorkbook.Worksheets
    wks.Calculate
Next

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

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    经过一些调查和测试,先选择所有工作表,然后计算:

    Application.Calculation = xlManual
    ThisWorkbook.Sheets.Select
    ActiveSheet.Calculate 
    

    这会同时计算所有选定的工作表,从而创建正确的计算顺序

    【讨论】:

    • 不起作用。我得到“对象'表'的方法'选择'失败
    • 如果工作表不是自包含的,该方法可能是错误的。
    【解决方案2】:

    Steven G 的回答实际上并没有用,它看起来确实有效。(我无法回复该帖子,因为我没有 50 多个代表,这很烦人)。

    它仍然以 1 个方向顺序计算工作表。我通过创建 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
    

    据我所知,没有解决方案,唯一的答案是要么知道工作簿的计算顺序并按该顺序手动计算工作表,要么使用“计算”​​接受,它将计算所有打开的工作簿。

    然而,我很想被证明是错误的。这是一个令人讨厌和愚蠢的问题。

    【讨论】:

    • 找到了解决方案:循环所有工作表并设置 EnableCalculation = false 相关工作簿除外,然后调用 Application.Calculate 然后恢复 EnableCalculation verycomputer.com/204_265ae465613d9bd1_1.htm
    【解决方案3】:

    我不知道,史蒂文。

    你实际上浪费时间做Application.Worksheets(1).Calculate

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

    一个具有 8200 个易失性函数,一个工作表中有 4 个不连续范围的 8000 个,其他工作表中有 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 ... 每个都将其称为 ThisWorkbook.Worksheets(1) - 更快

    另外,请注意参考ActiveWorkbook - 当您运行代码时,您的主工作簿可能不是活动的。 ThisWorkbook(有代码的那个)更安全。

    【讨论】:

      【解决方案4】:

      ThisWorkbook 将仅使用代码所在的工作簿

      For Each wks In ThisWorkbook.Worksheets
          wks.Calculate
      Next wks
      

      【讨论】:

        【解决方案5】:

        另一种选择是创建一个新的 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 的原始实例)。

        【讨论】:

          【解决方案6】:

          只需使用计算

          例如:

          Sub Cal_()
              Calculate
          End Sub
          

          【讨论】:

            【解决方案7】:

            我们可以使用

            Application.CalculateBeforeSave = True 
            

            然后保存工作簿?可能更巧妙地捕获当前值,如果不为真则设置,如果不为真则保存,重置。

            【讨论】:

              【解决方案8】:

              试试这个:

              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 将计算所有打开的工作簿
              • 所以我对您的理解是正确的,您同时打开了多个工作簿(Excel 文件)。您想更新其中的 1 个工作簿(文件),而不是其余的?如果是这样,请尝试上面的脚本。
              • 这是非常危险的,因为所有工作表之间都有链接,因此您可能会计算工作表 1,但您需要先计算工作表 2。我赞成这个答案,因为它确实计算了整个工作簿,但它很可能不会生成 Application.CalculateFull 的预期结果
              • 那么为什么不设置更新工作表的顺序呢?指定 Worksheets("Sheet2").Calculate,然后指定 Worksheets("Sheet1").Calculate
              • 很难确定您在大量工作簿上的顺序正确。我正在寻找像 Application.CalculateFull 一样的电话,但我想它不存在。如果没有更简单的解决方案,只需添加“没有内置函数可以这样做,但这里有一个解决方法,假设您的工作表之间没有链接”,我会接受答案
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-08-16
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多