脚本函数(script function)是由设计人员利用aws自行编写的函数,与代码片段相比,脚本函数具有更加完备的功能。使用脚本函数就如同使用系统函数一样,可以向脚本函数传递参数,或者接收脚本函数的返回值。通过将常用的过程(例如3.4节中介绍的常用字符串处理过程)定义为脚本函数,可以大大提高设计人员的开发效率。
脚本函数可以有3种存在形式:内部脚本函数、外部脚本函数和字符串脚本函数。
与创建代码片段相比,创建脚本函数要稍微复杂一些,但是设计人员付出的这种努力会带来大量的回报。代码片段就像是预定义的宏,需要在程序中展开代码才能进行工作,而脚本函数是真正的函数,其实现细节被封装在【脚本函数】设计图标内部,便于对代码进行统一管理。设计人员可以随时补充和完善脚本函数的功能,只要保证函数接口(参数和返回值)不发生变化,这些修改工作不会给程序中的其他内容带来任何不利影响。
内部脚本函数存在于【脚本函数】设计图标之中。【脚本函数】设计图标并不是一种新的设计图标,而是运算设计图标的一种新形式。可以通过以下步骤创建一个【脚本函数】设计图标。
(1)向流程线上拖放一个运算设计图标,并以所需函数名对运算设计图标进行命名。该设计图标名必须是惟一的,不能与其他设计图标同名,但是可以与系统函数同名。现在将其命名为“box”。如图3-38所示。
(2)执行modify>icon>properties菜单命令,打开运算设计图标属性检查器,在属性检查器中打开contains script function复选框,将当前运算设计图标定义为【脚本函数】设计图标,如图3-39所示。
(3)单击属性检查器中的【ok】按钮。此时运算设计图标就变为【脚本函数】设计图标,如图3-40所示。此时设计图标的外观发生了变化。双击【脚本函数】设计图标打开【运算】窗口,可以像使用普通运算设计图标一样向其中输入代码。向“box”运算窗口中输入以下代码:
repeat with i:= 1 to 100
box(1, 0, 0, i, i )
i:=i+1
end repeat
图3-39 对运算设计图标进行属性设置
图3-40 【脚本函数】设计图标创建完毕
就创建了在【演示】窗口中绘制50个矩形这个简单的脚本函数。
现在运行程序不会在【演示】窗口中看到任何矩形。【脚本函数】设计图标是一种特殊的【运算】设计图标,它与普通【运算】设计图标的不同之处在于:当程序执行到流程线上的脚本设计图标时会略过它,并不自动执行其中的代码。脚本函数只能通过系统函数callscripticon进行调用。现在向【设计】窗口中添加一个【运算】设计图标,如图3-41所示,向“call box”设计图标中输入函数调用语句:
callscripticon(@"box")
就可以调用脚本函数box,在【演示】窗口中绘制矩形。由于authorware不会主动执行“box”设计图标,因此两个设计图标的相对位置关系并不重要:将“call box”设计图标放置在“box”设计图标之前会得到同样的运行结果。
对应的范例程序是chapter03文件夹下的scripticon-box.a7p。
图3-41 调用脚本函数
与系统函数相比,脚本函数同样可以具有参数和返回值。看一下系统函数callscripticon完整的调用语法:
result:= callscripticon(iconid@"icontitle" [,args] [,byvalue] [,owner])
其中惟一的必选参数是【脚本函数】设计图标的名称。可选参数args就是向被调用的脚本函数传递的参数,该参数可以是各种类型,包括从最简单的字符串类型到复杂的多维列表。脚本函数通过名为args的图标变量来接受传递过来的参数,通过名为result的图标变量返回执行结果。
例如要创建一个在【演示】窗口中随机绘制多个矩形的脚本函数randombox,首先为其创建图标变量args@"randombox",然后通过参数args指定绘制次数:
repeat with i:= 1 to args@"randombox"
--随机挑选一种覆盖模式
setmode(random(0,4,1))
--随机设置边框的颜色
setframe(1, rgb(random(0,255,1), random(0,255,1), random(0,255,1)))
--随机设置填充颜色
setfill(1, rgb(random(0,255,1), random(0,255,1), random(0,255,1)))
--随机设置矩形的位置和大小并进行绘制
box(random(1,8,1), random(1,windowwidth,1), random(1,windowheight,1),﹁
random(1,windowwidth,1), random(1,windowheight,1))
end repeat
在上述过程中,系统函数random()根据【演示】窗口宽度(windowwidth)和高度(windowheight),随机决定矩形的大小、模式、颜色、位置和边框,然后由系统函数box在屏幕中进行绘制。图标变量args在这里决定了循环执行的次数,即绘制矩形的数目。在一个【运算】设计图标中输入以下函数调用语句,可以实现在【演示】窗口内部随机绘制10个矩形的目的。
callscripticon(@"randombox ", 10)
程序流程和运行结果如图3-42所示。接下来继续创建两个脚本函数:randomcircle和randomline,分别用于随机绘制圆形和线段。
图3-42 向脚本函数传递参数
--以下过程位于“randomcircle”设计图标中
repeat with i:= 1 to args@"randombox"
setmode(random(0,4,1))
setframe(1, rgb(random(0,255,1), random(0,255,1), random(0,255,1)))
setfill(1, rgb(random(0,255,1), random(0,255,1), random(0,255,1)))
box(random(1,8,1), random(1,windowwidth,1), random(1,windowheight,1), ﹁
random(1,windowwidth,1), random(1,windowheight,1))
end repeat
--以下过程位于“randomline”设计图标中
repeat with i:= 1 to args@"randomline"
setmode(random(0,4,1))
setframe(1, rgb(random(0,255,1), random(0,255,1), random(0,255,1)))
--随机挑选箭头样式
setline(random(0,3,1))
line(random(1,8,1), random(1,windowwidth,1), random(1,windowheight,1), ﹁
random(1,windowwidth,1), random(1,windowheight,1))
end repeat
然后在【运算】设计图标之中就可以通过以下函数调用语句,调用上述脚本函数开始绘图:
callscripticon(@"randomcircle",10)
callscripticon(@"randomline",10)
脚本函数调用语句不必手工输入。在创建新的脚本函数之后,函数面板中script icons类别下就会增加新的函数,如图3-43所示。双击函数名称,就可以直接将函数调用语句粘贴到【运算】窗口中,然后再根据需要补充调用参数就可以了。
图3-43 新的函数
chapter03文件夹中的范例程序randomdraw.a7p演示了上述3个脚本函数的使用:如图3-44所示,单击【continue】按钮,就可以在【演示】窗口中分别看到10个矩形、10个圆形和10条线段。
图3-44 范例程序randomdraw.a7p
上述脚本函数中都使用了计数变量i,该变量属于整个程序,而并非某个特定的脚本函数所有,任何设计图标都可能使用该变量。为避免脚本函数和其他过程之间相互影响,应该在脚本函数中尽量使用图标变量。
本节将3.4.3.2节中介绍的常用字符串处理过程转换为脚本函数,并藉此介绍如何在脚本函数中处理变量和参数。
对于reverse过程,在将其改写为脚本函数reverse时,除了利用图标变量args@"reverse"接收准备处理的字符串参数(string)之外,还应该利用图标变量result@"reverse"和i@"reverse"分别替换原有的变量result和i(result@"reverse"同时也作为脚本函数reverse的返回值):
result@"reverse":= ""
repeat with i@"reverse":= 1 to charcount(args@"reverse")
result@"reverse":= substr(args@"reverse", i@"reverse", i@"reverse")^ ﹁
result@"reverse"
end repeat
这样就将脚本函数本身的数据封装在脚本函数内部,因为上述图标变量在脚本函数之外通常是不可见的。以后就可以通过函数调用语句:
result:= callscripticon(@"reverse", "authorware 7.0 is coming")
对脚本函数reverse进行调用,并将函数返回的结果"gnimoc si 0.7 erawrohtua"存储到全局变量result之中。变量result@"reverse"和result之间互不影响。
实际上在【脚本函数】设计图标之外仍然可以访问图标变量i@"reverse",但此时该变量的名称已经非常明显地告诉设计人员:这是一个仅仅属于“reverse”设计图标的变量。
按照类似的方法,可以将encode、decode、wordreverse和casereverse过程分别转换为脚本函数。
--以下是脚本函数encode
result@"encode":= ""
repeat with i@"encode":= 1 to charcount(args@"encode")
ascii@"encode":= string(code(substr(args@"encode",i@"encode", i@"encode")))
reverse@"encode":= ""
repeat with j@"encode":= 1 to charcount(ascii@"encode")
reverse@"encode":= substr(ascii@"encode", j@"encode", j@"encode")^ ﹁
reverse@"encode"
end repeat
result@"encode":= result@"encode"^reverse@"encode"^" "
end repeat
脚本函数也可以互相调用。由于前面已经定义了具有反转字符串功能的函数reverse,实际上可以将函数encode简化为:
result@"encode":=""
repeat with i@"encode":=1 to charcount(args@"encode")
ascii@"encode":=string(code(substr(args@"encode", i@"encode", i@"encode")))
reverse@"encode":=callscripticon(@"reverse",ascii@"encode")
result@"encode":=result@"encode"^reverse@"encode"^" "
end repeat
但是为了在后续章节中能够更好地描述各种脚本函数的工作方式,本书并没有采用上述简化代码。
--以下是脚本函数decode
result@"decode":= ""
repeat with i@"decode":= 1 to wordcount(args@"decode")
ascii@"decode":= getword(i@"decode", args@"decode")
reverse@"decode":= ""
repeat with j@"decode":= 1 to charcount(ascii@"decode")
reverse@"decode":= substr(ascii@"decode", j@"decode", j@"decode")^ ﹁
reverse@"decode"
end repeat
result@"decode":= result@"decode"^ char(reverse@"decode")
end repeat
现在脚本函数便于调用的优势已经凸显出来,多次调用脚本函数encode,可以非常方便地对一个字符串进行多次加密,从而获得较为理想的加密强度。
string:= "authorware 7.0 is coming"
--通过3次调用encode函数,对变量string的内容进行3重加密
repeat with i:= 1 to 3
string:= callscripticon(@"encode",string)
end repeat
--必须通过3次调用decode函数,才能对变量string的内容完全解密
repeat with i:= 1 to 3
string:=callscripticon(@"decode",string)
end repeat
函数encode并不是一个商业化的加密程序,它的作用仅仅是示范如何对字符串进行处理。不要使用它对同一字符串进行5次以上的加密,因为每次加密的结果都会以指数方式增长,很容易就会超出变量string的存储容量(512kb)。
--以下是脚本函数wordreverse
result@"wordreverse":= ""
repeat with i@"wordreverse":= 1 to wordcount(args@"wordreverse")
result@"wordreverse":= getword(i@"wordreverse",args@"wordreverse")^" "﹁
^result@"wordreverse"
end repeat
result@"wordreverse":= substr(result@"wordreverse", 1, ﹁
charcount( result@"wordreverse")-1)
--以下是脚本函数casereverse
result@"casereverse":=""
repeat with i@"casereverse":=1 to charcount(args@"casereverse")
result@"casereverse":=result@"casereverse"^test(code(substr(﹁
args@"casereverse", i@"casereverse", i@"casereverse"))>64&code(substr(﹁
args@"casereverse", i@"casereverse" , i@"casereverse" ))<91, ﹁
lowercase(substr(args@"casereverse", i@"casereverse" , ﹁
i@"casereverse" )),(test(code(substr(args@"casereverse", i@"casereverse" , ﹁
i@"casereverse" ))>96&code(substr(args@"casereverse", i@"casereverse" , ﹁
i@"casereverse" ))<123, uppercase(substr(args@"casereverse", i@"casereverse" ,﹁
i@"casereverse" )),substr(args@"casereverse", i@"casereverse" , ﹁
i@"casereverse" ))))
end repeat
到目前为止这些脚本函数都只接收1个参数。从系统函数callscripticon的使用语法也可以看出,只能向脚本函数传递一个参数args。由于一个列表型变量可以包含多个元素,每个元素的值和数据类型也可以不同,因此可以将需要处理的多个数据集中放置在一个列表型变量中,再将该列表型变量作为参数传递给脚本函数,这就达到了向脚本函数传递多个参数的目的。
同理,如果将脚本函数设计为返回一个列表型变量,那么脚本函数实际上也能返回多个(种)值。
字符排序过程sortchar实际上需要使用两个参数:string和ascending,前者是待排序的字符串,后者指定排序方式(升序或降序)。现在就为“sortchar”【脚本函数】设计图标创建列表型变量args@"sortchar",通过它使脚本函数sortchar能够接受两个参数。
--以下是脚本函数sortchar
result@"sortchar":=""
charlist@"sortchar":=[]
ascending@"sortchar":=args@"sortchar"[2]
repeat with i@"sortchar":=1 to charcount(args@"sortchar"[1])
addlinear(charlist@"sortchar", substr(args@"sortchar"[1], i@"sortchar", ﹁
i@"sortchar"))
end repeat
sortbyvalue(charlist@"sortchar",ascending@"sortchar")
repeat with i@"sortchar":=1 to charcount(args@"sortchar"[1])
result@"sortchar":=result@"sortchar"^charlist@"sortchar"[i@"sortchar"]
end repeat
上述代码中以粗体显示的代码是获取第2个参数的语句。现在可以通过两种方式调用sortchart函数:
string:= "authorware 7.0 is coming"
--对变量string中的字符串以降序排序
string1:= callscripticon(@"sortchart", [string, 0])
--对变量string中的字符串以升序排序
string2:= callscripticon(@"sortchart", [string, 1])
对函数sortchar中的粗体代码进行修改,可以实现更为灵活的参数传递。例如可以将函数sortchar中第2个参数设置为可选参数,如果调用者没有给出排序方式,则函数sortchar自动以升序方式排序。实现代码如下所示:
-- ascending@"sortchar"的默认值为true,如果参数列表存在第2个元素,则以该元素
--指定排序方式
if listcount(args@"sortchar")>1 then
ascending@"sortchar":=args@"sortchar"[2]
else ascending@"sortchar":=true
end if
现在以下两种函数调用方式是等价的(对变量string中的字符串以升序排序):
string1:= callscripticon(@"sortchart", [string])
string2:= callscripticon(@"sortchart", [string, 1])
可以通过以下代码进一步拓宽参数的使用方式:
if listcount(args@"sortchar")>1 then
ascending@"sortchar":=args@"sortchar"[2]
else if listcount(args@"sortchar")=1 then
ascending@"sortchar":=true
else
--如果参数不是一个列表,则将其转换为列表再进行处理
args@"sortchar":=list(args@"sortchar")
ascending@"sortchar":=true
end if
现在下列三种函数调用方式都是等价的。
string1:= callscripticon(@"sortchart", [string])
string2:= callscripticon(@"sortchart", [string, 1])
string3:= callscripticon(@"sortchart", string)
以下是脚本函数sortchar的最终版本:
result@"sortchar":=""
charlist@"sortchar":=[]
if listcount(args@"sortchar")>1 then
ascending@"sortchar":=args@"sortchar"[2]
else if listcount(args@"sortchar")=1 then
ascending@"sortchar":=true
else
args@"sortchar":=list(args@"sortchar")
ascending@"sortchar":=true
end if
repeat with i@"sortchar":=1 to charcount(args@"sortchar"[1])
addlinear(charlist@"sortchar", substr(args@"sortchar"[1], i@"sortchar", ﹁
i@"sortchar"))
end repeat
sortbyvalue(charlist@"sortchar",ascending@"sortchar")
repeat with i@"sortchar":=1 to charcount(args@"sortchar"[1])
result@"sortchar":=result@"sortchar"^charlist@"sortchar"[i@"sortchar"]
end repeat
读者可能已经注意到这些脚本函数总是首先将图标变量result的内容清空。这一操作是必需的,否则在下次调用脚本函数时,上次的调用结果将继续参加下次的处理过程。
chapter03文件夹下的范例程序scripticon.a7p演示了这些脚本函数的功能。如图3-45所示,读者可以在演示窗口上方的文本输入框中自由输入字符串,然后单击不同的按钮调用脚本函数对输入的字符串进行处理。注意在单击encode按钮后,才能使用decode按钮对加密后的字符串进行解密,并且在单击decode按钮之前,其他按钮处于禁用状态。
图3-45 范例程序scripticon.a7p
新闻热点
疑难解答