ToolBook 多媒体应用开发中几种实用功能的实现
黄 穗 (暨南大学 计算机科学系 )
(广州、邮码510632)
内容摘要:
ToolBook 是美国Asymetrix公司推出的Windows 3.1与Windows 95多媒体应用开发工
具,它以易学易用、功能强大而深受广大应用开发者的喜爱。本文总结了作者用它
开发各种多媒体应用的经验,介绍几种实用功能的实现方法。

关键词:对象、脚本、消息、处理子

1、ToolBook使用简介
ToolBook 是Asymetrix公司推出的Windows 应用开发工具,其版本已经从较早时只
支持Windows 3.1的1.5版发展到目前同时支持Windows 3.1和Windows 95 的4.0版,
它所提供的可视化集成开发环境、近乎自然语言的面向对象编程语言OpenScript及
其强大的多媒体功能,既使是没有专业程序设计经验的普通计算机用户都能独立自
主地开发出诸如计算机辅助教学(CAI)、旅游指南、服务向导以及广告宣传等多媒体
应用程序。ToolBook的应用程序基本上采取传统的书架构,以页面为组织基础,通
过线性的和超媒体的有机结合将书编织成一个整体。开发ToolBook应用的基本步骤
是:
第一、理解ToolBook的基本概念和消息驱动机制,如对象、性质、事件、消息、脚
本、处理子等;
第二、在集成开发环境中利用拖-放功能,从工具条中选择需要的对象建立页面内
容,确定各对象的性质和相互位置,输入资料(如文字说明、图片、声音文件、动
画、影像文件等);
第三、针对某些应具备特定功能的对象,如按钮、热字等,通过ToolBook的专门手
段或OpenScript编程实现功能。详细的使用方法可参考文献1。

2、几种实用功能的实现
2.1 书签功能
对于电子书一类的应用来说,读者往往希望记住每次阅读停止的位置,以便下次阅
读时能从上次停止的地方继续下去,书签功能就是实现这种记忆的功能。实现方
法:用一个字段(field)作为记存器,在进入应用消息(EnterBook)处理子中从记存
器中取出上次退出时的页面代码,在退出应用消息(LeaveBook)消息处理子中将当前
页面代码存入记存器中,每次进入应用时先询问读者是否要回到上次退出的地方,
然后根据回答决定进入应用后是否转到上次退出的页面,详细的程序清单见附录1。
另外有一个与此类似的功能,即"阅读历史",程序记住读者阅读的页面顺序,可以
随时倒退到前面读的页面,实现方法是建立一个记录阅读顺序的数组,在进入页面
(EnterPage)消息处理子中将页面代码存入数组,另外做一个历史回退按钮,每按一
次从数组中取出上一个页面的代码并转入相应的页面。
2.2 自动演示功能
对于导游、CAI等类的应用,当读者一段时间未做任何操作时,应用程序能够好象一
位导游一样给读者从头到尾展示整个应用的内容。实现方法:首先用键按下
(KeyDown)消息处理子判断有无按键操作,并设置空闲时间的记时起点,然后用空闲
(Idle)消息处理子设置转入自动演示的时间和演示方式,如果设定的时间到了还没
有键盘和鼠标操作,则启动自动演示操作,每隔2秒钟就翻到下一页面,逐页遍历整
个应用,如果演示过程中出现键盘或鼠标动作则立即回到原来的页面,程序清单见
附录2。
2.3 功能提示
在应用中往往有不少按钮或具备按钮功能的图片、图符等对象,当操作者仅凭按钮
上的字符仍不清楚其实际功能时,只要将鼠标指向该对象并停留片刻,在对象的下
面就会自动出现一个提示框,简要地说明该对象的功能。实现方案:首先对需要提
示功能的对象建立用户性质pophelptext,以存放要提示的内容,然后利用鼠标进入
对象(MouseEnter)消息处理子设置定时器,在定时(timerNotify)消息处理子中发出
显示消息(showText),最后由显示消息处理子完成功能提示;这样,当鼠标进入某
有提示内容(其popHelpText性质非空)对象时,只要停留时间超过预先设定的值,则
显示提示窗(用视窗Viewer实现)并在窗内显示提示内容,当鼠标移离对象时隐藏提
示窗。实现程序放在应用脚本(Book Script)中,此外程序还要自动处理提示框的位
置和大小,以便完整显示提示内容,程序清单及有关注解见附录3。
2.4 图片移动控制
在地图类应用中,经常会碰到尺寸很大的图片或者界面上用来展示图片的区域比较
小的问题,图形移动控制功能就是象移动显示窗口那样移动图片,以便观察到图片
的各个部分,使用时只需要将光标指向图片的八个位置(中上、中下、中左、中右、
左上、左下、右上、右下),显示窗口便自动向这八个方向移动,移动速度可调。实
现方案:当显示图片的窗口一打开,定时器就开始工作,每半秒钟发一个消息检查
当前鼠标与主窗口的相对位置,在显示图片的主窗口下有一个隐藏的矩形框,用它
确定坐标X,Y的范围,然后根据当前鼠标与展示窗口的相对位置,分别发出八个方
向的消息(如ScrollDown向下移动),在对应的消息处理子中移动图片。详细的程序
清单及有关注解见附录4。

3、结束语
ToolBook在目前众多的多媒体应用开发工具中,以其易学易用最为突出,它对开发
者的计算机专业知识要求较低,又提供了许多可以效仿甚至直接采用的样例,有利
于开发者提高兴趣进入角色,但是,更深入、更灵活地利用它的功能则不是普通用
户所能做到,因为这需要对各类对象的结构和消息传递机制有较清楚的了解,另一
方面,ToolBook的许多功能(尤其是多媒体功能)都要通过函数的调用去实现,如何
设置调用参数和根据函数返回值作相应的处理也不是一般用户所能轻易掌握的,所
以,只有不断地学习他人的经验、总结自己的实践,才能提高应用开发水平,开发
出功能更强大、操作更灵活的应用程序来。

参考文献
1、《多媒体应用开发工具ToolBook 3.0及其应用》黄 穗、
蔡成滇 《电脑开发与应用》第8卷 增刊2 P19-22
2、《OpenScript Reference Manual》By Asymetrix
Corporation
3、《ToolBook User Manual》By Asymetrix Corporation

附录1:书签功能
进入应用的处理子:
to handle enterBook
system pNum
set pNum to text of field "pagename" of page 1 用字段域存放页面
request "回到上次离开的那一页吗 ?"with Yes or No
conditions
when It is "Yes"
go to page pNum
when It is "No"
go to page 1
end conditions
离开应用的处理子:
to handle leaveBook
system pNum
clear text of field "pagename" of page 1
put pNum into text of field "pagename" of page 1
end leaveBook

附录2:自动演示
按键处理子:
to handle KeyDown --检测是否有键按下
system CanTime
CanTime=False
end KeyDown
空闲时间处理子:
to handle Idle
system OldX,OldY,NewX,NewY,bool
system CanTime,TimeCount,CurrentPageNum
system GoFlag
get mousePosition of this window
NewX=Item 1 of it
NewY=Item 2 of it
If (OldX <>NewX) or (OldY <>NewY) --鼠标位置有无变化
CanTime=False
systemTimeFormat="sec"
Get systime
If CanTimer
If It-TimeCount=10 --设置时间段
GoFlag=true
end if
If GoFlag=true
If CurrentPageNum=null
set CurrentPageNum to PageNumber of this page
end if
bool=true
go next page
pause 2 seconds
end if
else
If CurrentPageNum <>null
bool=true
go page CurrentPageNum
end if
GoFlag=False
set CurrentPageNum to null
TimeCount=It
end if
CanTimer=true
OldX=NewX
OldY=NewY
end Idle

附录3:功能提示
鼠标离开处理子:
to handle mouseLeave
system popHelpTimer
if popHelpTimer is not null then
get timerStop(popHelpTimer) --关闭定时器
clear popHelpTimer
end if
if isOpen of viewer "poptext"
hide viewer "popText" --隐藏提示窗
end
end mouseLeave
鼠标进入处理子:
to handle mouseEnter
system popHelpTimer, currentObj, s_targetWindow
system logical popHelp
local oldCursor,temp, temp1,OldSysSuspend
s_targetWindow = this window
currentObj = target --置当前对象
temp1 = " "
popHelp = true
if sysLevel = reader
temp = name of target
notifyObj = "this book" --消息通知对象为本应用
popHelpTimer = timerStart("single",500,100,notifyObj)
end
end mouseEnter
定时器通知处理子:
to handle timerNotify timerID
system DEHomeBook,popHelpTimer,pophelp,currentObj,s_targetWindow
CONDITIONS
when timerID = popHelpTimer
if popHelpText of currentObj <> null
get flushMessageQueue() --删除鼠标和键盘消息
send showText to currentObj --将showText消息送当前对象
end if
end CONDITIONS
end timerNotify
显示提示处理子:
to handle showText
system EXEbook,s_targetWindow, DEHomeBook
linkDLL "tb40win.dll"
STRING clientFromPage(STRING,INT,STRING) --转换坐标
STRING screenFromPage(WORD,STRING,INT,STRING)
INT popText(STRING,STRING,STRING)
INT horizontalDisplayRes()
INT verticalDisplayRes()
end
sysLockScreen = true
if enabled of target is false
newText = pophelpText of target && "(disabled)"
else
newText = pophelpText of target --目标的提示内容
end if
set text of field "showText" of page "PopHelp" to newText
if not visible of viewer "popText"
show viewer "popText" as notActive
send upDateDisplay to page "popHelp"
end
maxXCoord = horizontalDisplayRes() -- 以象素为单位
maxYCoord = verticalDisplayRes() -- 以象素为单位
popHelpWidth = item 1 of size of viewer "poptext" -- 以象素为单位
popHelpHeight = item 2 of size of viewer "poptext"-- 以象素为单位
--确定目标的象素值大小
targetBounds = pageUnitsToScreen(bounds of target,s_targetWindow)
leftCorner = item 1 of targetBounds,item 2 of targetBounds
targetSize = (item 3 of targetBounds - item 1 of targetBounds),(item 4 of targetBounds) - (item 2 of targetBounds)
targetWidth = item 1 of targetSize
targetHeight = item 2 of targetSize
xPos = item 1 of leftCorner + (round(targetWidth/2)) --this indents the popup if room is available
--如果主窗口的右边界已移出荧幕,将提示窗靠右以便提示内容能看得见。
if item 1 of leftCorner < 0
xPos = xPos + round(abs(item 1 of leftcorner)/2)
end if
YPos = item 2 of leftCorner + targetHeight + 2 --places popup below target; extra 2 pixels
--防止鼠标进入提示窗内
combinedXPos = xPos + popHelpWidth
if combinedXpos > maxXCoord
offsetX = combinedXPos - maxXCoord
xPos = xPos - offsetX
end if
combinedYPos = yPos + popHelpHeight
if combinedYPos > maxYCoord
yPos = yPos - targetHeight -popHelpHeight -2
end if --提示的父窗 = s_targetWindow
position of viewer "Poptext" = xPos,yPos
syslockscreen = false
pophelp = true
end showText

附录4、图片移动
进入图片页面处理子:
to handle enterPage
system mPosTimer
send setConditions
systimeFormat = "seconds"
mPosTimer = timerStart("periodic",500,10,self)
end enterPage
定时器通知处理子:
to handle timerNotify timerID
system mPosTimer
if timerID = mPosTimer
send checkMousePos
else --非法定时值,关闭定时器
get timerStop(timerID)
end if
end timerNotify
--检查鼠标位置,确定图片滚动值
检查鼠标位置处理子:
to handle checkMousePos
system topLeftx1,topLeftx2,topLefty1,topLefty2, \
topRightx1,topRightx2,topRighty1,topRighty2, \
bottomLeftx1,bottomLeftx2,bottomLefty1,bottomLefty2, \
bottomRightx1,bottomRightx2,bottomRighty1,BottomRighty2, \
midLeftx1,midLeftx2,midLefty1,midLefty2,\
midRightx1,midRightx2,midRighty1,midRighty2, \
upx1,upx2,upy1,upy2,\
downx1,downx2,downy1,downy2,scrollAmount,baseHeight,viewersize
if scrollAmount is null;send fixScrollAmount;end if
get mousePosition of viewer id 0
x = item 1 of it
y = item 2 of it
if x < topLeftx1 or x > topRightx2 or y < 0 or y > bottomLefty2; break checkMousePos;end if
-- 设置 x , y 和系统时间
conditions
when x < topLeftx2 and y < topLefty2
send scrollLeftUp
when x > topRightx1 and y < topRighty2
send scrollRightUp
when x < midLeftx2 and y > topLefty2 and y < midLefty2
send scrollLeft
when x > midRightx1 and y > topRighty2 and y < midRighty2
send scrollRight
when x < bottomLeftx2 and y > midLefty2
send scrollLeftDown
when x > bottomRightx1 and y > midRighty2
send scrollRightDown
when x > topLeftx2 and x < topRightx1 and y < baseHeight
send scrollUp
when x > bottomLeftx2 and x < bottomRightx1 and y > (item 2 of viewerSize)
-- 基本高度
send scrollDown
end conditions
end checkMousePos
左上移动处理子:
to handle scrollLeftUp
system scrollAmount
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psx = psx - scrollAmount
psy = psy - scrollAmount
if psx < 0
psx = 0
end if
if psy < 0
psy = 0
end if
pageScroll of viewer "map" = psx,psy
end
右上移动处理子:
to handle scrollRightUp
system scrollAmount,pageScrollXmax
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psx = psx + scrollAmount
psy = psy - scrollAmount
if psx > pageScrollXmax
psx = pageScrollXmax
end if
if psy < 0
psy = 0
end if
pageScroll of viewer "map" = psx,psy
end
向左移动处理子:
to handle scrollLeft
system scrollAmount
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psx = psx - scrollAmount
if psx < 0
psx = 0
end if
pageScroll of viewer "map" = psx,psy
end
向右移动处理子:
to handle scrollRight
system scrollAmount,pageScrollXmax
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psx = psx + scrollAmount
if psx > pageScrollXmax
psx = pageScrollXmax
end if
pageScroll of viewer "map" = psx,psy
end
左下移动处理子:
to handle scrollLeftDown
system scrollAmount,pageScrollYmax
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psx = psx - scrollAmount
psy = psy + scrollAmount
if psx < 0
psx = 0
end if
if psy > pageScrollYmax
psy = pageScrollYmax
end if
pageScroll of viewer "map" = psx,psy
end
右下移动处理子:
to handle scrollRightDown
system scrollAmount,pageScrollXmax,pageScrollYmax
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psx = psx + scrollAmount
psy = psy + scrollAmount
if psx > pageScrollXmax
psx = pageScrollXmax
end if
if psy > pageScrollYmax
psy = pageScrollYmax
end if
pageScroll of viewer "map" = psx,psy
end
向上移动处理子:
to handle scrollUp
system scrollAmount,pageScrollYmax
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psy = psy - scrollAmount
if psy < 0
psy = 0
end if
pageScroll of viewer "map" = psx,psy
end
向下移动处理子:
to handle scrollDown
system scrollAmount,pageScrollYmax
if scrollAmount is null;send fixScrollAmount;end if
get pageScroll of viewer "map"
psx = item 1 of it
psy = item 2 of it
psy = psy + scrollAmount
if psy > pageScrollymax
psy = pageScrollymax
end if
pageScroll of viewer "map" = psx,psy
end
设置条件处理子:
to handle setConditions
system topLeftx1,topLeftx2,topLefty1,topLefty2, \
topRightx1,topRightx2,topRighty1,topRighty2, \
bottomLeftx1,bottomLeftx2,bottomLefty1,bottomLefty2, \
bottomRightx1,bottomRightx2,bottomRighty1,BottomRighty2, \
midLeftx1,midLeftx2,midLefty1,midLefty2,\
midRightx1,midRightx2,midRighty1,midRighty2, \
upx1,upx2,upy1,upy2,\
downx1,downx2,downy1,downy2,viewerSize,\
pageScrollXmax,pageScrollYmax,baseheight,baseWidth
if scrollAmount is null;send fixScrollAmount;end if
pageScrollXmax = 3472
pageScrollYmax = 2392
get position of rectangle "marker" of page "start"
xOffset = item 1 of it
yOffset = item 2 of it
viewerSize = size of rectangle "marker" of page "start"
baseWidth = 400
baseHeight = 400
topLeftx1 = 0 + xOffset
topLeftx2 = baseWidth + xOffset
topLefty1 = 0 + yOffset
topLefty2 = baseHeight + yOffset
toprightx1 = (item 1 of viewerSize) - baseWidth + xOffset
toprightx2 = item 1 of viewerSize + xOffset
toprighty1 = 0 + yOffset
toprighty2 = baseHeight + yOffset
bottomLeftx1 = 0 + xOffset
bottomLeftx2 = baseWidth + xOffset
bottomLefty1 = (item 2 of viewerSize) - baseHeight + yOffset
bottomLefty2 = item 2 of viewerSize + yOffset
bottomRightx1 = (item 1 of viewerSize) - baseWidth + xOffset
bottomRightx2 = item 1 of viewerSize + xOffset
bottomRighty1 = (item 2 of viewerSize) - baseHeight + yOffset
bottomRighty2 = item 2 of viewerSize + yOffset
midLeftx1 = 0 + xOffset
midLeftx2 = baseWidth + xOffset
midLefty1 = baseHeight + yOffset
midLefty2 = (item 2 of viewerSize) - baseHeight + yOffset
midRightx1 = (item 1 of viewerSize) - baseWidth + xOffset
midRightx2 = item 1 of viewerSize + xOffset
midRighty1 = baseHeight + yOffset
midRighty2 = (item 2 of viewerSize) - baseHeight + yOffset
upx1 = baseWidth + xOffset
upx2 = (item 1 of viewersize) - baseWidth + xOffset
upy1 = 0 + yOffset
upy2 = baseHeight + yOffset
downx1 = baseWidth + xOffset
downx2 = (item 1 of viewersize) - baseWidth + xOffset
downy1 = (item 2 of viewersize) - baseHeight + yOffset
downy2 = item 2 of viewerSize + yOffset
end
离开图片页面处理子:
to handle leavePage
system mPosTimer
if mPosTimer <> null
get timerStop(mPosTimer)
clear mPosTimer
end if
forward
end
移动速度处理子:
to handle fixScrollAmount
system scrollAmount
scrollAmount = 100
end


另注:作者备有上述全部功能的实现样例(.tbk文件),运行环境是Windows 95和
Multimedia ToolBook 4.0 。有兴趣者可来信联系索取。作者 e-mail 地址:
[email protected]