用LabVIEW编写Wizard类型的应用程序3(LabVIEW8.0)五、SubPanel主VI太过复杂,是肯定会影响它的可读性和可维护性的。所以,对向导类型程序的进一步改进的重点,就是把主VI进一步模块化,不但是程序代码要模块化,界面也必须模块化。代码模块化相对比较简单,多利用子VI就是了。但是界面的模块化,在之前的LabVIEW中是非常困难的,因为LabVIEW没办法在运行时,把不同的VI的界面拼在一起。是LabVIEW7.1和8.0的一些新功能最终解决了这个问题。对程序界面模块化,按一般的思路,第一步就是把每个页面划分成一个独立的模块。这似乎又回到了我们前文提到过的第一、二个阶段。但有所不同的是,旧版本LabVIEW功能不全,无法很好的管理被分为模块的页面,而新LabVIEW改进的对这方面的支持。在LabVIEW7.1中出现了一个新的控件-SubPanel(子面板)。当一个VI运行的时候,它的SubPanel控件中,可以显示另一个VI的前面板。我们可以利用这个新的控件,我们可以使用插件框架式程序架构来编写向导型的程序。图1是这种插件框架式程序结构的示意图。图1:插件框架式的程序结构插件框架式程序的实现思路是,把向导的每个页面都分配到一个独立的VI上去,这个页面上所有的操作,都有这个页面所在的VI完成。图1左上部分的那些VI就是为每个页面编写的VI。这些VI都被当作插件,在主程序需要的时候被调用显示在主程序上。图1右下角的VI是主程序的VI。它的界面上主要是一个SubPanel控件,这个控件用于显示页面VI的界面。主程序在每一步的时候,分别把对应这一步骤页面的VI的界面显示出来,这样就实现的向导功能。主程序的界面上还有一些公共控件,比如“上一步”“下一步”这样的按钮,这些按钮在所有步骤中都需要,所以可以放在主框架上,不需要再在每个页面中重复了。这样的插件框架式程序在运行时,主VI和插件VI是在同时运行的。主VI的运行流程大致如下:创建或注册程序运行时需要的各种事件-初始化程序-等待和处理事件,主要是管理插件。比如在用户按下“下一步”按钮后,主程序负责把当前的插件移出内存,把对应下一页的VI调入内存,运行,并显示界面。-最后负责销毁创建的事件,关闭所有资源,退出。插件VI的主要程序结构和主VI一样,采用的是事件处理结构。它在运行起来以后执行的流程也和主VI类似:创建或注册插件运行时需要的各种事件-初始化程序-等待和处理事件,主要是用户在界面上的操作,和一些后台程序,比如数据处理等等。-销毁创建的事件,关闭插件。虽然SubPanel在LabVIEW7.1中就出现了,但是我当时却并没有在我的程序里采用上述的设计方案。只是因为当时还有一个棘手的问题没有解决。这个问题就是VI太多了,不好管理。向导页面的多个插件VI,他们的功能有很多共同之处。在以前,所有页面都在同一个主VI中的时候,那些相同的功能可以通过调用同一个子VI来完成。但是,把页面分割成独立VI之后,很多情况,我都不得不为每个页面做一整套子VI,他们在每个页面上完成的功能都类似,但却不能使用同一个子VI。以处理事件为例,我写了一套子VI处理页面VI的事件。但是由于不同的页面可能会同时在运行,每个页面都有自己的事件,如果调用同一套处理事件的子VI,不同页面之间会相互干扰。另外,如果想创建一个新的页面,最方便的方法莫过于把一个已有页面的VI、子VI全部复制一遍,然后在其基础上做改动。LabVIEW以前是不允许出现同名VI的。把一个页面的VI、子VI全部改名,还要保证调用链接不出现混乱,非常的不方便。所以上述的插件框架方案是我等到到LabVIEW8.0出来以后才开始使用的。六、ProjectLibraryLabVIEW8.0作为一大升级版本,拥有了很多新特性。其中之一是“ProjectLibrary(工程库)”。工程库是一组功能相关联的VI或其它文件的集合。一个工程库是把一组功能相关的VI,和其她文件按一定结构组合封装在一起,以便于代码的管理和发布。工程库的名字也是库中VI的名字空间(namespace)。这个名字空间与C++、C#等语言中的名字空间的概念类似。有了它LabVIEW就可以在一个程序中使用两个同文件名的VI,当然,它们的名字空间不能相同,也就是它们存在于不同的工程库中。另外,工程库中的VI有操作安全设置,每一个VI可以被设置为公有(Public,可以被库外的VI调用);或者私有(Private,只能被库的成员VI调用)。工程库给开发插件框架式的程序带来的很大的方便,特别是在VI文件的管理方面。新的设计思路是这样的:把所有的功能模块都封装在工程库内,比如说每个页面都有一个对应的工程库。专为这个页面使用的所有子VI都被加在它的工程库内。并且,不想被其它库使用的的子VI都要标记为私有。被这样组织起来的程序,虽然VI数量还是很多,但模块划分清楚,不会出现不希望出现的调用关系。安全性,可维护性就大大提高了。另外,可扩展性也得到了提高。如果需要添加一个新的页面,只需要把一个已有页面复制一份。复制出来的这一份,只要工程库的名字换个新的就行了。再也不需要一个一个的去改VI的名字了。图2是我的一个程序的工程管理窗口:图2:采用工程库管理程序的VI但是,现在的程序结构还是有些令我不太满意的地方-重复的代码太多。不同页面之间,有很多类似的VI。就比如图2中的程序,每个页面都会用到事件处理的一些VI,他们的代码在每个页面中都是相同的。但是,利用这个工程库组织起来的程序却不能把这些重复的VI提取出来,变成共用的子VI,因为在每个页面里,这些代码相同的VI,处理的数据是不同的。并且这些数据会保留在VI的局部或全局变量中,不同的页面如果共用一套子VI,会相互影响,出现数据混乱的。直到LabVIEW支持了面向对象的编程之后,我们才终于找到了一个完美的解决这一问题的方案。