當使用列表型變量作為參數時,系統函數callscripticon的可選參數byvalue決定參數是以引用方式傳遞,還是以傳值方式傳遞。該參數的默認值是false,表示參數以引用方式傳遞,圖標變量args相當于參數變量的別名,這意味著腳本函數可以修改參數變量的值。當參數byvalue的值為true時,authorware將參數變量的值復制到圖標變量args中,腳本函數中所有對圖標變量args的操作不會影響到參數變量本身。
系統函數callscripticon的另一個可選參數owner用于設置腳本函數的擁有者。在默認情況下,調用腳本函數的運算設計圖標(即執行系統函數callscripticon的運算設計圖標)就是擁有者,這意味著由腳本函數繪制到【演示窗口中】的顯示對象都屬于該運算設計圖標,通過【擦除】設計圖標(或其他設計圖標的自動擦除選項以及系統函數eraseicon)擦除該設計圖標就可以擦除由腳本函數繪制到屏幕中的對象。例如在圖3-41所示的流程中,執行eraseicon(iconid@"call box")可以將窗口中顯示的所有矩形擦除,而執行eraseicon(iconid@"box")則沒有任何效果。如果在調用腳本函數時總是將參數owner設置為true,即以callscripticon(@"box",,,1)方式調用腳本函數,就將腳本函數的擁有者設置為對應的【腳本函數】設計圖標“box”,此時再執行eraseicon(iconid@"box"),就可以擦除【演示】窗口中所有由腳本函數box繪制的矩形。
由調用者作為擁有者,就意味著由腳本函數輸出到演示窗口中的內容可以被分別處理,不僅可以用擦除設計圖標進行單獨擦除,還可以用移動設計圖標進行單獨移動,甚至單獨響應用戶的操作。
腳本函數之間可以相互調用,也可以進行遞歸調用(調用其自身)。這種相互調用存在一個最大次數的限制,因為系統函數callscripticon的參數棧是有限的,每個參數將會在棧中占據一定的位置,使用args參數將使遞歸調用的最大次數減半。同時使用4個參數將使遞歸調用的最大次數減少到1/4。當達到棧的最大容量后,系統變量evalstatus和evalmessage將包含對應的出錯信息。遞歸調用的最大嵌套深度是12。
腳本函數的遞歸調用不是真正的遞歸調用,真正的遞歸調用意味著每層函數調用中所有的變量都是局部變量,而authorware中只存在全局變量,因此當函數調用自身時,當前層中變量的值會被下一層調用中變量的值所覆蓋。所以,當進行遞歸調用時,必須建立和維護腳本函數的變量堆棧,最簡便的方法是創建一個自動增長的列表來保存每層函數調用中的變量值,當每層函數調用返回時縮短列表的長度。如果在腳本函數中需要同時跟蹤多個變量的值,那么就要使用多維列表。
authorware沒有提供計算整數階乘的系統函數。以下是一個由aws編寫的腳本函數recursion,通過遞歸調用實現整數(12以內)的階乘。
-- nesting@"recursion"用于記錄當前遞歸調用的嵌套深度
nesting@"recursion":=nesting@"recursion"+1
--由線性列表linearlist@"recursion"形成變量堆棧,保存每層調用中的args@"recursion"
--參數值。因為在下一層調用中,變量args@"recursion"值會發生變化
addlinear(linearlist@"recursion", args@"recursion", nesting@"recursion")
if args@"recursion">1 then
--n!=(n-1)!×n 在此不能直接使用變量args@"recursion",因為在后續的調用中它的值
--被改變。只能使用變量堆棧中保存的值。
result@"recursion":=callscripticon(@"recursion",args@"recursion"-1)* ﹁
linearlist@"recursion"[nesting@"recursion"]
else
result@"recursion":=1
end if
--退出本層遞歸過程之前,刪除無用的列表元素(相當于將變量出棧)
deleteatindex(linearlist@"recursion", nesting@"recursion")
nesting@"recursion":=nesting@"recursion"-1
位于chapter03文件夾下的范例程序recursion.a7p提供了腳本函數recursion。如圖3-46所示,讀者可以在文本輸入框中輸入1至12之內的整數,回車之后就可以看到運算結果。
圖3-46 范例程序recursion.a7p
現在以函數調用callscripticon(@"recursion",4)為例,通過參數和堆棧列表值的變化分析遞歸調用過程:
result:= callscripticon(@"recursion",4)
進入第1層
linearlist@"recursion" [4]
nesting@"recursion" 1
args@"recursion" 4
result@"recursion" 0
進入第2層
linearlist@"recursion" [4, 3]
nesting@"recursion" 2
args@"recursion" 3
result@"recursion" 0
進入第3層
linearlist@"recursion" [4, 3, 2]
nesting@"recursion" 3
args@"recursion" 2
result@"recursion" 0
進入第4層
linearlist@"recursion" [4, 3, 2, 1]
nesting@"recursion" 4
args@"recursion" 1
result@"recursion" 1
返回第3層
linearlist@"recursion" [4, 3, 2]
nesting@"recursion" 3
args@"recursion" 1
result@"recursion" 2
返回第2層
linearlist@"recursion" [4, 3]
nesting@"recursion" 2
args@"recursion" 1
result@"recursion" 6
返回第1層
linearlist@"recursion" [4]
nesting@"recursion" 1
args@"recursion" 1
result@"recursion" 24
最后返回計算結果24。
由于使用了堆棧,不要在腳本函數中使用goto()函數。可在正常退出腳本函數之后,再根據需要跳轉到其他設計圖標。
創建多個腳本函數之后,就需要加強對腳本函數的管理,為每個腳本函數進行必要的說明,如圖3-47所示,這樣就可以保證無論何時面對這些腳本函數,都能夠保持清醒。同時還需要一種手段,可以方便地向設計圖標中添加需要使用的腳本函數。通過為【腳本函數】設計圖標添加描述信息可以實現上述目的。
在函數面板中【category】下拉列表框中選擇script icons類,在其中可以找到當前程序中被創建的所有腳本函數,在函數列表中選擇需要添加描述信息的腳本函數后,就可以向【description】文本框中輸入腳本函數的使用說明。注意將第一段內容保持為腳本函數的完整使用語法(請參閱圖3-47)。
此后在函數列表中雙擊需要使用的腳本函數,或者單擊函數面板的【paste】按鈕,就可以將該函數的使用語法粘貼到【運算】窗口中當前光標所在位置處或者設計圖標屬性檢查器中,就像使用系統函數一樣方便,如圖3-48所示。
圖3-47 為【腳本函數】設計圖標添加描述信息
圖3-48 粘貼腳本函數
由于腳本函數只能通過系統函數callscripticon進行調用,所以原則上【腳本函數】設計圖標可以放在流程線上的任意位置而不會影響程序的正常運行。但是在這里還是建議將所有的【腳本函數】設計圖標集中放置在一起,以便于日后進行維護,如圖3-49所示。
圖3-49 集中管理腳本函數
腳本函數可以存儲在外部文本文件中。包含腳本函數的文本文件可以位于本地驅動器,也可以位于網絡中(通過url指定地址)。將腳本函數存儲在外部文本文件中的真正意義在于,不同的程序文件可以共享同一份腳本函數,同時便于進行程序發行后的代碼維護。設計人員可以將最有可能發生改動的代碼以外部腳本函數的形式保存在程序文件外部。
位于文本文件中的外部腳本函數必須通過系統函數callscriptfile()進行調用,其使用語法為:
result:= callscriptfile("filename" [,args] [,byvalue])
與callscripticon()函數相比,callscriptfile()函數使用文本文件的路徑和名稱來代替【腳本函數】設計圖標的名稱。
本書3.5.2節中介紹的字符串處理腳本函數都已經被轉換為外部腳本函數,分別存放在chapter03/scriptfiles文件夾下的6個文本文件之中。chapter03文件夾下的范例程序scriptfile.a7p示范了如何使用這些外部腳本函數。
以下是外部腳本函數sortchar.txt中的代碼(觀察與內部腳本函數sortchar之間的區別):
charlist@iconid:=[]
result@iconid:=""
if listcount(args@iconid)>1 then
ascending@iconid:=args@(iconid)[2]
else if listcount(args@iconid)=1 then
ascending@iconid:=true
else
args@iconid:=list(args@iconid)
ascending@iconid:=true
end if
repeat with i@iconid:=1 to charcount(args@(iconid)[1])
addlinear(charlist@iconid, substr(args@(iconid)[1], i@iconid, i@iconid))
end repeat
sortbyvalue(charlist@iconid,ascending@iconid)
repeat with i@iconid:=1 to charcount(args@(iconid)[1])
result@iconid:=result@iconid^charlist@(iconid)[i@iconid]
end repeat
將內部腳本函數轉換為外部腳本函數的要點在于:
(1)在使用各種圖標變量時,以@iconid代替@"sortchar"。忽略設計圖標的名稱后,就可以在任意運算設計圖標中調用存儲于程序文件外部的腳本函數。
(2)對于列表型圖標變量(例如args和charlist),由于下標運算符的優先級高于引用運算符,因此必須對iconid使用括號,以類似于args@(iconid)[下標]的方式訪問列表中的元素。
(3)必須為調用外部腳本函數的運算設計圖標創建函數中使用的所有圖標變量。對于腳本函數sortchar而言,包含args,result,i,charlist和ascending,同時還要在程序文件范圍內創建全局變量args,result,i,charlist和ascending,否則在調用腳本函數時會出現“variable is not defined.”的錯誤提示信息。腳本函數中使用的全局變量也必須在程序文件范圍內重新定義。
外部腳本函數sortchar.txt的調用方法是:
result:= callscriptfile(filelocation^"scriptfiles//sortchar.txt", [entrytext,0])
將腳本函數存儲在外部文本文件中可能會帶來一些安全問題:任何人都可以輕易地通過任意一種文本文件編輯工具查看外部腳本函數的內容,從而了解程序運行過程的細節,或者惡意修改代碼,加入一些額外的指令。如果能夠將外部腳本函數進行加密,就能夠從很大程度上防止出現上述情況。
字符串腳本函數就是存儲有腳本函數的字符串。設計人員可以將字符串腳本函數加密后存儲于文本文件之中,在需要使用這些函數時,將加密的函數代碼讀入字符串變量并進行解密,還原為字符串腳本函數,然后通過系統函數callscriptstring()對字符串腳本函數加以調用。
字符串腳本函數與其他類型腳本函數的主要區別在于,字符串腳本函數中只能使用全局變量。因此必須在程序文件范圍內創建字符串腳本函數中用到的所有變量,否則在調用字符串腳本函數時會出現“variable is not defined.”的錯誤提示。
以下是字符串腳本函數sortchar所包含的代碼(觀察與內部腳本函數sortchar存在的區別):
charlist:=[]
result:=""
if listcount(args)>1 then
ascending:=args[2]
else if listcount(args)=1 then
ascending:=true
else
args:=list(args)
ascending:=true
end if
repeat with i:=1 to charcount(args[1])
addlinear(charlist, substr(args[1], i, i))
end repeat
sortbyvalue(charlist,ascending)
repeat with i:=1 to charcount(args[1])
result:=result^charlist[i]
end repeat
字符串腳本函數sortchar的調用方法是:
script:=readextfile("sortchar.txt")
args:=["authorware 7.0 is coming", 0]
callscriptstring(script ,args)
腳本函數的返回值存儲在全局變量result之中。
本書3.5.2節中介紹的字符串處理腳本函數都已經被轉換為字符串腳本函數,分別存放在chapter03/scriptstring文件夾下的6個文本文件之中。chapter03文件夾下的范例程序scriptstring.a7p示范了如何使用這些字符串腳本函數。
本書3.5.2節中介紹的encode腳本函數就是一個很好的加密函數,利用它就可以將字符串腳本函數包含的代碼進行加密。例如通過以下過程,就可以將存儲于wordreverse.txt文件之中的字符串腳本函數進行加密,并保存在wordreverse_encrypted.txt文件之中。
script:=readextfile("wordreverse.txt")
encryptedscript:=callscripticon(@"encode",script)
writeextfile("wordreverse_encrypted.txt", encryptedscript)
打開wordreverse_encrypted.txt文件,只能看到一些雜亂無章的數字,如圖3-50所示。但是可以通過以下過程解密并調用字符串腳本函數。
script:=callscripticon(@"decode", readextfile("wordreverse_encrypted.txt"))
args:="authorware 7.0 is coming"
callscriptstring(script, args)
圖3-50 加密后的字符串腳本函數
本書3.5.2節中介紹的字符串處理腳本函數都已經被轉換為加密的字符串腳本函數,分別存放在chapter03/encryptedscript文件夾下的6個文本文件中。chapter03文件夾下的范例程序scriptstringencrypted.a7p示范了如何使用這些加密的字符串腳本函數。
新聞熱點
疑難解答