【问题标题】:Wait for external data to load before automatic calculations? Excel/VBA在自动计算之前等待外部数据加载? Excel/VBA
【发布时间】:2015-03-24 05:13:34
【问题描述】:

第一次发帖,一直在寻找解决这个问题的方法,但还没有运气。

解释我的问题: 条款: OPC = 用于过程控制的对象链接和嵌入 (OLE) (允许其他应用程序使用来自 PLC 标签的数据) PLC = 可编程逻辑控制器(用于过程控制的计算机 SCADA = 监控和数据采集(显示来自 PLC 的值并允许控制的界面)

我有一个 Excel 工作簿,它在 PLC 对一些值进行排序后的特定时间由 SCADA 系统(WonderWare > Intouch,软件)自动打开。此工作簿使用 OPC 客户端填充其单元格,并使用以下方法访问它们:

=OPCLINK|EAST!'r[BELLWWPOWER]DailyValues_Z3[1,21]'

这很好用,但是要填充很多单元格,所以需要几秒钟。

我想要自动填充这些单元格并完成所有计算,然后将所有带有公式的单元格更改为这些公式的值。然后将工作簿保存在新的工作簿名称(“PowerReports-YesterdaysDate”)下,去掉 VBA 代码,并关闭两个工作簿(不保存原始文件,以保留公式)。

这一切都很好,除了它发生得太快并且新保存的副本最终在所有具有 OPC 链接的单元格中只有“#N/A”。当我将第一个工作表的私有子设置为“Worksheet_Activate()”而不是“Worksheet_Calculate()”时,代码不会自动统计并等待鼠标单击工作表的一个单元格(仅供参考:SCADA 系统打开此工作簿自动到工作表 1 以从工作表 1 的代码开始)。在这种情况下,新副本会成功保存,但是当代码自动统计时,它太快了。在计算完成之前如何等待外部数据加载?

我已经尝试过(我不知道它们的实施有多成功..),例如: -Application.Calculate -Application.RefreshAll -定时器 - 尝试从 PLC 获取标志 -检查剩余的#N/As

似乎如果一个循环或类似的东西立即运行,它不会让外部数据刷新。

Private Sub Worksheet_Calculate()

    ' When first sheet "Main" is activated, all formulas are replaced
    ' with their calculated values. The second sheet, "Monthly Values" is then activated

    Dim rng As Range, r As Range
    Set rng = Range("A1:D52")

    For Each r In rng
        If r.HasFormula Then
            r.Value = r.Value
        End If
    Next r

    Worksheets("Monthly Data").Activate

End Sub

Private Sub Worksheet_Activate()
    ' When second sheet "Monthly Values" is activated, all formulas are replaced
    ' with their calculated values. The sub routine, "SaveWithoutMacros" is then called

    Dim rng As Range, r As Range
    Set rng = Range("A1:BJ84")

    'Worksheets("Monthly Data").Calculate
    'If Not Application.CalculationState = xlDone Then
    'DoEvents
    'End If

    For Each r In rng
        If r.HasFormula Then
            r.Value = r.Value
        End If
    Next r

    Call SaveWithoutMacros
End Sub

Sub SaveWithoutMacros()
    'Purpose : To save a copy of the active workbook without macros

    Dim vFilename As String
    Dim wbActiveBook As Workbook
    '----------------------------------------------------------------------
    'Following two lines causes an error in Excel 97 - comment them out

    Dim VBComp As VBIDE.VBComponent
    Dim VBComps As VBIDE.VBComponents
    '----------------------------------------------------------------------

    ' Save to filename in format (yesterdays date) "PowerReports-DD-MM-YYYY"
    vFilename = ("D:\PowerReports\" & "PowerReport-" _
    & Format(Date - 1, "DD-MMM-YYYY") & ".xls")

    ActiveWorkbook.SaveCopyAs vFilename
    Set wbActiveBook = Workbooks.Open(vFilename)

    'Now strip all VBA, modules, userforms from the copy
    'This code is from Chip Pearson's website http://www.cpearson.com

    Set VBComps = wbActiveBook.VBProject.VBComponents

    For Each VBComp In VBComps
        Select Case VBComp.Type
        Case vbext_ct_StdModule, vbext_ct_MSForm, vbext_ct_ClassModule
            VBComps.Remove VBComp
        Case Else
            With VBComp.CodeModule
                .DeleteLines 1, .CountOfLines
            End With
        End Select
    Next VBComp
    wbActiveBook.Save ' saves new version after code is stripped

    ThisWorkbook.Saved = True ' sets save flag to true, does not actually save
    Application.Quit ' quits entire application, all workbooks
End Sub

抱歉,帖子太长了,看到其他人因为不够详细而被扯掉,哈哈。

【问题讨论】:

  • worksheet.Calcuate 将在填充工作表时一直运行,它对您来说效果不佳。 SCADA 是否总是写入相同的单元格,它是否总是以相同的单元格(可能是 D52)完成,因为您可以将其用作参考点,然后仅保存值(使用 .calulate 来查看该单元格是否有值)
  • 是的,它总是填充相同的单元格。仅保存值部分正在工作,但在加载外部 OPC 数据之前,因此由于缺少参考,计算的答案为 #N/A。如何使用 .calculate 检查外部数据是否已加载?
  • 在每次单元格值更改时。Calculate 会调用您粘贴或未填充的所有单元格,因此在写入每个单元格时,公式都会更改为值。我现在给你写一个答案,告诉你该怎么做

标签: vba excel


【解决方案1】:

现在这应该对你有用,通过只测试最后一个被填充的单元格,然后你将确定所有数据在你将它们更改为值之前都在里面

基本上是告诉 worksheet_calculate 在最后一个单元格有公式之前什么都不做

注意:有关在这种 SCADA 情况下工作的修改后的代码,请参阅下面的 OP 答案

 Private Sub Worksheet_Calculate()

        Dim rngLastCell As Range
        Set rngLastCell = Range("D52")

        If rngLastCell.HasFormula Then

            Dim rng As Range, r As Range
            Set rng = Range("A1:D52")


            For Each r In rng
                If r.HasFormula Then
                    r.Value = r.Value
                End If
            Next r

            Worksheets("Monthly Data").Activate
       End If
    End Sub

【讨论】:

  • 谢谢,我会在星期一的第一件事上尝试一下 =)!
  • 这实际上产生了相同的结果,每个具有包含对外部数据引用的公式的单元格在新副本中都是“#N/A”。
  • 不会 .HasFormula 只检查单元格是否包含任何公式,无论其中是否缺少引用?我可能会尝试做类似的事情,但检查最后一个单元格是否仍然是#N/A。
【解决方案2】:

终于搞定了!感谢 Steven Martin 给了我一个起点来让这个工作,直到你发布你的答案,我不认为 if 语句在没有循环的情况下对我有用。

这对我有用:

 Private Sub Worksheet_Calculate()

    Dim rngLastCell As Range
    Set rngLastCell = Range("D52")

    If WorksheetFunction.IsNA(rngLastCell) = False Then
        Dim rng As Range, r As Range
        Set rng = Range("A1:D52")

        For Each r In rng
            If r.HasFormula Then
                r.Value = r.Value
            End If
        Next r

        Worksheets("Monthly Data").Activate
   End If
End Sub

然后在第二张表的代码中检查“#N/A”的相同 IF 语句现在就像一个魅力。

【讨论】:

  • 很高兴它为您工作,非常聪明地使用 NA 检查来确保 ref 有效 - 请记住,Worksheet.Calculate 本身就是一个循环,因为每次工作表重新计算时都会调用它打开计算时单元格值发生变化
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 2018-07-14
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
相关资源
最近更新 更多