· 一个时间标识(time stamp);
· 一个已发生事件的枚举标识;
· 一个触发事件的对象的“VI服务器引用”。
时间标识是一个毫秒计数器,用于计算两个事件的间隔时间或确定事件发生的顺序。“产生事件的对象的引用”与该对象的VI服务器类必须严格地类型一致。根据产生事件的对象,如应用程序、VI或控件,事件被划分为不同的类。如果单个分支处理多个不同VI服务器类对象的事件,那么该引用类型必须是所有对象的公共父类。例如,如果将事件结构中某一个分支配置为处理数值控件和颜色梯度控件的事件,由于数值控件和颜色梯度控件都属于数值类,则事件源的控件引用类型为数值型。如果VI类和控件类注册了同样的事件,LabVIEW先产生VI事件。簇是仅有的可产生事件的容器对象。除“值改变(Value Change)”事件外,LabVIEW一般先为簇产生控件事件,再为簇中的对象产生事件。“值改变”事件先为簇中的元素产生事件,再为簇本身产生事件。如果容器对象上的VI事件及控件事件的结构分支放弃该事件,LabVIEW将不再进一步产生事件。
LabVIEW可产生多种不同的事件,可通过对事件注册来指定希望LabVIEW通知的事件,这样就可以避免产生其它不需要的事件。程序框图上的每一个事件结构和“事件注册函数”都具有一个LabVIEW用来存储事件的队列。当事件发生时,LabVIEW会在该事件注册的每一个队列中放置该事件的一个副本。事件结构将处理其队列中的所有事件,以及连接到该事件结构动态事件接线端的所有“事件注册函数”队列中的事件。通过这些队列,LabVIEW可确保事件被可靠地按其发生顺序传输到每个已注册的事件结构。
默认状态下,当一个事件进入队列后,LabVIEW将锁定含有产生该事件的对象的前面板。前面板将一直保持锁定状态直至所有事件结构完成处理该事件。前面板锁定时,LabVIEW将不处理前面板操作而将这些操作放入缓冲区,直至前面板解除锁定后才着手处理。例如,用户可能需要事件分支打开一个需要输入文本的应用程序。由于用户已预计到需要进行文本输入,可能在该应用程序前面板出现之前用户便开始了文本输入。一旦应用程序打开并在前面板上出现,LabVIEW将以按键的发生顺序处理按键。
在LabVIEW中有两种事件注册模式: “静态注册(Static Registration)”和“动态注册(Dynamic Registration)”。如4.5.1节所述,静态注册要求在设计时指定每个事件结构的分支处理何种事件,一旦设定完成,就无法在运行时改变事件结构所处理的事件。因此,只有用户界面事件可进行静态事件注册。LabVIEW会在VI运行时自动注册程序框图中使用到的静态注册事件,同时会使事件结构处于等待状态,直到事件被触发后相应的事件结构分支执行为止。
VI服务器是一套位于“函数»应用程序控制子选板”的函数(如右图),可在本地计算机或在远程计算机上通过程序框图、ActiveX技术和TCP协议访问VI服务器,动态控制前面板对象、VI和LabVIEW环境。动态注册就通过将事件注册与VI服务器(VI Server)相结合,在运行时使用应用程序、VI和控件引用(Control Reference)来指定希望产生事件的对象。动态注册可以更灵活的控制LabVIEW所产生事件的类型和事件产生的时间。它有以下几个明显的优点:
1. 可使事件仅在应用程序的某个部分发生;
2. 在应用程序运行时改变产生事件的VI或控件;
3. 允许程序在产生事件的VI和它的子VI中处理事件。
但是动态注册比静态注册复杂,它需要在程序框图中使用VI服务器引用,使用代码明确地注册和取消注册事件,而无法像静态注册那样通过事件结构的配置信息自动处理注册。
在程序中使用动态事件注册主要涉及以下几个步骤:
1. 获取要处理事件对象(事件源)的VI服务器引用。
2. 将VI服务器引用连接至“注册事件函数(Register for Event )”注册对象的事件。
3. 将事件注册引用句柄或事件注册引用句柄的簇连接至“动态事件接线端子(Dynamic Event Terminal )”
4. 将事件结构放在While循环中,处理对象事件直至结束。
5. 使用“取消注册事件函数(Unregister for Events )”停止事件发生。
在4.5.1节中我们使用静态事件注册的方法实现了字符串超链接文本显示,图4.5.3-1给出了以动态事件注册的方式实现相同功能的程序代码。下面我们以就结合这个例子来讨论动态事件注册各实现步骤中的关键技术。
图4.5.3-1动态事件注册实现超链接文本显示
要动态注册对象事件,必须先获取该对象的VI服务器引用。一般来说,应用程序和VI的引用可通过“打开应用程序引用(Open Application Reference )”和“打开VI引用(Open VI Reference )”函数来获取。对控件来说,最为常用的是它引用的常量。可以通过右键单击控件,从快捷菜单中选择“创建(Create)»引用(Reference)”来获得。对于字符串超链接文本显示的例子来说,事件源为字符串控件“Web”,可以通过常量来获得控件引用,如图4.5.3-1中的第1步所示。当然,在实际设计过程中仅有控件引用的常量是远远不够的,有时候对程序来说,具体要操作的控件只有在程序运行时才能明确,就需要使用属性节点查询来获得控件的引用。 例如当需要通过程序代码寻找前面板上标签(Label)等于“Input”的控件,并将其标题(Caption)从英文“Input”改为中文“输入”时,可以用下面代码实现。
图4.5.3-2 通过程序代码寻找前面板上标签等于“Input”的控件
在程序框图中,首先使用使用“打开VI引用函数”获得VI的引用,并将其传递给后续属性节点。一旦属性节点接收到VI引用作为输入,就可以从其接线端子列表中选择与VI相关的属性。从属性节点中选择“前面板”作为元素,可以返回前面板的引用。同理,将前面板属性传递给下一个属性节点,可以选择所有与前面板相关的的属性。从中选择“控件集”作为元素可以数组的形式返回所有前面板上控件的引用。组后使用循环逐个索引控件,并取每个组件的Label属性与“Input”比较,找到后就更改控件的标签属性。这种使用属性节点从VI到控件逐级别通过查询获得控件引用的方法在设计中被大量使用。此外,只要保证前面板上每个label的单一性,就能很容易使用这种方法实现用户界面的多语言支持,这一技术我们将在后续章节详细介绍。
回到字符串超链接文本显示的例子,获取到字符串控件“Web”的VI服务器引用后,接下来要使用“注册事件函数”动态注册事件。使用“注册事件函数”时,调整它的大小可以显示一个或多个事件源输入接线端。将应用程序、VI或控件引用连接到每一个“事件源输入接线端”,然后单击每一个输入接线端,从事件快捷菜单中选择想要注册的事件即可完成“注册事件函数”的配置。事件快捷菜单中所能选择的事件与静态注册事件时在编辑事件对话框中出现的事件相同,取决于连接到事件源输入端的VI服务器引用类型。如图4.5.3-1第2步所示,我们为字符串超链接文本显示的例子动态注册“鼠标进入”和“鼠标离开”两个事件。当“注册事件函数”执行时,LabVIEW将对每个事件源相关联的对象上的事件进行注册,随后LabVIEW将按事件发生的顺序将事件放入队列,直到事件结构来处理这些事件。“注册事件函数”的输出端是一个事件注册引用句柄,使用该引用句柄将已注册事件的信息传递给事件结构。
图4.5.3-3 选择动态注册事件
“注册事件函数”配置完毕后,将事件注册引用句柄输出接线端连接至事件结构左侧的动态事件接线端子,驱使事件结构对已注册的事件进行处理。“动态事件接线端子”类似于移位寄存器,可右键单击事件结构并从快捷菜单中选择显示它。“动态事件接线端子”的左接线端接受事件注册引用句柄或事件注册引用句柄的簇。如果不连接事件结构内部的“动态事件接线端子”右接线端,右接线端的数据将与左接线端相同。有时候可通过“注册事件函数”将事件注册引用句柄或事件注册引用句柄的簇连接至内部的右接线端并动态地修改事件注册。
要使事件结构能处理动态注册的事件,还要使用事件编辑对话框将动态事件映射至相应的事件处理分支。事件编辑对话框的事件源部分包含一个列出了每个已动态注册的事件源的标题(图4.5.3-3)。选择“web”作为事件源,并选择“鼠标进入”和“鼠标离开”两个事件确认后,事件结构将相应增加两个事件处理分支。在“鼠标进入”事件处理分支中,增加改变字符串的字体颜色为蓝色,并显示下划线的代码,在“鼠标离开”事件处理分支中,将文本恢复到默认状态即可。
事件处理结束后,要在程序中停止再产生事件。这可通过将事件结构右侧的动态事件接线端连接至“取消注册事件函数”来实现。“取消注册事件函数”一般位于含有该事件结构的While循环外,当它执行时,LabVIEW将把连接到它的事件注册引用句柄所指定的一切事件注册取消,销毁与其关联的事件队列,并放弃任何还在队列中的事件。如果用户不取消注册事件,且在包含事件结构的While循环结束后又执行了可产生事件的操作,那么LabVIEW将无限地查询事件,直到VI空闲时才销毁事件队列,这将消耗大量的系统资源。因此,强烈建议在程序中,尤其是在长时间运行的应用程序中不再使用事件时取消注册的事件。LabVIEW也会在顶层VI结束运行时自动取消所有事件注册。