A Progress Bar Widget
In the previous section, we created a 'Preloader' script to (1) preload a URL; (2) send a message when the preload is complete; and (3) send 'status' messages while the preload is happening. In this section, we are going to create a progress bar that shows the current status (such as the percentage of the preload that has been completed).
Example Movie can be downloaded here. It contains the scripts discussed in this tutorial.
(Updated 25th June 05)
There are many ways to create progress bars. We can use Flash sprites, simple shapes that are stretched and resized, simple text sprites, widgets provided by Xtras such as OS Controls, and so on. In this example, we are going to use imaging lingo. No matter which way we do it, the script needs to have the ability to respond to two messages that we are going to send to it: (a) a #mShowWorking message, which we will send while we are waiting to connect to a server, and a #ShowProgress(amount) message which we will send when we know how far we have progressed through the preload.
The script below will create an object that will draw a simple 'barberpole' type animation to an image when we send it the #ShowWorking message. When we send the #ShowProgress message, it will replace this barberpole with a simple progress bar.
-- [PARENT SCRIPT] "ProgressBar" (v.1).
-- Author defined properties
property myColour, myColour2
-- Internally defined properties
property myCanvas, myRectOnCanvas, myBuffer, myBufferRect, myAlpha
property myStep, mySegmentSize
on Initialise (me, aCanvas, aRectOnCanvas, settings)
-- stash a reference to the output canvas and rect
myCanvas = aCanvas
myRectOnCanvas = aRectOnCanvas
-- some basic settings
myColour = rgb(68,68,68) -- bar colour
myColour2 = rgb(255,255,255) -- stripe colour
-- create an image buffer
myBuffer = image(myRectOnCanvas.width, myRectOnCanvas.height, 16)
myBuffer.copyPixels(myCanvas, myBuffer.Rect, myRectOnCanvas)
-- store this rect for use later
myBufferRect = myBuffer.rect
-- set up parameters for working animation
myStep = 0
mySegmentSize = myBuffer.height -4
return me
end
on Destroy (me)
-- store the canvas to its previous state
myCanvas.copyPixels(myBuffer, myRectOnCanvas, myBufferRect)
end
on ShowProgress (me, amt)
-- make sure the amt is between 0 and 1.0
amt = min(1.0, max(0, amt))
-- create a duplicate of the buffer
buffer = myBuffer.duplicate()
-- draw a border
buffer.draw(myBufferRect, [#ShapeType: #rect, #Color: myColour])
-- calculate a fill rect based on the amount to show
progressBarRect = rect(2,2, (myBufferRect.width-2)*amt, myBufferRect.height-2)
-- fill the progress bar rect
buffer.fill(progressBarRect, myColour2)
-- copy the result to the stage
myCanvas.copyPixels(buffer, myRectOnCanvas, myBufferRect)
end
on ShowWorking (me)
-- create a duplicate of the buffer
buffer = myBuffer.duplicate()
-- draw a border
buffer.draw(myBufferRect, [#ShapeType: #rect, #Color: myColour])
-- add 1 to the myStep property. This is used to move the 'stripes' along
myStep = myStep + 1
-- if the step is bigger than the striped segment, then reset it
if myStep > 0 then myStep = -mySegmentSize
-- create the temporary inner image for the barber pole
innerRect = buffer.rect.inflate(-2,-2)
innerImage = image(innerRect.width, innerRect.height, 24)
innerImage.fill(innerImage.rect, myColour)
-- now draw the stripes
L = myStep
repeat while true
dRect = rect(L, 0, L + mySegmentSize, mySegmentSize+2)
innerImage.draw(point(L,0), point( L + mySegmentSize, mySegmentSize),\
[#ShapeType: #Line, #lineSize: 1, #Color: myColour2, #ink: 2])
L = L + mySegmentSize
if L > buffer.width then exit repeat
end repeat
-- add the striped pole to the buffer
buffer.copyPixels(innerImage, innerRect, innerImage.rect)
-- copy the result to the stage
myCanvas.copyPixels(buffer, myRectOnCanvas, myBufferRect)
end
This script is designed to do nothing except in response to either #ShowWorking or #ShowProgress messages. To see how it works, have a look at this "PreloaderInterface" frame script that both creates a Progressbar and a Preloader object discussed in the previous section, and then sends messages to the Progressbar:
[FRAME SCRIPT / BEHAVIOUR]
property myURL, myProgressBarObj
on beginSprite (me)
if the runMode = "Author" then clearcache()
PreloaderDaemon = script("NetOp.Preloader").new(myURL)
PreloaderDaemon.AddListener(me)
myProgressBarObj = script("ProgressBar")
canvas = (the stage).image
rectOnCanvas = rect(10,10,110,22)
myProgressBarObj.Initialise(canvas, rectOnCanvas)
end
on endSprite(me)
myProgressBarObj.Destroy()
end
on exitframe (me)
go to the frame
end
-- Messages Sent by the preloader
on PreloadStatusUpdate (me, newOp, statusList)
-- member("StatusDisplay").text = statusList.state
put statusList.state
if statusList.state = "InProgress" then
myProgressBarObj.ShowProgress(statusList.fractionDone)
else myProgressBarObj.ShowWorking()
end
on PreloadFinished (me, newOp, errorNum)
if errorNum <> 0 then
-- get a description of the error
description = newOp.GetErrorDescription(errorNum)
alert "Network Error!" & return & description
else alert "All Done"
end
-- Author Settings
on getPropertyDescriptionList (me)
pdList = [:]
pdList[#myURL] = [#Comment: "URL", #format: #String, \
#Default: "http://www.lingoworkshop.com/Tutorials/Preloader/Main.dcr"]
return pdList
end
So whats happening here?
1. When this "PreloaderInterface" behaviour is instantiated and receives the #beginSprite event, it creates a new Preloader object and a ProgressBar object. It keeps a reference to the ProgressBar object so that it can send messages to the ProgressBar.
2. As the preload proceeds, the Preloader Object starts sending #PreloadStatusUpdate messages to the "PreloaderInterface" object. The "PreloaderInterface" object then sends #ShowWorking and #ShowProgress messages to the ProgressBar object (depending on whether the preload has actually started or not).
Downloads
Example Movie can be downloaded here. It contains the scripts discussed in the tutorial.
(Updated 25th June 05)