如何确定计算是否已完成或检测到中断的计算?

时间:2012-01-12 23:14:22

标签: excel vba

我有一个相当大的工作簿需要很长时间才能计算出来。它一直是一个挑战,让它一直计算,因为如果你看这么多,Excel非常渴望默默地中止计算。

为了帮助缓解这个问题,我创建了一些VBA代码来启动计算,这是由表单启动的,结果是中断计算过程并不容易,但仍然可以。 (我可以通过单击表单上的关闭X轻松完成此操作,但我想还有其他方法)

我希望让代码检测计算是否完整,而不是采取更多步骤来尝试使计算更加完整,因此它可以通知用户而不是盲目地进入其余步骤在我的代码中。到目前为止,我找不到任何办法。

我见过对Application.CalculationState的引用,但是在我中断计算后的值是xlDone,即使我在几秒钟后中断计算(通常需要大约一个小时)。

我想不出通过检查单元格的值来做到这一点的方法,因为我不知道最后计算哪一个。我看到有一种方法可以将细胞标记为“脏”但我无法找到检查细胞肮脏的方法。而且我不知道这是否是正确的道路,因为我可能需要检查每张纸上的每个单元格。

中断计算的行为不会引发错误,因此我的ON ERROR不会被触发。

有什么我想念的吗?有什么想法吗?

有什么想法吗?

8 个答案:

答案 0 :(得分:2)

我认为您需要实现的技巧(如果您在Excel 2007或更高版本中运行应用程序)是使用Application.AfterCalculate事件处理此事件,该事件在计算完成后引发没有出色的疑问。

如果您以前从未使用过VBA中的事件,那么cpearson.com会有一个很好的概述。

答案 1 :(得分:1)

上面查尔斯·威廉姆斯的(MSDN)解决方案为我工作,我有1000个VLOOKUP需要重新计算,因为代码因迭代循环而改变了查找值。由于计算未达到100%完成,结果出现偏差。

在我的子程序开始时代码执行

Application.Calculation = xlManual

在我准备好之前,这消除了Excel不必要的计算。

现在处于代码执行的关键点

Application.Calculation = xlAutomatic
ThisWorkbook.ForceFullCalculation = True
Application.Calculate

强制Excel执行完整计算后,代码可以保存结果并转到下一次迭代......但在此之前

ThisWorkbook.ForceFullCalculation = False
Application.Calculation = xlManual

记住最后

Application.Calculation = xlAutomatic  

答案 2 :(得分:0)

我从未真正使用过它,但我认为这可能会阻止计算被中断。

Application.CalculationInterruptKey = xlNoKey

答案 3 :(得分:0)

我想我听说您需要一种方法来监控正在执行的计算中的每一步是否都已执行。

假设您不想重新设计工作簿以使用比电子表格计算更容易跟踪的方法(例如VBA或数据透视表中的易变计算),这可能对您有用:

在VB中,您可以使用 .EnableCalculation .Calculate 将整个工作表设置为“Dirty”(需要计算),然后重新计算。这与您当前流程的主要区别在于,我们将在手动模式下一次一次执行这些操作。通过在VBA内一次启动一个工作表计算,您将能够执行其他中间操作,可用于跟踪您在计算过程中的进度。

请注意,这种方法假定一个相当线性的工作簿结构,这样如果我们首先按照您希望的顺序重新计算Sheet1,Sheet2,Sheet3等,您的工作簿将产生正确的结果。如果你的公式依赖性比线性更“意大利面”,这可能不适合你。它还假定您使用的是Excel 2000或更高版本。

例如,您可以编写一个VBA例程来完成以下步骤。 您将需要知道您的依赖关系,以便知道哪些计算必须先于其他计算,并从工作表开始处于“干净”状态,其中当前没有计算待处理。

第1步:将活动工作表设置为需要重新计算的第一个工作表

步骤2 :将计算模式设置为手动,如下所示:

    Application.Calculation = xlCalculationManual

第3步:“脏”整个活动工作表,如下所示:

    With ActiveSheet

    .EnableCalculation = False

    .EnableCalculation = True

第4步:仅使用以下内容(而不是整个工作簿)重新开始此工作表的重新计算:

    .Calculate

    End With

请注意,如果计算模式设置为自动,则步骤3将启动整个工作簿的重新计算。通过使用手动模式和With,我们将计算约束到当前工作表。

现在你已经弄脏了并重新计算了第一张纸(欢呼!)。现在,通过将上面的步骤3和4嵌入到For / Each或For / Next循环中,您可以为工作簿中的每个工作表重复此过程。同样,请确保您知道工作表需要计算的顺序(如果需要订单)。

现在,通过在循环中创建计数器变量,您可以通过在每次完成工作表计算时更新计数器变量值来跟踪计算得到的距离。例如,在重新计算工作表后,可以将计数器值设置为当前值+ 1,并将结果存储在全局变量中(即使在VBA例程结束后它也会保留),或者存储在工作表中的单元格中。这样,您可以稍后检查此值,以查看在计算完成或中断之前更新了多少工作表。

如果工作簿中的工作表相对较少,则可以一次将相同的方法应用于一个范围而不是工作表。

我不会详细介绍如何构建“计数器”,循环或全局变量,但如果需要,可以使用您最喜欢的搜索引擎轻松找到此信息。我强烈建议您在完成后重新启用自动计算,因为很容易忘记它已被设置为手动模式。

我希望这适合您 - 有关计算模式和重新计算的更多信息,这是一个有用的链接: http://msdn.microsoft.com/en-us/library/bb687891.aspx

答案 4 :(得分:0)

也许以下方法可行:

Do Until Application.CalculationState = xlDone
    DoEvents
Loop

不能说我已经测试了它,也不知道我知道Application.CalculationState的功能确实是多么强大,以确定是否发生了“完整”计算,而不是中断进程并将计算状态标记为已完成。

答案 5 :(得分:0)

Private sub SomeCodeThatGeneratesFormulas
    Application.Calculation = xlCalculation.xlCalculationManual
    '...Some formulas are copied here'
    Application.OnTime DateTime.DateAdd ("s",.01,DateTime.Now), "Module1.CalculateFullRebuildAndSubsequentSteps" 'By using Application.OnTime, this method will be called in a way that locks the end-user out of providing inputs into Excel until the calculation itself is complete.
end sub

public sub CalculateFullRebuildAndSubsequentSteps
    Application.CalculateFullRebuild
    '...Do next steps, i.e. paste as values'
end sub

答案 6 :(得分:0)

在状态栏的右侧,重新计算时会显示MH_MAGIC_64(其中Calculating (N processors) X%是您计算机上的处理器数量,N是已完成的数量) 。如果你没有在那里看到文字,那就不会重新计算了。

我正在使用Office 2010,但它应该存在于所有版本中。它有点微妙,所以很容易错过。

答案 7 :(得分:-1)

Excel中的数组可能有点愚蠢。也就是说,为了完成某些任务,人们避免使用中间列/行来存储(临时)数据,因此数组必须每次从头开始重新计算人员,因此变得非常慢。我的建议是:

  1. 修复数组以避免多次搜索。使用隐藏的单元格甚至是隐藏的单元格
  2. 避免使用A:A而是在excel 2007或更高版本中使用A1:A1000
  3. 使用公式等于零或错误(例如:NA()),而不计算先前的项目,因此您可以清楚地看到是否完成了操作。
  4. 可以使用一些VBA一次一步地注入配方,执行计算,然后继续下一步,但这可能意味着很多工作......