《我和LabVIEW》补充内容和注释 第2版

这是在本书第二版完稿后,我记录的一些使用LabVIEW的经验。这些文章可以作为对书中内容的补充。

针对书中章节 简要说明 详文链接
4.2 可重入VI 可重入VI的两种分配数据空间方式 可重入VI的两种数据空间分配方式
11 代码风格与优化 像其他语言程序那样,把可执行代码与源代码分离开来 可执行代码与源代码分离
11 代码风格与优化 内嵌子VI对程序效率的影响 内嵌子VI

返回《我和LabVIEW》主页

《我和LabVIEW》售出九千多册了

我常常会去售书的网站看看读者对自己这本书的评论,最近发现京东,卓越两个网站长期缺货,也不知道为啥。于是想起来去跟编辑打听一下这本书的销售情况。胡主任告诉我,书已经卖出了九千多册了,前两次印刷的一万册很快就会售罄。今天正好是这本书发行两周年的纪念日。

我最初还真没想到一本LabVIEW书会有这么多读者。开始写这本书的时候,我以为中国LabVIEW用户数量不多,这本书能卖出去三四千本我就满足了。现在看来,中国LabVIEW用户还真不少,LabVIEW影响力蛮大呢。

当当网上查看书的销量

我还是比较关心自己的书的销量的,所以是不是会跟编辑联系一下,问他卖了多少了。不过这个绝对的销量数字对于我来说意义不大,我更希望看到这本书与同类型书籍的比较结果。也许LabVIEW读者的总数并不多,但是如果我的书比其它的LabVIEW书更受欢迎我就心满意足了。

查看印刷数是一个方法,比如打开我的书能够看到它是第二次印刷,印数5000~10000,销售数量肯定也就介于这个数字之间。

更精确一点的可以去看网上书店的用户留言,对同一类书来说,买书者和留言者的比例可能差不多。但也不精确啦,如果一本书特别好或者特别不好,肯定会比那些中规中矩的书吸引到更多的留言数量。

前一阵子,发现当当网给每本书还多设置了一个参数:“喜欢人数”。我一直在琢磨,当当凭什么判定有多少用户喜欢一本书呢?我跟踪观察了一段时间,觉得最有可能的是所谓“喜欢人数”就是这本书的买家数量。这大概是最能体现销量的参数了。

image

回调VI

LabVIEW界面程序最常用的结构就是循环事件结构。用事件结构截获用户在界面上对控件的操作,然后做出相应处理。

在文本语言中,常用的事件处理方法与LabVIEW是不同的。文本语言常常使用回调函数来处理界面事件。比如:某个按钮按下时,需要做一个fft运算。那么就写一段函数来完成这个fft运算,再把这个函数与按钮按下事件关联起来。开发语言通常已经做好了对事件的监控,一旦发现按钮按下事件产生了,就去调用与它关联的fft运算函数。这个有开发者编写,被系统调用的函数就叫做回调函数。

LabVIEW也可以采用与文本语言相类似的方法来处理事件:不是在事件结构内处理,而是在程序开始时,就为某事件注册一个回调VI。在回调VI内编写相应代码,一旦事件发生,这段代码就会被执行。

与事件结构相比,回调VI编写起来稍微麻烦一点;但它的好处是,它和主VI是平行运行的。如果事件处理过程比较耗时,把它放在事件结构中会阻塞整个程序,使得程序界面暂时失去响应;而把它放在回调VI中,则不会影响程序其它部分的运行。

比如下面这个例子。程序界面上有两个仪表盘:左面那个始终在运转,每10秒钟旋转一圈;右边那个,由按钮控制,按下按钮才旋转一圈。若把旋转右表这个工作放到事件结构的按钮按下处理分支中去做,它势必会打断左表的旋转,因此,考虑把它放到回调VI中去做。

这是主程序界面:两个表盘,和一个控制右表旋转的按钮。

程序的代码也比较简单。先看代码的右半部份:这是一个典型的循环事件结构,用来控制左表的旋转。但是注意,右表的控制并不是在这个结构中实现的。

再看程序左半部分:它为按钮“右表旋转一圈”的值改变事件注册了一个回调VI。

注册回调VI用的是节点“Register Event Callback”,它在函数选板“Connectivity –> ActiveX”上。这个节点主要是为了给ActiveX、.NET控件的事件注册回调VI。事件结构无法截获ActiveX、.NET控件的事件,因此只能通过回调VI的方式来处理这些控件的事件。但是这个节点也可以用于给LabVIEW自带的控件注册回调VI。

注册回调VI节点,有三个输入参数从上至下分别是:事件的发出者、回调VI、用户自定义数据。

在我们这个例子中,需要截获的是按钮“右表旋转一圈”的值改变事件,因此需要把“右表旋转一圈”控件的引用作为第一个参数传递给注册回调VI节点。指定好事件的发出者,接下来需要选择事件的类型,鼠标点击注册回调VI节点的第一个参数的接线方块,发现“右表旋转一圈”按钮的所有事件都已经列在这里了,选择“值改变”事件。

第三个参数是用户自定义数据,可以是任意类型的数据,在回调VI中需要用到的数据都可以通过它来传递。因为我打算在回调VI中对控件“右表”做修改,因此,在这里把“右表”的引用作为数据传递给回调VI。

第二个参数是回调VI的引用,如果已经写好了回调VI,把引用传进去就行了。我还没有编写回调VI,因此可以在参数的接线端上点击鼠标右键,选择“Create Callback VI”创建一个空白的回调VI。

回调VI中写一小段代码,让右表旋转一圈,整个程序就完成了。这时,左右表可以各自运行,互不影响。

LvClass 的一个效率问题

前几天,听到了一个客户的抱怨:他编写了一个LabVIEW程序,每次打开主程序就要花费几分钟的时间,这有点令他忍无可忍。我没有见过他的源程序,不过据帮他检查过程序的同事讲,他的问题很可能是使用了大量的LvClass造成的。在他的项目中,包含有上百个类(LvClass)。我以前也听说过LvClass在效率上可能会有些问题,听到了这个消息后,我自己做了一个实验。

LabVIEW Scripting中有一个属性节点可以用来查看内存中所有的VI,我就利用这个VI来查看一个程序到底在装入些什么,令它启动如此之慢。

假设不存在子VI,如果打开某个不在LvClass中的VI(即便这个VI是属于某个lvlib的),只有这个VI会被装入内存。但是,打开某一个LvClass中的VI,我发现不但这个VI会被装入内存,它所在的类中的所有其它的VI也都被调入内存。如果这个类还有父类和祖先类,那么所有父类、祖先类中的VI统统都会被调入内存。

总结一下就是这样:当一个VI被装入内存

  1. 它的所有子VI都会被装入内存;
  2. 它所在的类中的所有的VI都会被装入内存;
  3. 它所在的类的父类中的所有的VI都会被装入内存。

以上3条可以是递归发生的,比如一个主VI A被装入内存,它的子VI B也会被装入内存,和B同属一个类的VI C也要被装入内存,C中有个子VI D,D属于类E,E有个父类F,F中有个方法VI G。尽管G的功能和程序A八杆子都打不着了,但也会被装进来。这大概就是那个用户遇到的问题,表面上他的程序不算太大,但是程序开始启动时,却需要把多于程序本身数倍的不相关的VI都装入内存,这一过程会每次都浪费他几分钟的时间。

鉴于LvClass的这一特性,设计使用它的时候一定要格外小心,否则很可能会造成程序效率的低下。我想到了几点需要注意的地方:

  1. 如果仅需要对一些VI进行封装,那么应当使用lvlib,而不是lvclass。两者封装的主要区别是,lvclass可以封装对象的属性(也就是模块用到的数据)。
  2. 类中的VI必须是高内聚的,类中的方法共同完成某一基本功能,不可再分割。应用程序一旦用到这个类中的某个VI,就意味着程序将会使用到类中几乎全部的VI;而不是一个应用程序可能只使用这个类中的某几个VI。
  3. 继承关系应当尽量简单。没有必要的时候尽量不使用继承。LabVIEW不支持接口,不应创建一个纯虚类,然后当作接口来用。
  4. 尽量不要嵌套调用。比如在一个类的VI中又去调用另一个类中的VI。
  5. 打算使用多态这个特性时要注意,多态使得应用程序在运行时,根据对象的类型选择对应的处理方法。但有些选择应当是程序编译时就做出的,它们不适合套用在多态特性上。

举一些例子:

  • INI文件读写这个模块比较适合做成类,每个INI文件对应一个类的实例。它有丰富的数据(文件的内容);它的方法有限,基本上只需要打开、读条目、写条目、保存关闭,这四个方法,并且一般的应用程序都会同时使用到这四个方法。
  • 复杂仪器的驱动程序不适合做成类。因为驱动程序会提供非常多的功能,示波器有各种触发模式。而一个应用程序通常只用到多种模式中的某一种就够用了。
  • 某测试程序可以生成测试报告给用户。用户可以选择几种不同的报告类型。生成报告的模块可以用lvclass来设计。因为生成不同类型的报告的方法间,可重用代码很多,可以为它们设计一个基类。并且,是程序运行时,才选择生成报告类型的。
  • 某一测试程序,可以支持多种型号的仪器。因为不同用户使用不同的硬件。对不同型号仪器的支持不适合使用lvclass来设计,因为测试程序发布给用户时,用户的硬件设备是固定的。对仪器的选择应当是程序发布时就决定好的,而不应等到程序每次运行起来后判断。

WPF界面编程与LabVIEW界面编程的比较

最近一段时间在学习使用WPF编写程序。计算机软件技术发展太快了,新的语言、体系,层出不穷。往往一个技术还没用熟练,就被要求换用更新的技术了。没准哪一天LabVIEW被什么其它语言替代了,我这方面的经验也就全作废了-程序员果然是吃青春饭的。

WPF是.NET中编写程序界面的一套体系。微软提出WPF时的构想是非常好的:它希望把程序的界面和运行逻辑部分完全分开来,这样可以有专门美工来设计程序界面;而程序员则专心实现程序功能的编码。它能不能实现这个美好的愿望呢?很难说,至少对于我和周边的同事来说,仍然需要同时负责相关程序的界面和代码。

虽然WPF之前,Visual Studio就号称支持可视化界面编程了,但那时可视化做的并不彻底。早期的VB、VC可视化编程,提供了一个可视化界面编辑环境。程序员在通过界面编辑器设计调整程序界面的同时,界面编辑器自动生成能够产生当前界面效果的VB或VC代码。也就是说,界面最终也还是程序代码的一部分,只不过可视化界面编辑环境帮可以助程序员生成相关的代码,从而简化了程序设计。
在WPF中,界面设计有了它自己的专门的记录方式,XAML语言,一种类似XML格式的文本语言。只有在程序进行编译的时候,编译器才把XAML代码编译成.NET的中间代码。这种行为与LabVIEW是类似的:界面与程序代码采用两套不同的机制表示。

与LabVIEW相比,WPF功能强大、灵活,但学习和使用难度更大。

先说LabVIEW的优点:LabVIEW的界面设计简单直观。WPF也许还不成熟,在可视化编辑方面做得并不好。最严重的问题是,一旦界面较为复杂,Visual Studio的界面编辑器就无法对其进行解析显示了。这样就完全失去了可视化编辑的功能。我现在接触的这个项目,有上百个XAML文件,超过7成的文件都无法被界面编辑器显示出来,只能手工的去修改XAML的文本。改完后,运行程序才能看到修改的效果。
再有,界面很少是静态的,界面上常有一些元素会根据程序运行时某些数据的不同而变化,因此,WPF上总有一些控件和程序中某些数据绑定起来。LabVIEW即便在编辑状态下,控件也可以拥有数据。这样以来,程序员在编辑状态下就可以看到程序运行起来后的控件状态。而WPF没有这一功能,程序只有在运行时才有数据,一旦进入编辑状态,所有数据都是空的。这样一来,在界面编辑器上看到的界面很可能与程序运行时的完全不同。

界面上的基本元素是控件,提供什么样的控件给程序员呢,LabVIEW与WPF采用了完全不同的策略。WPF面向通用编程,是给专业程序员用的,所以它侧重功能的强大与编程的灵活性。WPF自带的界面控件种类并不多,但是程序员可以很方便的就把它们组合起来,实现各种界面风格,完成各类复杂功能。LabVIEW只应用于某些领域,而且使用LabVIEW的不仅是程序员。因此LabVIEW侧重控件的易用性:它提供了大量自带的控件,每个控件可供修改的属性有限,如果想使用这些控件很容易:拖到VI前面板上就好了;如果想使用某种LabVIEW尚未提供的控件……那还是不要想了。
实际上LabVIEW今日的应用已远超出当时所定范围,相当一部分LabVIEW使用者都是专业程序员,他们对于功能和灵活性的要求越来越高,因此LabVIEW近几个版本也在这方面做了较大改进,比如增加项目管理功能,支持面向对象等。XControl便是转为补偿LabVIEW自带控件功能和灵活性不足而设计的新功能,但XControl使用起来太过复杂了,不如WPF的机制更加合理。也许将来的LabVIEW应该向WPF学习。
WPF中的控件差不多都可以作为容器再容纳其它控件。比如说按钮这个控件,它只提供一个按钮框架以及按下按钮相关的方法和事件。如果用户希望按钮上有一张图片,可以在按钮控件里面再嵌入一个图片控件;如果希望按钮上再有一行文字,那就在按钮中再放入一个文本框控件;如果还需要其它功能,再放入其它相应控件即可。LabVIEW中的控件不能嵌套使用,LabVIEW提供了带图片的按钮和带文字的按钮,如果需要其它功能,那只能去学习复杂的XControl了。界面常用到一种控件:列表。比如说一张列表有两列,第一列的每个元素都是一个按钮,第二列每个元素是一个下拉框。使用WPF编程非常容易,把按钮和下拉框嵌入列表控件就行了呗;LabVIEW编程可就复杂了,要自己编写程序把个按钮和下拉框控件在界面上移来移去,让它看上去好像在列表框里一样。
LabVIEW中有唯一和WPF控件这种性质类似的控件:Tab。你可以把一个按钮或者灯泡之类的控件放到某个Tab页上去,组合起来使用。

《我和LabVIEW》首页

 

设计:同一功能对应多种不同界面的应用程序

虽然我以前研究过动态注册事件这一功能(3.7.6),但是还没有想到,这个功能有什么实际用途。直到前几天,一个客户向我介绍了他们工作中遇到的困难,我才突然想到,他们的问题恰好可以使用动态注册事件来解决。

他们的问题是这样的:他们开发了一套软件销售给多个用户。用户们对软件功能的需求是一致的,但他们对软件的界面却有各自不同的需求。比如界面的语言、控件的位置、尺寸、颜色等都不同。对于软件开发人员来说,最好的解决方案是程序的代码(程序框图)只有一份,而界面(VI前面板)有多份。常规方法是无法解决这个问题的,因为LabVIEW中每个VI只能对应一个前面板和一个程序框图。
程序中实现界面的那个VI通常是主VI,这个VI中的代码都是比较复杂的。一个程序维护多份功能相同而又复杂的主VI并不是一种优化的方法,发现一个bug,要到每个VI中去改。

动态注册事件的一个用途就是把界面和程序代码完全分离开来。遇到上文客户提出的需求,可以编写多个只有界面的VI,和一个没有界面只有程序框图的VI(这里说的只有界面和只有程序框图,并不是说那个VI真的没有程序框图或界面,只是说它的程序框图或界面特别简单,没有实质内容)。不同界面VI中控件的标签要有统一命名,以便被实现功能那个VI按照控件名来设置或读取控件参数。每个界面上其它的设置,都可以各不相同。界面VI的程序框图需要有一个空循环,以便它可以持续的运行。

程序真正实现功能的那个主VI不需要有界面,它要在后台运行。主程序的主体框架还是传统的循环事件结构。主程序开启后,把界面VI运行起来,需要使用不同的界面,只要在这里修改一下界面VI的路径就可以了。然后,主程序再通过控件的标签得到每一个控件的引用,再把它们注册到事件结构中去。这样一来,主程序就具备了和传统的主VI一样的能力了,读写界面上控件的值,接收控件发出的事件。

这样一来,程序中不再有代码重复的VI,可维护性大大加强。

————————————————————————

 

2011.3.29 今天应网友要求,给这个设计写了一个示例:

示例由三个VI组成。Main.vi实现软件的功能,Interface1,和Interface2分别是程序两个不同风格的界面。

image

我为程序设计了一个非常简单的功能,在界面上点一下按钮,就返回一个随机数值。程序的功能是在Main.vi中实现的,它采用的是经典的事件结构。与一般程序不同的是,它没有界面控件,它所捕获的事件都是通过动态注册生成的。

image

Main.vi的前面板用于把界面VI上控件的引用传递过来。

image

Interface1.vi,它的前面板就是程序界面:

image

它的程序框图不需要做任何实质工作,只要把界面上的控件的引用传递给Main.vi就可以了。

image

Interface2.vi只是与第一种界面风格略有不同:

image

它的程序框图与前一VI完全相同:

image

 

通过这种设计,把程序的界面与功能完全分离到了两个不同的VI中。因此,可以方便的只改变程序的界面而又完全不动程序的功能代码部分。

示例程序可以从这里下载:http://decibel.ni.com/content/docs/DOC-15583

如果需要在LabVIEW中使用到字典容器

(2.3.6) (13.3.5)

编程的时候经常遇到这种情况:需要保存一些数据,这些数据的组织类似一张表格。表格有很多类型相同的条目组成,每个条目由一个标识符(比如ID,名称等),和其它一些数据组成。程序会保存这张表格、对表格中的条目做修改、根据标识符快速找到某的条目。

实现这样的程序功能在C++或C#中非常简单,只要使用他们提供的Map,Dictionary容器就可以了,这些容器已经把维护和查找这张表的功能都实现好了,用户只需使用它们的几个简单接口函数。遗憾的是,LabVIEW中没有提供类似的容器。LabVIEW通常自己定义一个簇的数组来保存表单中的数据,然后再自己编写查询数据的代码。这样做一是编程复杂,而是查询效率太低。

我曾经想过给LabVIEW添加一个这样功能的容器,但是没有得到批准。不过,我最近发现,原来LabVIEW中有三个函数,可以实现类似的功能,虽然它们原本可能并不是用来做这个功能的。这三个函数的本职工作是为变体数据类型设置属性,它们在“Programming->Classter,Class&Variant->Variant”函数选板下,分别是Get Variant Attribute, Set Variant Attribute, Delete Variant Attribute 几个函数。从它们的名字就能知道他们是做什么的了。

变体数据的的属性由一个名字和一个数据组成。每个属性的名字都必须是唯一的,数据可以是任何数据类型的。这样,它恰好适合于前文提到测程序需求。我们可以把表单中的每一个条目看作是一个属性;条目的标识就是属性的名称;条目的其它部分是属性的数据。创建和修改表单使用Set Variant Attribute,Delete Variant Attribute 函数;查询表单的内容使用Get Variant Attribute函数就可以了。

变体的属性在LabVIEW中是以哈希表格式存储的,它的查询效率极高,所以特别适合用于需要大量查询的程序。

它毕竟不是一个真正的容器,还有一些局限性,比如标识只能使用字符串。

队列消息驱动的状态机与事件驱动的状态机的对比

(4.5)

一般来说一个程序的主程序,就是他的主界面。编写这样的程序是有固定套路的,也就是它的设计模式。

在主程序中,少不了对用户界面操作的处理,因此事件结构时必须的。同时,它也会处理一些非界面上的任务,因此程序也必须还有一个选择结构以应对其它工作。这样一来,就有两种程序结构可供选择了:1.选择结构在外,事件结构在内;2.事件结构在外,选择结构在内。

  队列消息驱动 事件驱动
示意图
工作原理 这是一个典型的状态机结构。使用队列记录消息,控制状态的跳转。
选择结构根据每次发来消息的不同,选择一个分支进行处理。这里有一个特殊的状态“No Action”,在没有其它消息的时候,选择结构进入此分支。这个分支内嵌一个事件结构,用于接收用户的界面操作。
使用事件(包括LabVIEW自带的和用户自定义的事件)来控制程序的运行,在不同分之间跳转。
事件结构有一个特殊分支“用户事件”,用于处理所有的非界面事件。其内部嵌套一个选择结构,以处理不同的事件。
实际上如果为程序的每一个处理分支都定义一个用户事件,那么这个程序中可以不需要选择结构。但定义太多的用户事件,比较麻烦,不如像这样定义一个统一的用户事件,然后在其事件处理分支中再根据事件传来的数据区分其具体是何事件。
发展历史 早些年,状态机结构是相当盛行的。这样的程序结构应该是在状态机基础上一步步改进演化来的。类似的程序结构相当多,截图中这个版本取自NI官方的LabVIEW社区,大概是NI一些系统工程师开发出来的。 我自己在编程过程中不断改进演化而来。状态机盛行那会,我没怎么编写过界面程序。而我开始编写界面程序时,LabVIEW已经具有了事件结构。因此,我开始按照自己认为最简洁的方式来设计界面程序。
封装性 这个架构比较复杂的,架构中包含多个子VI,用户管理消息队列(队列的创建、销毁、消息的入队、出队等)。网络上可以找到一些已经编写好的子VI和模板,但是用起来还是稍显复杂。 LabVIEW自带的事件处理函数已经比较简单了,可以不对其做封装就直接使用。但是我为了让程序更简洁,还是对其作了进一步的封装,把主要功能放在几个子VI中。LabVIEW中某些对话框就是采用此架构编写的,因此,这几个子VI是随LabVIEW一起发布的。无需下载就可以直接使用。
代码可读性、可维护性、扩展性 连线和子VI较多一些,程序复杂度高,是的其几项指标都较差。
此外,界面程序最主要的工作还是对界面事件的相应,其它任务居次要地位。而这个架构中把主要对象放在次要对象中的某一分支内,主次颠倒,看起来比较别扭。
连线和子VI较少,程序复杂度低,因此这几项更好。
调整未被处理的任务 由于程序中用于控制程序流程的消息是用户自己管理的,所以比较灵活。用户可以在任何时候对还没有处理到的消息进行调整,比如删除某些消息、改变其顺序等。
但实际上,这种应用比较罕见。
对事件的管理是在LabVIEW内部进行的。用户不能对其做调整。
其它VI对程序流程的控制 在其它VI中,也可插入新的消息到队列中来,从而控制这个VI的运行。
队列有个优点,就是可以通过队列的名字来得到一个队列,而不需要一定把队列的数据线连出去。这个优势可以使得程序编写稍许简化。
在其它VI中,也可抛出一个事件,来控制这个VI的运行。
事件比队列中的消息有个额外的优势,事件被抛出后,任何VI都可以接收到,这样其它VI不但可以控制当前这个VI的运行,也可以监视当前这个VI有哪些事件发出了。
事件比队列的缺陷在于它不能通过名字来获取,一定要连一根数据线。
使用事件结构定时 这个模式中的事件结构的延时设置有特殊用途,必须设定一个100~300ms的超时事件,超时事件发生后,程序继续向下执行。没有这个超时事件,程序可能会被阻塞在事件结构这里,而失去了对其它状态跳转的响应。
所以这里不能再把超时事件用来做定时用。
任何用户自定义事件都会触发事件结构,因此它不存在阻塞的问题。
程序中如有定时需求(比如每1秒采集一个数据),可以把超时事件做定时器用。
状态跳转时的滞后 程序每次运行至事件结构时,都需要等待100~300ms,超时事件产生后才能继续运行下去,如果这是,有新的消息加入到队列中,程序是不会立刻响应的。 没有响应滞后的问题。
适用场合 各种场合皆可,尤其是需要灵活改变消息的顺序时。 各种场合皆可。

框架插件结构两种实现方法的对比

这里说的框架插件结构是指程序启动时或运行中,去查看硬盘某个路径下,有哪些插件模块,然后把它们调用起来的这样一种程序结构。LabVIEW中实现这样的程序机构有两种方法,一是利用LabVIEW Scripting中动的态调用VI,二是利用LVClass。下面比较一下这两种方法各自的优缺点。

  动态调用VI LVClass
LabVIEW版本 LabVIEW很早的版本就具备了动态调用VI的功能。 LabVIEW 8.2开始才支持面向对象的程序设计。
开发的难度 相对来说比较直观易懂。 对于已经了解了LabVIEW面向对象编程的用户来说,做一个插件也是比较简单的。但是如果完全没接触过面向对象这个概念,还要先花不少时间去学习面向对象编程。
插件的形式 插件是一个单独的VI,插件所有的功能都必须在这个VI中实现。 插件是一个对象(类的实例)。插件对象可以拥有多个方法。一个新的插件被添加进来后,它的所有方法可以自动应用于框架程序中任何调用了插件方法的地方。
总结 适合简单程序 适合大型程序

为列表框控件添加自定义的图标

LabVIEW 中 Listbox, Tree 等控件,每个条目之前都可以显示出一个图标。选中控件的右键菜单 Visible Items->Symbols 就可以把这些图标显示出来。

控件中每个条目的图标可以直接通过控件的 Item Symbol 右键菜单来选择,也可通过才程序中设置控件的 Item Symbols属性来设置。控件自带的图标都比较简陋,并且总共只有40几个。(最后一个图标其实不是“图标”,它是分割线,有时可能是非常有用的)

但是LabVIEW提供了对这些图标的扩展功能。通过编程,可以为Listbox控件添加自定义的图标。设置图标时使用的“Custom Item Symbol –> Set To Custom Symbol” 方法,这个方法有两个输入,Index 表示图标的序号。应给给新图标选一个比较大的序号,以免覆盖掉控件自带的图标。第二个参数是图标的图片。

我在这个例子中,自己做了一张图片 Icon.png,它是一张彩色的LabVIEW标志。打开这个图片文件,得到它的图像数据,然后设置给Listbox控件。效果图如下:

在Google Wave上讨论LabVIEW问题

如果还不了解 Google Wave,点击后面的链接查看 Google Wave 的各种介绍。需要 Wave 的邀请,可以在这里留下 Email。

最近公司同事都积极的开始用上它了。在我看来,Google Wave 取代或整合 Gmail 是迟早的事,已经在用 Gmail 的兄弟姐妹,赶快来熟悉一下新系统吧。但 Wave 会不会整体取代传统 Email 就很难说了。商业公司对待更换 Email 系统这样的决定会非常的保守。毕竟,它的影响面实在太广了,公司的营运时刻也离不开 Email。而且,很可能会有一大堆的数据库、服务应用等于 Email 系统绑定在一起。移植的工作量极其巨大。就说我们公司吧,使用的 Loutus Notes 系统。Notes 做的真的很烂,用过的人没有不骂的。可是抱怨了十几年,我们公司也还是在坚持用着。

但不论怎样,Wave 的出现给了大家提供了一条新的交流途径。我的 Wave 帐号和 Eamil 是同一个:ruanqizhen@gmail.com,需要加我的话题尽管加:)。 如果有兴趣在 Wave 上讨论 LabVIEW 问题,可以登录 Wave 后加入这个帖子“试验在Wave上讨论LabVIEW问题”,获得所有LabVIEW讨论者的名单。打算讨论《我和LabVIEW》这本书的问题,可以加入“《我和LabVIEW》讨论区

如何激活LabVIEW Scripting高级功能

LabVIEW Scripting的高级功能(比如创建新的VI,修改VI程序框图上的程序等)是需要特殊授权的。从2009年8月开始,NI公司将这一授权公开给了所有LabVIEW用户。也就是任何一个LabVIEW用户都可以免费申请获得LabVIEW Scripting的高级功能的使用授权。

取得授权并激活这一功能的方法是:

首先打开 LabVIEW Scripting 的网页,网址(http://decibel.ni.com/content/docs/DOC-4973),下载 LabVIEW Scripting 的安装包。安装包在页面的最下方。

比如,我的电脑是Windows XP操作系统,LabVIEW版本8.6,那就下载 LabVIEW Scripting API – WinXP.zip 这个安装包。

这个安装包会为LabVIEW添加一个 LabVIEW Scripting 许可证,许可证还要激活后才能使用。打开NI许可证管理器,找到LabVIEW xx版本下“工具包->Scripting Development”, 选择激活。输入注册码“L12S86758”(这是NI提供给所有用户,专用于激活LabVIEW Scripting 高级功能的注册码)就可以将 LabVIEW Scripting 的高级功能激活了。  

激活 LabVIEW Scripting 后,再打开LabVIEW,可以看到在函数选板“Programming->Application Control”下,多出了三个函数,这三个函数分别用于创建一个新的VI,得到某VI上某个对象的引用,和创建一个新的对象。这里说的对象包括前面板的控件,程序框图上的函数、结构、子VI、数据线,等。

并且,在使用Property Node和Invoke Node的时候会发现,它们多出了很多新的属性和方法共用户使用。使用这些 LabVIEW Scripting 的高级功能,几乎可以完成所有手工编辑VI可以完成的操作。