Labview學(xué)習(xí)筆記_第1頁
Labview學(xué)習(xí)筆記_第2頁
Labview學(xué)習(xí)筆記_第3頁
Labview學(xué)習(xí)筆記_第4頁
Labview學(xué)習(xí)筆記_第5頁
已閱讀5頁,還剩45頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、reference死鎖問題LabVIEW中的引用經(jīng)常需要和“InPlaceElementStructure己合使用。InPlaceElementStructure對(duì)一個(gè)引用的數(shù)據(jù)進(jìn)行處理時(shí),為了保證多線程安全,它會(huì)鎖住引用指向的數(shù)據(jù);其它線程若需對(duì)同一數(shù)據(jù)做操作,必須能這個(gè)InPlaceElementStructure中所有代碼執(zhí)行完畢才可,這樣就避免了多線程讀寫同一內(nèi)存數(shù)據(jù)所產(chǎn)生的競(jìng)爭(zhēng)問題。舉例來說,下面這段程序的執(zhí)行時(shí)間是1秒:而下面這段程序的執(zhí)行時(shí)間則是2秒:j引SingkData.viBlockDiagram£ileEditViewProjectQperateleakWird

2、ojjelpli_空牌向阿圜115Pt4p悶_L因?yàn)榈诙纬绦蛑械膬蓚€(gè)InPlaceElementStructure必須順序執(zhí)行。有了鎖住”這個(gè)操作,就有不小心造成死鎖的可能。比如對(duì)于同一數(shù)據(jù)的引用,千萬不能嵌套使用InPlaceElementStructure否則就會(huì)死鎖:在上面這個(gè)示例中,程序運(yùn)行至內(nèi)層的InPlaceElementStructure就會(huì)停在這里等外層InPlaceElementStructure運(yùn)行結(jié)束,釋放它鎖住白數(shù)據(jù);而對(duì)于外層InPlaceElementStructure來說,它內(nèi)部的全部代碼要運(yùn)行結(jié)束,它才結(jié)束。因而它們相互等待,造成了死鎖。PackedProje

3、ctLibraries2與Library的比較ackedProjectLibrary從名字上來看,就是被包裝好了的ProjectLibrary0ProjectLibrary是編程時(shí)候由程序員創(chuàng)建出來的。比如下圖這個(gè)工程,我在里面創(chuàng)建了一個(gè)叫做“MyAlgorithmLibrary.lvlib的工程庫。它包含兩個(gè)VI,其中一個(gè)是私有的ProjectExplorerMyAlgoriu£ileEditViewProjectOperateToolsWindItemsFiles71瓦ProjectMyAlgorithmLibrary.lvproj3日MyComputftirAlgorithmL

4、ibrary.lvlib-r<.FactcriaLvii、工廿PrivateviDependencies-篤Build5pecifications:$M/PackedLibraryPackedProjectLibrary并不是手工創(chuàng)建的,他是通過一個(gè)項(xiàng)目的生成規(guī)范,從ProjectLibrary編譯而來的。比如上圖的項(xiàng)目,我創(chuàng)建了一個(gè)PackedLibrary類型的生成規(guī)范。我在這個(gè)生成規(guī)范中指定把“MyAlgorithmLibrary.lvlib編譯成PackedProjectLibrary。rTMyPacHtEdLiibiraryPrope-ties編譯的結(jié)果是在我指定的路徑下生成了

5、一個(gè)名為“MyAlgorithmLibrary.lvlibp的文件。它的后綴名僅比PackedLibrary多了一個(gè)字母p。雙擊這個(gè)文件,可以打開它,看到他里面包含的VI:如果需要在其它項(xiàng)目中使用到這個(gè)PackedProjectLibrary,我們可以直接把它加到另一個(gè)項(xiàng)目中去,下圖是一個(gè)演示項(xiàng)目:PackedProjectLibrary看上去和ProjectLibrary非常相似,用法也完全相同。PackedProjectLibrary與ProjectLibrary 都是將功能相關(guān)的一組VI封裝起來的方法; 庫中的VI可以具有層次機(jī)構(gòu); 庫中的VI都帶有名字空間,名字空間是帶有后綴名的庫名;

6、 都可以方便的放在項(xiàng)目管理器里使用盡管它們十分相似,PackedProjectLibrary與ProjectLibrary相比,還是有一些明顯區(qū)別的: PackedProjectLibrary是通過編譯生成的; PackedProjectLibrary中的VI是編譯后產(chǎn)生的,它們不能被修改; PackedProjectLibrary包含有私有VI,但用戶無法看到也不能使用它們; PackedProjectLibrary把VI,.lvlib以及其它用到的文件都打成一個(gè)壓縮包,用戶在磁盤上就只能看到一個(gè).Ivlibp文件,看不到VI文件; PackedProjectLibrary很適合作為最終產(chǎn)品

7、發(fā)布給用戶使用; 在項(xiàng)目中使用PackedProjectLibrary可以縮短編譯時(shí)間,因?yàn)镻ackedProjectLibrary中的VI是已編譯好的,不會(huì)再隨項(xiàng)目編譯一遍。(這一條先這樣寫上,但我還需要再深入研究一下)LabVIEW中LVClass數(shù)據(jù)轉(zhuǎn)換成XML格式的問題前一段時(shí)間,一個(gè)同事的程序出了問題。他在程序中把一個(gè)LVClass類型的數(shù)據(jù)轉(zhuǎn)換成XML格式,再保存成文件。但是從文件中把數(shù)據(jù)轉(zhuǎn)回成LVClass時(shí),卻出了問題:在調(diào)用“UnflattenXML這個(gè)函數(shù)時(shí),程序有時(shí)出錯(cuò),有時(shí)又不出錯(cuò)。他的程序中使用了大量的LVClass,并且它們之間有著復(fù)雜的繼承與包含關(guān)系,以至于花了兩

8、三天的事件,才找出問題所在。其實(shí)是個(gè)簡(jiǎn)單的問題,只是在設(shè)計(jì)程序時(shí)他沒有意識(shí)到。我做了一個(gè)簡(jiǎn)化的程序,可以重現(xiàn)這個(gè)問題:首先,給一個(gè)子類的對(duì)象設(shè)置一些數(shù)據(jù)。然后把它當(dāng)做父類類型的數(shù)據(jù),平化成XML文本,存盤:關(guān)閉LabVIEW,然后重新打開LabVIEW。再編寫一個(gè)反向程序,把XML數(shù)據(jù)轉(zhuǎn)換成父類類型的數(shù)據(jù)::romXMLFileviUnflatt«nFrormXML=OBd|!ReadFromXMLFil虱Wring)-errorout國(guó)|發(fā)現(xiàn)UnflattenFromXML函數(shù)返回一個(gè)錯(cuò)誤,value中是一個(gè)空的數(shù)據(jù)。錯(cuò)誤產(chǎn)生原因如下:在把子類數(shù)據(jù)轉(zhuǎn)換成父類數(shù)據(jù)類型,這個(gè)類型雖然是

9、父類的,但其數(shù)據(jù)仍然是子類的。再轉(zhuǎn)換成XML格式,XML格式中記錄的仍然是子類的數(shù)據(jù)。在反向過程中,UnflattenFromXML拿到的數(shù)據(jù)是子類的,但它企圖轉(zhuǎn)換時(shí),卻發(fā)現(xiàn)內(nèi)存中沒有子類的類型信息,因此它也就不知道如何轉(zhuǎn)換這個(gè)數(shù)據(jù),所以報(bào)錯(cuò)。如果這個(gè)程序稍微改動(dòng)一下,把XML數(shù)據(jù)直接轉(zhuǎn)換成子類的數(shù)據(jù),就不會(huì)出錯(cuò)了:實(shí)際上,子類的數(shù)據(jù)總是可以用父類來表示的。因此這個(gè)XML數(shù)據(jù)亦可以直接被轉(zhuǎn)換成父類的類型,但前提是,一定要保證子類的類型別家在到內(nèi)存中去了。只要在程序中放置一個(gè)子類的對(duì)象,自然就可以把子類加載至內(nèi)存。像下面這個(gè)程序就可以正常工作:FromXMLFileviUnflatt«

10、nFromXMLvdlueRadFromXMLFil而ring)子物星類型父會(huì)災(zāi)據(jù)芟型errorout二1=I這個(gè)實(shí)驗(yàn)反映出兩個(gè)問題:1 .把XML中的內(nèi)容如果是屬于某個(gè)LVClass類型的數(shù)據(jù),把這些數(shù)據(jù)轉(zhuǎn)換回LVClass數(shù)據(jù)時(shí),那個(gè)LVClass一定要已經(jīng)存在于內(nèi)存才行。2 .在之前的一篇文章LvClass的一個(gè)效率問題”中提到過:當(dāng)子類被加載如內(nèi)存時(shí),它所有的父類也會(huì)被加載入內(nèi)存。但反過來并不成立。因?yàn)橐粋€(gè)類有哪些父類是確定的,父類的地址就記錄在子類中。但一個(gè)類并不知道他會(huì)有多少子類,任何人都可以從它派生出不同的子類來,因此它在裝入內(nèi)存時(shí),不可能把自己的子類也都裝進(jìn)來。LabVIEW中

11、實(shí)現(xiàn)鏈表、樹等數(shù)據(jù)結(jié)構(gòu)LabVIEW自帶的數(shù)據(jù)結(jié)構(gòu)只有數(shù)組和隊(duì)列。多數(shù)情況下,這兩種數(shù)據(jù)結(jié)構(gòu)足夠開發(fā)者使用了。但是,我平時(shí)使用C+和C#S言更多一些,所以編寫程序時(shí)常常會(huì)想到使用其它編程語言中常見的數(shù)據(jù)結(jié)構(gòu)比如鏈表(List)、樹(Tree)等。LabVIEW中也可以編程實(shí)現(xiàn)這些數(shù)據(jù)結(jié)構(gòu),一個(gè)比較直觀易懂的編程方法是基于LabVIEW中的類和引用來實(shí)現(xiàn)各類數(shù)據(jù)結(jié)構(gòu)。我在我和LabVIEW一書的第13.3.5節(jié)中介紹了一個(gè)簡(jiǎn)單的鏈表容器的實(shí)現(xiàn)方法,它是基于LvClass編寫的,數(shù)據(jù)流驅(qū)動(dòng)的一種容器。但是正如我在書中提到的,它雖然和有一些和文本編程語言中的鏈表相類似的地方,但本質(zhì)并不相同。文本編程

12、語言中的鏈表,樹等數(shù)據(jù)結(jié)構(gòu)離不開引用(或指針),節(jié)點(diǎn)之間是通過引用來相互關(guān)聯(lián)的。LabVIEW可以為數(shù)據(jù)創(chuàng)建引用,因此也可以方便的實(shí)現(xiàn)與文本語言中功能相同的數(shù)據(jù)結(jié)構(gòu)。這里插一段,介紹一下數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)容器的關(guān)系,我自己理解是這樣的:數(shù)據(jù)結(jié)構(gòu)側(cè)重于數(shù)據(jù)的存儲(chǔ)方式,比如如何排序;數(shù)據(jù)結(jié)構(gòu)在加上與此結(jié)構(gòu)相關(guān)的操作方法,比如添加刪除數(shù)據(jù)等方法,就構(gòu)成了一個(gè)數(shù)據(jù)容器。脫離了操作方法,單純的數(shù)據(jù)結(jié)構(gòu)用處非常有限。因此,我文章中在提到數(shù)據(jù)結(jié)構(gòu)或者數(shù)據(jù)容器時(shí),指的都是同一回事:數(shù)據(jù)結(jié)構(gòu)和相關(guān)的方法。為了介紹如何在LabVIEW中實(shí)現(xiàn)一個(gè)數(shù)據(jù)結(jié)構(gòu),我打算以雙向鏈表為例,講解一下如何編寫它。雙向鏈表中每個(gè)節(jié)點(diǎn)都會(huì)

13、記錄上一個(gè)節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)的位置。因此,在雙向鏈表中,可以從一個(gè)節(jié)點(diǎn)直接跳轉(zhuǎn)到它的上一個(gè)或下一個(gè)節(jié)點(diǎn)上去,也就是正向或反向遍歷整個(gè)鏈表??梢灾庇^的想到,使用LvClass實(shí)現(xiàn)這樣的節(jié)點(diǎn),只要為這個(gè)節(jié)點(diǎn)創(chuàng)建一個(gè)類ListNode,并且這個(gè)類有兩個(gè)成員變量,它們的類型都是ListNode的引用,分別用于指向前一個(gè)和后一個(gè)節(jié)點(diǎn)就可以了:ListNodeDMa;intPrevious:LirtNodeNext:ListNode這樣的設(shè)計(jì)在文本編程語言中是沒有問題的,但在LabVIEW中行不通。其它編程語言中,程序運(yùn)行時(shí),才會(huì)對(duì)類的對(duì)象進(jìn)行初始化。LabVIEW中,VI一打開,它上面的控件和常量就需要被

14、初始化了。某個(gè)對(duì)象在初始化時(shí),它的成員變量也要被初始化,若它的成員變量的類型還是這個(gè)類,這以初始化的過程就陷入了死鎖:類需要它的成員變量先初始化;它成員變量需要這個(gè)類先初始化。基于同樣的原因,一個(gè)類的成員變量的數(shù)據(jù)類型也不可以是這個(gè)類的子類:子類初始化需要先對(duì)它的父類進(jìn)行初始化。但是,一個(gè)類的成員變量的數(shù)據(jù)類型可以是這個(gè)類的父類:父類在初始化的時(shí)候,不需要理會(huì)它的任何子類。既然父類初始化時(shí),不依賴于子類的初始化;而子類的對(duì)象又可以被當(dāng)做父類的類型來保存,咱們就可以利用這一特性在LabVIEW中實(shí)現(xiàn)可以數(shù)據(jù)結(jié)構(gòu)的節(jié)點(diǎn)了。只不過LabVIEW實(shí)現(xiàn)鏈表的節(jié)點(diǎn)要多一個(gè)步驟:我們需要為L(zhǎng)istNode類

15、再定義一個(gè)父類ListNodeVirtual。這個(gè)父類不做任何實(shí)質(zhì)性的工作,它僅用于保存相鄰節(jié)點(diǎn)的引用。ListNodeVirtud;intPrevious:LktNodeVirtualNest:ListrJodEVirtual以上兩個(gè)類是針對(duì)鏈表節(jié)點(diǎn)的雙向鏈表本身也需要做成一個(gè)類:DoubleLinkedList類,這個(gè)類中封裝有鏈表的屬性和方法。比如它需要一個(gè)指向鏈表表頭的引用,需要有為鏈表添加刪除數(shù)據(jù)的方法,為遍歷鏈表中的數(shù)據(jù),還需要有一個(gè)迭代器作為演示,我只實(shí)現(xiàn)了鏈表的幾個(gè)簡(jiǎn)單功能。演示程序工程結(jié)構(gòu)如下:赤ProjectExpllorer-List.lvprqj£ileEdi

16、tyiewProjectOperateTookWindowHe箱片可。2x|)拿胃|陶工HemsFiles:3,幻一ProjectListIvprojEj-國(guó)MyComputerif-ListMcdeVirtualilvdass百.ListNode.IvcIass!h,H解ListNode.ctl*Raddata.viL3Iht|I-息Writedata.viI-Readprevious.virir=ik,a.匕/Writeprevious-viIh'虔,Readnext,vi«X-岫加next.viECoubleLinkedLitt.IvqlaiI-f1DoubleLink

17、edLittctl:/.AppendafterEnumerator.viI阿GetAllCata.vil“至,EnumeratorgoNertiVi例一EnumeratorValue.vi-g.ResetEnurnerator.vir-,Demovil-哲DependencieslGuildSpeqifiqListNode的成員變量包括一個(gè)數(shù)據(jù),和兩個(gè)指向前后節(jié)點(diǎn)的引用:DoubleLinkedList類的成員變量包括指向鏈表頭節(jié)點(diǎn)的引用,迭代器指向的節(jié)點(diǎn)的引用,并記錄了鏈表長(zhǎng)度卜面看一下鏈表中幾個(gè)主要方法是如何實(shí)現(xiàn)的首先是AppendafterEnumerator”這個(gè)方法,它是鏈表里最復(fù)雜

18、的一個(gè)方法。它的輸入是鏈表中一個(gè)新的節(jié)點(diǎn),它把這個(gè)新節(jié)點(diǎn)添加在鏈表迭代器指向的那個(gè)節(jié)點(diǎn)的后面。在給鏈表添加數(shù)據(jù)時(shí),會(huì)遇到兩種情況。首先,這個(gè)鏈表是一個(gè)空鏈表,那么被添加的節(jié)點(diǎn)就是這個(gè)鏈表的首節(jié)點(diǎn),鏈表的迭代器也應(yīng)當(dāng)指向這一唯一的節(jié)點(diǎn)。我設(shè)計(jì)的這個(gè)鏈表是一個(gè)環(huán)狀鏈表。當(dāng)鏈表中只有一個(gè)節(jié)點(diǎn)的時(shí)候,這個(gè)鏈表的上一個(gè)和下一個(gè)節(jié)點(diǎn)都是它自己。如果鏈表不是空的,就把新節(jié)點(diǎn)插在迭代器指向的節(jié)點(diǎn)的后面。因此:新節(jié)點(diǎn)的前一節(jié)點(diǎn)指向的應(yīng)當(dāng)是迭代器指向的那個(gè)節(jié)點(diǎn);新節(jié)點(diǎn)的后一節(jié)點(diǎn)是迭代器指向節(jié)點(diǎn)原來的后一節(jié)點(diǎn)。迭代器指向節(jié)點(diǎn)的新的后一節(jié)點(diǎn)應(yīng)當(dāng)是這個(gè)新節(jié)點(diǎn);原來迭代器的后一節(jié)點(diǎn)的前一節(jié)點(diǎn)也應(yīng)當(dāng)換成這個(gè)新的節(jié)點(diǎn)。最后,

19、我把迭代器也指向了這個(gè)新的節(jié)點(diǎn),這樣連續(xù)添加新節(jié)點(diǎn)時(shí),它們會(huì)按照先后順序插入鏈表。我的演示程序還用到了其它幾個(gè)方法。ResetEnumerator”負(fù)責(zé)把迭代器復(fù)位,也就是指向鏈表的頭節(jié)點(diǎn):ListinfiistenumeratorListoutfirstenumeratorerrorout.卜力kosnEnumeratorgoNext.vi用于讓迭代器向后移動(dòng)一個(gè)節(jié)點(diǎn):erroroiitListoutEnumeratorValue.vi返回迭代器指向的那個(gè)節(jié)點(diǎn):Listinerrorin(noerror)LustoutpJcaterrorout使用這幾個(gè)方法就可以搭建出一個(gè)簡(jiǎn)單的演示程序來看

20、一下鏈表如何工作了。下面這個(gè)演示程序中,分兩部分:第一部分是左面那個(gè)循環(huán),每次循環(huán)迭代就會(huì)創(chuàng)建出一個(gè)新的ListNode對(duì)象,它的數(shù)值是當(dāng)前迭代的次數(shù);右半部分使用鏈表的迭代器遍歷鏈表中的節(jié)點(diǎn)。在這個(gè)演示程序中,迭代器移動(dòng)次數(shù)比鏈表長(zhǎng)度多了兩次,因?yàn)殒湵硎黔h(huán)狀的,轉(zhuǎn)著圈訪問,鏈表中的頭兩個(gè)元素會(huì)被讀出兩遍。程序運(yùn)行后,data顯示了迭代器每一步所指向的節(jié)點(diǎn)的值:data回調(diào)VILabVIEW界面程序最常用的結(jié)構(gòu)就是循環(huán)事件結(jié)構(gòu)。用事件結(jié)構(gòu)截獲用戶在界面上對(duì)控件的操作,然后做出相應(yīng)處理。在文本語言中,常用的事件處理方法與LabVIEW是不同的。文本語言常常使用回調(diào)函數(shù)來處理界面事件。比如:某個(gè)按

21、鈕按下時(shí),需要做一個(gè)fft運(yùn)算。那么就寫一段函數(shù)來完成這個(gè)fft運(yùn)算,再把這個(gè)函數(shù)與按鈕按下事件關(guān)聯(lián)起來。開發(fā)語言通常已經(jīng)做好了對(duì)事件的監(jiān)控,一旦發(fā)現(xiàn)按鈕按下事件產(chǎn)生了,就去調(diào)用與它關(guān)聯(lián)的fft運(yùn)算函數(shù)。這個(gè)有開發(fā)者編寫,被系統(tǒng)調(diào)用的函數(shù)就叫做回調(diào)函數(shù)。LabVIEW也可以采用與文本語言相類似的方法來處理事件:不是在事件結(jié)構(gòu)內(nèi)處理,而是在程序開始時(shí),就為某事件注冊(cè)一個(gè)回調(diào)VI。在回調(diào)VI內(nèi)編寫相應(yīng)代碼,一旦事件發(fā)生,這段代碼就會(huì)被執(zhí)行。與事件結(jié)構(gòu)相比,回調(diào)VI編寫起來稍微麻煩一點(diǎn);但它的好處是,它和主VI是平行運(yùn)行的。如果事件處理過程比較耗時(shí),把它放在事件結(jié)構(gòu)中會(huì)阻塞整個(gè)程序,使得程序界面暫時(shí)

22、失去響應(yīng);而把它放在回調(diào)VI中,則不會(huì)影響程序其它部分的運(yùn)行。比如下面這個(gè)例子。程序界面上有兩個(gè)儀表盤:左面那個(gè)始終在運(yùn)轉(zhuǎn),每10秒鐘旋轉(zhuǎn)一圈;右邊那個(gè),由按鈕控制,按下按鈕才旋轉(zhuǎn)一圈。若把旋轉(zhuǎn)右表這個(gè)工作放到事件結(jié)構(gòu)的按鈕按下處理分支中去做,它勢(shì)必會(huì)打斷左表的旋轉(zhuǎn),因此,考慮把它放到回調(diào)VI中去做。這是主程序界面:兩個(gè)表盤,和一個(gè)控制右表旋轉(zhuǎn)的按鈕程序的代碼也比較簡(jiǎn)單。先看代碼的右半部份:這是一個(gè)典型的循環(huán)事件結(jié)構(gòu),用來控制左表的旋轉(zhuǎn)。但是注意,右表的控制并不是在這個(gè)結(jié)構(gòu)中實(shí)現(xiàn)的。再看程序左半部分:它為按鈕右表旋轉(zhuǎn)一圈”的值改變事件注冊(cè)了一個(gè)回調(diào)VI0注冊(cè)回調(diào)VI用的是節(jié)點(diǎn)“Register

23、EventCallback它在函數(shù)選板“Connectivly>-ActiveX上。這個(gè)節(jié)點(diǎn)主要是為了給ActiveX、.NET控件的事件注冊(cè)回調(diào)VI。事件結(jié)構(gòu)無法截獲ActiveX、.NET控件的事件,因此只能通過回調(diào)VI的方式來處理這些控件的事件。但是這個(gè)節(jié)點(diǎn)也可以用于給LabVIEW自帶的控件注冊(cè)回調(diào)VI。注冊(cè)回調(diào)VI節(jié)點(diǎn),有三個(gè)輸入?yún)?shù)從上至下分別是:事件的發(fā)出者、回調(diào)VI、用戶自定義數(shù)據(jù)。在我們這個(gè)例子中,需要截獲的是按鈕右表旋轉(zhuǎn)一圈”的值改變事件,因此需要把右表旋轉(zhuǎn)一圈”控件的引用作為第一個(gè)參數(shù)傳遞給注冊(cè)回調(diào)VI節(jié)點(diǎn)。指定好事件的發(fā)出者,接下來需要選擇事件的類型,鼠標(biāo)點(diǎn)擊注冊(cè)

24、回調(diào)VI節(jié)點(diǎn)的第一個(gè)參數(shù)的接線方塊,發(fā)現(xiàn)右表旋轉(zhuǎn)一圈”按鈕的所有事件都已經(jīng)列在這里了,選擇俏改變”事件。第三個(gè)參數(shù)是用戶自定義數(shù)據(jù),可以是任意類型的數(shù)據(jù),在回調(diào)VI中需要用到的數(shù)據(jù)都可以通過它來傳遞。因?yàn)槲掖蛩阍诨卣{(diào)VI中對(duì)控件右表”做修改,因此,在這里把右表”的引用作為數(shù)據(jù)傳遞給回調(diào)VI。第二個(gè)參數(shù)是回調(diào)VI的引用,如果已經(jīng)寫好了回調(diào)VI,把引用傳進(jìn)去就行了。我還沒有編寫回調(diào)VI,因此可以在參數(shù)的接線端上點(diǎn)擊鼠標(biāo)右鍵,選擇“CreateCallbackVI創(chuàng)建一個(gè)空白的回調(diào)VI?;卣{(diào)VI中寫一小段代碼,讓右表旋轉(zhuǎn)一圈,整個(gè)程序就完成了。這時(shí),左右表可以各自運(yùn)行,互不影響。LvClass的一個(gè)

25、效率問題前幾天,聽到了一個(gè)客戶的抱怨:他編寫了一個(gè)LabVIEW程序,每次打開主程序就要花費(fèi)幾分鐘的時(shí)間,這有點(diǎn)令他忍無可忍。我沒有見過他的源程序,不過據(jù)幫他檢查過程序的同事講,他的問題很可能是使用了大量的LvClass造成的。在他的項(xiàng)目中,包含有上百個(gè)類(LvClass)o我以前也聽說過LvClass在效率上可能會(huì)有些問題,聽到了這個(gè)消息后,我自己做了一個(gè)實(shí)驗(yàn)。LabVIEWScripting中有一個(gè)屬性節(jié)點(diǎn)可以用來查看內(nèi)存中所有的VI,我就利用這個(gè)VI來查看一個(gè)程序到底在裝入些什么,令它啟動(dòng)如此之慢。假設(shè)不存在子VI,如果打開某個(gè)不在LvClass中的VI(即使這個(gè)VI是屬于某個(gè)lvlib

26、的),只有這個(gè)VI會(huì)被裝入內(nèi)存。但是,打開某一個(gè)LvClass中的VI,我發(fā)現(xiàn)不但這個(gè)VI會(huì)被裝入內(nèi)存,它所在的類中的所有其它的VI也都被調(diào)入內(nèi)存。如果這個(gè)類還有父類和祖先類,那么所有父類、祖先類中的VI統(tǒng)統(tǒng)都會(huì)被調(diào)入內(nèi)存。總結(jié)一下就是這樣:當(dāng)一個(gè)VI被裝入內(nèi)存1 .它的所有子VI都會(huì)被裝入內(nèi)存;2 .它所在的類中的所有的VI都會(huì)被裝入內(nèi)存;3 .它所在的類的父類中的所有的VI都會(huì)被裝入內(nèi)存以上3條可以是遞歸發(fā)生的,比如一個(gè)主VIA被裝入內(nèi)存,它的子VIB也會(huì)被裝入內(nèi)存,和B同屬一個(gè)類的VIC也要被裝入內(nèi)存,C中有個(gè)子VID,D屬于類E,E有個(gè)父類F,F中有個(gè)方法VIGo盡管G的功能和程序A八

27、桿子都打不著了,但也會(huì)被裝進(jìn)來。這大概就是那個(gè)用戶遇到的問題,表面上他的程序不算太大,但是程序開始啟動(dòng)時(shí),卻需要把多于程序本身數(shù)倍的不相關(guān)的VI都裝入內(nèi)存,這一過程會(huì)每次都浪費(fèi)他幾分鐘的時(shí)間。鑒于LvClass的這一特性,設(shè)計(jì)使用它的時(shí)候一定要格外小心,否則很可能會(huì)造成程序效率的低下。我想到了幾點(diǎn)需要注意的地方:1 .如果僅需要對(duì)一些VI進(jìn)行封裝,那么應(yīng)當(dāng)使用lvlib,而不是lvclass。兩者封裝的主要區(qū)別是,lvclass可以封裝對(duì)象的屬性(也就是模塊用到的數(shù)據(jù))。2 .類中的VI必須是高內(nèi)聚的,類中的方法共同完成某一基本功能,不可再分割。應(yīng)用程序一旦用到這個(gè)類中的某個(gè)VI,就意味著程序

28、將會(huì)使用到類中幾乎全部的VI;而不是一個(gè)應(yīng)用程序可能只使用這個(gè)類中的某幾個(gè)VI。3 .繼承關(guān)系應(yīng)當(dāng)盡量簡(jiǎn)單。沒有必要的時(shí)候盡量不使用繼承。LabVIEW不支持接口,不應(yīng)創(chuàng)建一個(gè)純虛類,然后當(dāng)作接口來用。4 .盡量不要嵌套調(diào)用。比如在一個(gè)類的VI中又去調(diào)用另一個(gè)類中的VI。5 .打算使用多態(tài)這個(gè)特性時(shí)要注意,多態(tài)使得應(yīng)用程序在運(yùn)行時(shí),根據(jù)對(duì)象的類型選擇對(duì)應(yīng)的處理方法。但有些選擇應(yīng)當(dāng)是程序編譯時(shí)就做出的,它們不適合套用在多態(tài)特性上。舉一些例子: INI文件讀寫這個(gè)模塊比較適合做成類,每個(gè)INI文件對(duì)應(yīng)一個(gè)類的實(shí)例。它有豐富的數(shù)據(jù)(文件的內(nèi)容);它的方法有限,基本上只需要打開、讀條目、寫條目、保存關(guān)

29、閉,這四個(gè)方法,并且一般的應(yīng)用程序都會(huì)同時(shí)使用到這四個(gè)方法。 復(fù)雜儀器的驅(qū)動(dòng)程序不適合做成類。因?yàn)轵?qū)動(dòng)程序會(huì)提供非常多的功能,示波器有各種觸發(fā)模式。而一個(gè)應(yīng)用程序通常只用到多種模式中的某一種就夠用了。 某測(cè)試程序可以生成測(cè)試報(bào)告給用戶。用戶可以選擇幾種不同的報(bào)告類型。生成報(bào)告的模塊可以用Ivclass來設(shè)計(jì)。因?yàn)樯刹煌愋偷膱?bào)告的方法問,可重用代碼很多,可以為它們?cè)O(shè)計(jì)一個(gè)基類。并且,是程序運(yùn)行時(shí),才選擇生成報(bào)告類型的。 某一測(cè)試程序,可以支持多種型號(hào)的儀器。因?yàn)椴煌脩羰褂貌煌挠布?duì)不同型號(hào)儀器的支持不適合使用Ivclass來設(shè)計(jì),因?yàn)闇y(cè)試程序發(fā)布給用戶時(shí),用戶的硬件設(shè)備是固定的。對(duì)儀器

30、的選擇應(yīng)當(dāng)是程序發(fā)布時(shí)就決定好的,而不應(yīng)等到程序每次運(yùn)行起來后判斷。如何在程序中同時(shí)彈出多個(gè)子VI的界面,各自運(yùn)行互不影響回答網(wǎng)友一個(gè)問題:我設(shè)計(jì)了一個(gè)labview界面子VI,我想在主VI中多次調(diào)用該界面VI(同時(shí)執(zhí)行,單獨(dú)分配內(nèi)存),并顯示出多窗口,該如何設(shè)置?我嘗試將子VI屬性設(shè)置成可重入,仍無法解決?!边@個(gè)問題其實(shí)挺常見的。若需要子VI打開多份實(shí)例,子VI必須是可重入的。所以第一步要把子VI設(shè)置為可重入。但僅僅這樣還不夠,主程序運(yùn)行到子VI處,把子VI打開后,會(huì)一直等在這里,知道子VI運(yùn)行結(jié)束,才繼續(xù)執(zhí)行主VI后續(xù)的代碼。主VI既然已經(jīng)停在這里了,自然不會(huì)再繼續(xù)去打開其它子VI。解決的

31、辦法是在調(diào)用子VI的地方,改為動(dòng)態(tài)調(diào)用,并且不等待子VI運(yùn)行結(jié)束。這樣一來,主程序運(yùn)行到這里,將子VI調(diào)起后,立即執(zhí)行后續(xù)代碼,又可以去調(diào)用其它的子VI了。需要注意的是,用于子VI是可重入的,需要給“OpenVIReference!'數(shù)設(shè)置一個(gè)值為“8的Options參數(shù)。主VI程序代碼如下:口也8:PTe:ppreferreentrantrur>-LabVIEW2009新功能幅引用以前版本的LabVIEW雖然也有多種方法可以讓數(shù)據(jù)以引用的方式在程序間傳遞,但是用起來都有些麻煩。LabVIEW有了構(gòu)建數(shù)據(jù)傳引用的節(jié)點(diǎn),大大簡(jiǎn)化了傳引用的程序代碼。新添的有關(guān)傳引用的兩個(gè)節(jié)點(diǎn)在函數(shù)選

32、板“Programir->ApplicationControl->MemoryControl中,分別是“NewDataValueReferenceDeleteDataValueReference:'NNewDataValueReferences于創(chuàng)建一個(gè)數(shù)據(jù)的引用,“DeleteDataValueReference可以從引用中取回原來的數(shù)據(jù)。引用最主要應(yīng)用于多線程程序中。如果兩個(gè)線程同時(shí)對(duì)同一份數(shù)據(jù)進(jìn)行修改,則必須使用傳引用的機(jī)制。否則,使用值傳遞的方式,數(shù)據(jù)在數(shù)據(jù)線分叉的地方,就會(huì)編程獨(dú)立的兩份,之后在兩個(gè)線程內(nèi)分別修改的是兩份完全獨(dú)立的數(shù)據(jù),沒辦法對(duì)同一份數(shù)據(jù)進(jìn)行修改的

33、。比如下圖這個(gè)程序,程序輸入了一個(gè)數(shù)組,然后需要在兩個(gè)并行的子VI中同時(shí)對(duì)這個(gè)數(shù)組中的數(shù)據(jù)進(jìn)行修改。每個(gè)子VI可能修改了數(shù)組不同的元素,程序運(yùn)行結(jié)束產(chǎn)生的數(shù)組應(yīng)當(dāng)把兩個(gè)子VI中的修改都包含進(jìn)來。因此,程序一開始需要數(shù)組數(shù)據(jù)生成一個(gè)引用,然后把引用分別傳遞到兩個(gè)子VI中去。兩個(gè)子VI都運(yùn)行結(jié)束后,在從引用中取回?cái)?shù)據(jù)。dataindataoutLabVIEW中已有的函數(shù)還都是為值傳遞設(shè)計(jì)的,所以使用值傳遞少不了把數(shù)據(jù)取出、放回的過程。這以過程中,可能又會(huì)產(chǎn)生數(shù)據(jù)拷貝,效率會(huì)比較差。好在我們可以使用“InPlaceElementStructur鉆構(gòu)來處理從引用中取出、放回?cái)?shù)據(jù)的過程<配合了“I

34、nPlaceElementStructur結(jié)構(gòu)使用后,LabVIEW會(huì)盡量使用數(shù)組原地址,而不是把從引用中取出的數(shù)據(jù)復(fù)制一份,這樣就做到了傳引用與效率的兼顧。比如下面兩圖中的程序,功能是完全相同的,但LabVIEW會(huì)對(duì)下面一幅圖中的程序進(jìn)行優(yōu)化,提高效率。dvaluereferenctErrcrin(noerror二sUvsIijisreferenceouterrorout美化程序僚藏程序框圖上的大個(gè)Cluster在編寫某些程序的時(shí)候可能會(huì)遇到如圖1所示的情形:即用到了一個(gè)極為復(fù)雜的數(shù)據(jù)類型常量。這個(gè)常量由于體積巨大,使得在程序框圖無論怎么擺放都讓人看起來不太舒服。如何才能把這個(gè)程序改造得美觀

35、一些呢?圖1:體積巨大的常量會(huì)有礙觀瞻要解決這個(gè)問題,只有設(shè)法把這個(gè)常量在主程序框圖上隱藏起來。通常可以用以下兩種方法。第一種方法:把這個(gè)常數(shù)變換成控件,再把控件隱藏起來。這種方法比較簡(jiǎn)單,但是也有弊病。容易引起誤解:控件一般表示有值傳入,其他人讀程序讀到這里就可能搞不清楚這個(gè)值是從哪里傳來的了;如果要修改常量Cluster中某一個(gè)元素的值,操作起來比較麻煩。第二種方法,也就是我向大家推薦的:把它隱藏到更深層的子VI中去。具體操作方法如下:如圖2先給這個(gè)復(fù)雜數(shù)據(jù)類型建立一個(gè)StrictTypeDef。我的建議是為所有程序中用到的Cluster都建立一個(gè)StrictTypeDef。這樣可以為以后

36、的程序維護(hù)省去很多麻煩。圖2:StrictTypeDef.然后然后再建立一個(gè)新的VI,把我們要隱藏的這個(gè)個(gè)頭巨大的常量擺放在這個(gè)VI中,并且連接一個(gè)Indicator,以把它的值傳出來。VI的接線板采用4-2-2-4格式的,最下層第3個(gè)接線端用于傳出VI中唯一的數(shù)據(jù),如圖3所示。圖3:用于隱藏個(gè)頭巨大常量的VI這個(gè)VI的圖標(biāo)要做得小巧漂亮,如圖4,圖標(biāo)不一定非要做成正方形。只要B&W和256Colors中的圖標(biāo)形狀一樣,我們就可以畫出不規(guī)則圖標(biāo)了。詳細(xì)方法可以參考制作不規(guī)則圖形的子VI圖標(biāo)。圖4:常量數(shù)據(jù)VI的圖標(biāo)把這個(gè)新造出來的常量數(shù)據(jù)VI拖到程序框圖上,把它的輸出鏈接到剛才鏈接常量

37、的地方,再把位置擺放好。現(xiàn)在我們的程序是不是漂亮多了圖5:改造后的程序框圖Caption和Label的書寫規(guī)范LabVIEW控件的Caption和Label的特性和用途很相似,都是給了控件一個(gè)有意義的名字。因此,在很多場(chǎng)合沒有必要刻意區(qū)分他們。Caption和Label的最主要區(qū)別在于,Caption可以在程序運(yùn)行的時(shí)候改變;而Label則不可以,一旦程序運(yùn)行,就固定不變了。鑒于這一點(diǎn),Caption和Label的用途也略有區(qū)別。Label應(yīng)該是給程序自己用的,比如在程序中需要根據(jù)控件的名字找到它,那就得跟據(jù)Label來找,而不能用Caption來找;Caption是為了給用戶看的,有時(shí)控件的

38、名字在運(yùn)行到不同狀態(tài)下需要發(fā)生改變,此時(shí)顯示在界面上的就應(yīng)該是Caption推薦大家按照下面的規(guī)范使用Caption和Label。先給VI分一下類:1 .底層VI:用戶不會(huì)直接使用到的VI,作為subVI隨程序一起發(fā)布。2 .用戶界面VI:VI前面板是給用戶看的程序界面的一部分。3 .程序接口VI:VI是提供給用戶,在他們編程時(shí),當(dāng)作API被調(diào)用。對(duì)于Caption和Label一個(gè)共同的書寫規(guī)范是:使用有意義的文字,在使用英語短語命名時(shí),單詞之間用空格分隔,不應(yīng)該有重名。不同點(diǎn)列于下表:LabelCaption底層VI顯示出來使用LabVIEW的默認(rèn)狀態(tài),即Caption為空。用戶界面VI隱藏

39、多諦言版本中,只使用英語顯示多語百版本中,使用本地化語百程序接口VI隱藏多諦言版本中,只使用英語不用標(biāo)注控件的默認(rèn)值顯示多語百版本中,使用本地化語百在后面加一括號(hào),括號(hào)內(nèi)標(biāo)注控件的默認(rèn)值和數(shù)據(jù)單位在LabVIEW中實(shí)現(xiàn)VI的遞歸調(diào)用LabVIEW中使用遞歸調(diào)用不是很方便。不過遞歸并不是編程必須程序結(jié)構(gòu),任何需要使用遞歸調(diào)用的地方,都可以用循環(huán)結(jié)構(gòu)來代替。但是在某些情況下,使用遞歸調(diào)用的確可以大大簡(jiǎn)化程序代碼,對(duì)縮短編程時(shí)間、提高程序可讀性都非常有幫助,所以學(xué)習(xí)一下遞歸的實(shí)現(xiàn)方法還是有好處的。一、為什么VI不能夠被靜態(tài)的遞歸調(diào)用LabVIEW不能通過靜態(tài)調(diào)用的方法(把子VI直接放到另一VI的程序

40、框圖上)來實(shí)現(xiàn)遞歸。對(duì)于一個(gè)非可重入的subVI,在每一個(gè)時(shí)間,這個(gè)subVI這能被運(yùn)行一次。LabVIEW需要借此來保證多線程時(shí)的數(shù)據(jù)安全。對(duì)于被遞歸調(diào)用的代碼,是需要在它執(zhí)行到中間的時(shí)候,就再次被調(diào)用的。所以默認(rèn)設(shè)置下的VI不能被靜態(tài)遞歸調(diào)用。對(duì)于被設(shè)置為可重入的VI,是可以被同時(shí)調(diào)用多次的,但也不能被靜態(tài)的遞歸調(diào)用。除非是通過VIServer動(dòng)態(tài)的調(diào)用VI,否則,LabVIEW是在一個(gè)程序被調(diào)入內(nèi)存,開始運(yùn)行之前就為它的所有VI分配好內(nèi)存空間的,包括數(shù)據(jù)區(qū)。如果一個(gè)VI不是可重入的,LabVIEW會(huì)在這個(gè)VI運(yùn)行時(shí)局部變量所在的數(shù)據(jù)區(qū)開辟在這個(gè)VI所在的空間內(nèi);對(duì)于可重入的VI,LabV

41、IEW把它的數(shù)據(jù)區(qū)開辟在調(diào)用者VI上,這樣就可以保證這個(gè)可重入VI在不同的地方被同時(shí)調(diào)用時(shí)使用不同的數(shù)據(jù)區(qū),以防止多線程運(yùn)行時(shí)數(shù)據(jù)混亂。因此,可重入VI雖然可以被同時(shí)多次調(diào)用,但是被調(diào)用的次數(shù)是運(yùn)行前就確定的。而遞歸運(yùn)算時(shí)的調(diào)用次數(shù)是運(yùn)行時(shí)決定的。這樣,如果是靜態(tài)調(diào)用,LabVIEW根本沒有辦法為提前為參與遞歸的VI開辟好數(shù)據(jù)區(qū)。二、用動(dòng)態(tài)調(diào)用方法實(shí)現(xiàn)遞歸圖1是一個(gè)采用遞歸算法計(jì)算階乘的例子,可以點(diǎn)擊后面的連接直接下載示例VI:3535080153251.rarkl皿Eiror圖1:利用遞歸結(jié)構(gòu)計(jì)算階乘正如前文說過的,所有的遞歸都可以使用循環(huán)來代替,計(jì)算階乘也可以使用循環(huán)結(jié)構(gòu),但是這里介紹的是

42、使用遞歸結(jié)構(gòu)的方法。因?yàn)閚!=n*(n-1)!,所以我們只要編寫一個(gè)VI實(shí)現(xiàn)功能F(n)=n*F(n-1)就可以了。程序中,遞歸調(diào)用VI自身的結(jié)構(gòu)由三個(gè)VI動(dòng)態(tài)調(diào)用節(jié)點(diǎn)實(shí)現(xiàn):OpenVIReference,CallByReferenceNode,CloseReference這三個(gè)節(jié)點(diǎn)分別負(fù)責(zé)動(dòng)態(tài)打開一個(gè)VI(本例中就是這個(gè)VI自身),運(yùn)行這個(gè)VI,再關(guān)閉它。使用CallByReferenceNode需要在打開VI句柄的時(shí)候就要知道VI連線板(ConnectorPane的布局,因止匕,我們?cè)谟肙penVIReference打開VI的時(shí)候要提供VI連線板的布局信息,在例子中就是OpenVIRefe

43、rence節(jié)點(diǎn)上方的那個(gè)常量。三、使用遞歸時(shí)的幾點(diǎn)注意事項(xiàng)遞歸調(diào)用的退出或結(jié)束條件,本例中當(dāng)輸入數(shù)據(jù)小于1時(shí),就需要結(jié)束遞歸調(diào)用返回最底層的值了。如果遞歸調(diào)用的退出條件設(shè)置不當(dāng),可能會(huì)引起程序死循環(huán)甚至崩潰。LabVIEW中也可以實(shí)現(xiàn)A調(diào)用B,B又調(diào)用A這種用多個(gè)VI相互調(diào)用的遞歸結(jié)參與遞歸調(diào)用的VI必須被設(shè)置為可重入。動(dòng)態(tài)調(diào)用的需要把VI在運(yùn)行時(shí)調(diào)入內(nèi)存,這個(gè)過程是比較耗時(shí)的。因此遞歸結(jié)構(gòu)的運(yùn)行效率遠(yuǎn)不如可實(shí)現(xiàn)相同功能的循環(huán)結(jié)構(gòu),內(nèi)存占用也會(huì)更大一些。決定使用遞歸結(jié)構(gòu)之前要考慮到這些因素。在LabVIEW中實(shí)現(xiàn)VI的遞歸調(diào)用LabVIEW中使用遞歸調(diào)用不是很方便。不過遞歸并不是編程必須程序結(jié)

44、構(gòu),任何需要使用遞歸調(diào)用的地方,都可以用循環(huán)結(jié)構(gòu)來代替。但是在某些情況下,使用遞歸調(diào)用的確可以大大簡(jiǎn)化程序代碼,對(duì)縮短編程時(shí)間、提高程序可讀性都非常有幫助,所以學(xué)習(xí)一下遞歸的實(shí)現(xiàn)方法還是有好處的。一、為什么VI不能夠被靜態(tài)的遞歸調(diào)用LabVIEW不能通過靜態(tài)調(diào)用的方法(把子VI直接放到另一VI的程序框圖上)來實(shí)現(xiàn)遞歸。對(duì)于一個(gè)非可重入的subVI,在每一個(gè)時(shí)間,這個(gè)subVI這能被運(yùn)行一次。LabVIEW需要借此來保證多線程時(shí)的數(shù)據(jù)安全。對(duì)于被遞歸調(diào)用的代碼,是需要在它執(zhí)行到中間的時(shí)候,就再次被調(diào)用的。所以默認(rèn)設(shè)置下的VI不能被靜態(tài)遞歸調(diào)用。對(duì)于被設(shè)置為可重入的VI,是可以被同時(shí)調(diào)用多次的,但

45、也不能被靜態(tài)的遞歸調(diào)用。除非是通過VIServer動(dòng)態(tài)的調(diào)用VI,否則,LabVIEW是在一個(gè)程序被調(diào)入內(nèi)存,開始運(yùn)行之前就為它的所有VI分配好內(nèi)存空間的,包括數(shù)據(jù)區(qū)。如果一個(gè)VI不是可重入的,LabVIEW會(huì)在這個(gè)VI運(yùn)行時(shí)局部變量所在的數(shù)據(jù)區(qū)開辟在這個(gè)VI所在的空間內(nèi);對(duì)于可重入的VI,LabVIEW把它的數(shù)據(jù)區(qū)開辟在調(diào)用者VI上,這樣就可以保證這個(gè)可重入VI在不同的地方被同時(shí)調(diào)用時(shí)使用不同的數(shù)據(jù)區(qū),以防止多線程運(yùn)行時(shí)數(shù)據(jù)混亂。因此,可重入VI雖然可以被同時(shí)多次調(diào)用,但是被調(diào)用的次數(shù)是運(yùn)行前就確定的。而遞歸運(yùn)算時(shí)的調(diào)用次數(shù)是運(yùn)行時(shí)決定的。這樣,如果是靜態(tài)調(diào)用,LabVIEW根本沒有辦法為提

46、前為參與遞歸的VI開辟好數(shù)據(jù)區(qū)。二、用動(dòng)態(tài)調(diào)用方法實(shí)現(xiàn)遞歸圖1是一個(gè)采用遞歸算法計(jì)算階乘的例子,可以點(diǎn)擊后面的連接直接下載示例VI:3535080153251.rarkl皿Eiror圖1:利用遞歸結(jié)構(gòu)計(jì)算階乘正如前文說過的,所有的遞歸都可以使用循環(huán)來代替,計(jì)算階乘也可以使用循環(huán)結(jié)構(gòu),但是這里介紹的是使用遞歸結(jié)構(gòu)的方法。因?yàn)閚!=n*(n-1)!,所以我們只要編寫一個(gè)VI實(shí)現(xiàn)功能F(n)=n*F(n-1)就可以了。程序中,遞歸調(diào)用VI自身的結(jié)構(gòu)由三個(gè)VI動(dòng)態(tài)調(diào)用節(jié)點(diǎn)實(shí)現(xiàn):OpenVIReference,CallByReferenceNode,CloseReference這三個(gè)節(jié)點(diǎn)分別負(fù)責(zé)動(dòng)態(tài)打開

47、一個(gè)VI(本例中就是這個(gè)VI自身),運(yùn)行這個(gè)VI,再關(guān)閉它。使用CallByReferenceNode需要在打開VI句柄的時(shí)候就要知道VI連線板(ConnectorPane的布局,因止匕,我們?cè)谟肙penVIReference打開VI的時(shí)候要提供VI連線板的布局信息,在例子中就是OpenVIReference節(jié)點(diǎn)上方的那個(gè)常量。三、使用遞歸時(shí)的幾點(diǎn)注意事項(xiàng)遞歸調(diào)用的退出或結(jié)束條件,本例中當(dāng)輸入數(shù)據(jù)小于1時(shí),就需要結(jié)束遞歸調(diào)用返回最底層的值了。如果遞歸調(diào)用的退出條件設(shè)置不當(dāng),可能會(huì)引起程序死循環(huán)甚至崩潰。LabVIEW中也可以實(shí)現(xiàn)A調(diào)用B,B又調(diào)用A這種用多個(gè)VI相互調(diào)用的遞歸結(jié)參與遞歸調(diào)用的V

48、I必須被設(shè)置為可重入。動(dòng)態(tài)調(diào)用的需要把VI在運(yùn)行時(shí)調(diào)入內(nèi)存,這個(gè)過程是比較耗時(shí)的。因此遞歸結(jié)構(gòu)的運(yùn)行效率遠(yuǎn)不如可實(shí)現(xiàn)相同功能的循環(huán)結(jié)構(gòu),內(nèi)存占用也會(huì)更大一些。決定使用遞歸結(jié)構(gòu)之前要考慮到這些因素。一個(gè)XControl的實(shí)例XControl與.ctl用戶定義控件相比,其最大的提高就在于它不但可以定義控件的外觀,還可以定義控件的行為。在XControl出現(xiàn)之前,同樣可以在程序中編寫代碼,控制程序的行為。在用XControl實(shí)現(xiàn)面向組件的編程一文中提到了,這種方法在程序模塊劃分上有缺陷。如果用戶想發(fā)布一個(gè)帶有特定行為的控件也是不可能的,因?yàn)榭刂瓶丶袨榈拇a,是同其它代碼混雜在一起的。利用XCont

49、rol可以解決上面提到的問題,這里以一個(gè)例子說明一下如何利用XControl實(shí)現(xiàn)一個(gè)有特定行為的控件。Windows風(fēng)格的工具條上的按鈕有一個(gè)特點(diǎn),就是當(dāng)鼠標(biāo)移動(dòng)到按鈕上方,按鈕就會(huì)變亮或浮起。LabVIEW中默認(rèn)的按鈕沒有這樣的特性,但是實(shí)現(xiàn)這一點(diǎn)是很容易的。以鼠標(biāo)移上,按鈕變亮為例:在程序中,當(dāng)按鈕的MouseEnter事件發(fā)生時(shí),把按鈕的顏色設(shè)置為淺顏色;當(dāng)按鈕的MouseLeave事件發(fā)生時(shí),把按鈕的顏色設(shè)置為深色即可。現(xiàn)在把界面上的按鈕和控制顏色的代碼都封裝在一個(gè)XControl中。這樣,其他人在使用這個(gè)XControl時(shí),就無需修改他的代碼,而直接獲得這種顏色變化的特性了。一、簡(jiǎn)單

50、行為的XControl首先創(chuàng)建一個(gè)空的XControl。圖1、2:創(chuàng)建一個(gè)新的XControl新的XControl中有四個(gè)VI。Data.ctl定義XControl的數(shù)據(jù)類型。比如我們要做一個(gè)按鈕,數(shù)據(jù)類型應(yīng)該是布爾型。如果要作一個(gè)工具條,數(shù)據(jù)類型就應(yīng)該是布爾型數(shù)組了。State.ctl定義XControl內(nèi)部要用到的一些數(shù)據(jù),類似于類的私有變量。我們這個(gè)簡(jiǎn)單的例子用不到任何變量,所以可以不去動(dòng)它。Init.vi類似于類的構(gòu)造函數(shù)。在我們這個(gè)簡(jiǎn)單的例子中也不需要去改變它。Facade.vi是最主要的VI,XControl的外觀和行為都是在這個(gè)VI中定義的。Facade.vi的界面就是XCont

51、rol控件的外觀。控制控件行為的代碼也是放在這個(gè)VI的程序框圖上。我們要做的是個(gè)按鈕,所以就在Facade.vi的前面板上放一個(gè)按鈕。如果希望用戶在使用這個(gè)XControl時(shí)可以調(diào)整它的大小,在我們這個(gè)簡(jiǎn)單例子中,只要設(shè)置Facade.vi窗口尺寸屬性中的在窗口尺寸變化時(shí),按比例調(diào)整控件大小”這個(gè)選項(xiàng)就可以了。對(duì)于復(fù)雜的XControl控件,要另寫代碼,在窗口尺寸變化后重新計(jì)算每個(gè)控件的大小和位置。信VIProperties區(qū)CategoryWindowSieeMininriumPanelSizeMdth0Height0<<SettoCurrsrtV/indaw5i2e回:allo

52、bjectsonfrontpanelasthewindowresizes*Appliesonlyto511glepanepanelsOKCancelHelp圖3:窗口尺寸屬性設(shè)置控制按鈕顏色的代碼也需要放在Facade.vi中:把前文提到的按鈕的MouseEnter和MouseLeave放在這里即可。具體實(shí)現(xiàn)方法,可以參考文章結(jié)尾給出的范例程序:5280261469140.zip二、有持續(xù)運(yùn)動(dòng)的XControlFacade.vi不能夠持續(xù)運(yùn)行,只有在有事件發(fā)生時(shí),LabVIEW才會(huì)調(diào)用這個(gè)VI。處理完這個(gè)事件,F(xiàn)acade.vi就會(huì)停止運(yùn)行。不要試圖讓Facade.vi持續(xù)運(yùn)行,否則會(huì)導(dǎo)致整個(gè)

53、LabVIEW被掛起。有時(shí)候,需要控件能夠循環(huán)地或者持續(xù)一段時(shí)間地作一個(gè)動(dòng)作。比如說,需要做一個(gè)不停閃爍的小燈??刂茻艄忾W爍的代碼就不能夠放在Facade.vi中。實(shí)現(xiàn)這種功能的一個(gè)方法是:把定時(shí)控制小燈顏色的代碼放在一個(gè)可重入VI中,通過小燈控件的引用參考來定時(shí)更改它的顏色屬性。在XControl的Init.vi中把這個(gè)定時(shí)VI動(dòng)態(tài)加載并以異步方式運(yùn)行;在XControl的Uninit.vi中再把這個(gè)定時(shí)VI卸載即可。Uninit.vi不是一個(gè)必須的XControl功能定義VI(AbilityVI),新建的XControl沒有這個(gè)VI??梢栽诠こ虨g覽窗口,鼠標(biāo)右擊這個(gè)XControl來為它添

54、加新的功能定義VI。笆5279316579099.zip它只能在LabVIEW8.5下打開。XControl是可以在VI的面板上放多個(gè)實(shí)例的,每個(gè)實(shí)例小燈的閃爍頻率可能不同。我在這個(gè)例子里,每個(gè)XControl實(shí)例都有自己的一個(gè)專用定時(shí)VI,因?yàn)檫@些VI是可重入的。定時(shí)的方法我采用的是加延時(shí)。我做了一下測(cè)試,發(fā)現(xiàn)現(xiàn)在的XControl有個(gè)問題,就是在程序面板上放多個(gè)XControl實(shí)例之后,定時(shí)就變得非常不準(zhǔn)確了,小燈閃爍速度明顯減慢。這也許是XControl的bug,也許是LabVIEW延時(shí)函數(shù)的問題。解決這個(gè)問題的方法就是使用一個(gè)定時(shí)VI控制所有的實(shí)例,當(dāng)然這樣的實(shí)現(xiàn)方法會(huì)比較麻煩一些。下

55、載文章中的示例程序:LabVIEW中的泛型容器Google網(wǎng)站里有個(gè)Google實(shí)驗(yàn)室,有不少Google的產(chǎn)品最初就是放在這個(gè)實(shí)驗(yàn)室里的?,F(xiàn)在NI也有NI實(shí)驗(yàn)室了。NI實(shí)驗(yàn)室公布出來的項(xiàng)目一般是NI工程師利用額外時(shí)間做的一些調(diào)查研究。這些項(xiàng)目不是公司的正式產(chǎn)品,但是它們的設(shè)計(jì)很有創(chuàng)新或者是比較有應(yīng)用潛力。與其讓這些項(xiàng)目被埋沒了,不如先看看用戶對(duì)這些項(xiàng)目的反應(yīng),如果相當(dāng)一部分用戶覺得某個(gè)項(xiàng)目非常有幫助,或許它就值得我們?yōu)槠湓黾油顿Y,把它作成正式產(chǎn)品了。我這里給大家介紹其中的一個(gè)項(xiàng)目:LabVIEWGenericContainerMap”。因?yàn)檫@個(gè)項(xiàng)目是我設(shè)計(jì)的,所以對(duì)它了解比較多一些。當(dāng)時(shí),我

56、們打算提出這個(gè)項(xiàng)目的時(shí)候,主要有兩個(gè)目的:第一是幫助用戶編寫有復(fù)雜數(shù)據(jù)結(jié)構(gòu)的應(yīng)用程序;第二是推進(jìn)LabVIEW向通用編程語言方向做改進(jìn)。C+的程序員基本都很喜歡STL這個(gè)模板庫。程序中常會(huì)使用數(shù)組、隊(duì)列、字符用等等數(shù)據(jù)類型和結(jié)構(gòu),如果自己設(shè)計(jì)實(shí)現(xiàn)這些數(shù)據(jù)結(jié)構(gòu)和相關(guān)的操作,是相當(dāng)耗費(fèi)精力的。好在STL實(shí)現(xiàn)了這些數(shù)據(jù)結(jié)構(gòu),和它們常用的操作方法。借用STL提供的功能,編程時(shí)很多細(xì)節(jié)方面不需要再去考慮了,這就讓工作簡(jiǎn)化了許多。嘗到STL甜頭的程序員,在編寫程序的時(shí)候,已經(jīng)很難離開STL了。STL中非常重要的一個(gè)部分就是容器。容器用于存放數(shù)據(jù),程序通過調(diào)用容器的結(jié)構(gòu)函數(shù)保存數(shù)據(jù)到容器或者訪問容器中的數(shù)據(jù)。容器也分為不同的類型,如鏈表、隊(duì)列等。它們?cè)跀?shù)據(jù)的組織方式上,或存取方式上有所分別,以適用不同的需求。STL中的容器和方法都是泛型的或者說是數(shù)據(jù)類型無關(guān)的,就是說這些容器可以保存和操作任何類型的數(shù)據(jù)。其它一些常用的編程語言,如JavaC#也都有類似的泛型容器以方便程序員使用。LabVIEW的主要方針是簡(jiǎn)化工程師們編寫程序的難度,以前用La

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論