问题的背景
我正在使用Factory Talk View Studio 7.00.00 (CPR 9 SR 6)和VBA 6.5为 HMI 开发一项新功能。
我有两个显示器:ma1_header和ma2_header,而且,正如你们中的许多人所知,在 Factory Talk View Studio(为了简洁起见,我将把它称为 FTV)每个显示器都有一个专用的DisplayCode。显示代码可以看作是 Excel 文件后面的 VBA 代码,只要它的 excel 文件保持打开状态。从这个角度来看,在 FTV 中绑定到显示的 VBA 代码与 excel 中的 VBA 项目具有相同的行为,因此当图形显示被用户或代码关闭时,它会被关闭。
为了理解这个问题,另一个重要的一点是,当 FTV 中名为 A 的通用显示器在替换模式下打开时,至少有一个像素与另一个显示器 B 重叠,显示器 B 会以其 VBA 代码关闭。请记住,ma1_header 和 ma2_header 始终以替换模式打开。
问题描述
也就是说,现在我将描述我发现的问题。
绑定到 ma1_header 和 ma2_header 的 VBA 代码基本相同(在以下模式中指出了差异),它在显示开始时执行一些初始化操作,然后运行一个名为ScheduleCheck的过程。此过程更新一些 UI 组件并评估一些条件以确定是否该显示 ma2_header(如果代码在 ma2_header 后面执行,则为 ma1_header),然后它会自行调用。
打开显示的命令不是直接从 VBA 执行的,而是在 VBA 外部异步执行的。事实上,VBA 对于某些操作,如:“显示显示”、“设置标签值”等,可以使用一个库来告诉 FTV 服务(也可以与命令行工具一起使用)来执行这些操作的列表(一次传输 1 个或更多命令)。
当用户启动 FTV 客户端时,首先显示 ma1_header 和其他一些组成用户界面的显示。
在ma1_header中,当ma2_header的开启条件满足并开启时,问题就出来了。现在让我们逐步描述 VBA 状态,以便尽可能清楚地解决问题:
- 在 ma1_header 中,满足打开条件并执行显示 ma2_header 的异步命令。请注意,目前 ma1_header vba 仍处于打开状态。
当 ma2_header 开始打开代码时,它的执行没有任何问题,直到等待过程。等待过程编写如下:
Public Declare Function GetTickCount Lib "kernel32" () As Long Public Sub wait(lMillSec As Long) Dim lT2 As Long Dim lT1 As Long On Error GoTo errHandle Const strMethod = "wait" MsgBox "wait - 1" lT1 = GetTickCount lT2 = lT1 While lT2 - lT1 < lMillSec lT2 = GetTickCount DoEvents Wend errHandle: If Err.Number Then LogDiagnosticsMessage "VBA: Display " & Me.Name & " in Method " & strMethod Err.Clear End If End Sub
等待过程的执行没有任何问题,直到第 18 行的DoEvents命令。当 DoEvents 执行时,ma1_header 有时间完全关闭自己(甚至是它的 vba 代码),然后 ma2_header 中的 vba 流似乎在这里停止而没有任何错误。因此,ScheduleCheck 无法自行调用。
丑陋的解决方案1
目前我发现了一个我称之为让代码工作的丑陋解决方案。
当 ma1_header 打开时,ma2_header 的打开将强制关闭 ma1_header,正如我之前解释的,只有在执行 DoEvents 时才完成。当需要显示 ma2_header 时,我尝试将这个新的命令列表传输到 FTW 工具:
##New##
Abort MA2_HEADER;
Pause 1;
Display MA1_HEADER /TRRU;
##Old##
Display MA1_HEADER /TRRU;
使用新方法,我关闭 ma2_header,然后使用命令“Pause 1;”等待(在 FTV 工具中,而不是在 VBA 中)1 秒钟;然后当我有理由确定 ma1_heder 由于 pause 命令而关闭时,我打开 ma1_header。以这种方式,ma2_heder 定期执行过程 ScheduleCheck,而不会出现奇怪的执行中断。
我不知道为什么这可以解决我的问题,所以我想了解它为什么会起作用以及导致此问题的原因,以便找到更好的解决方案。
丑陋的解决方案2
我找到了另一个丑陋的解决方案,但和以前一样,我并不满意,因为我想知道我当前的代码存在这个问题的方式(对我来说,解决一个问题而不知道是什么原因导致了程序员的失败)。
- 我在FTV 的标签服务器上创建了以下新标签
- 我在 FTV 上创建了以下新活动:
我在 ma1_header 和 ma2_header 中添加了一个包含新标签 Tick 的字符串显示
- 现在,在 VBA 中,我可以使用此字符串显示的Change事件,以便在每次此字符串显示更改(每秒)时执行 ScheduleCheck 中包含的相同代码(显然无需等待 DoEvents 循环)。
对问题的任何澄清或更好的解决方案将不胜感激。